Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private flag on posts #98

Merged
merged 14 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions app/components/ui/post-form.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { useFetcher } from '@remix-run/react'
import { useState, type FormEvent } from 'react'
import { type ChangeEvent, useState, type FormEvent } from 'react'
import { Textarea } from '#app/components/ui/textarea.tsx'

export function PostForm({ className }: { className?: string }) {
export function PostForm({
showPrivateFlag = false,
className,
}: {
showPrivateFlag: boolean
className?: string
}) {
const [textAreaValue, setTextAreaValue] = useState<string>('')

const [isPrivate, setIsPrivate] = useState<number>(0)

const replyFetcher = useFetcher<{ newPostId: number }>()
const handleSubmit = function (event: FormEvent<HTMLFormElement>) {
replyFetcher.submit(event.currentTarget)
setTextAreaValue('')
}

function handleCheckboxChange(event: ChangeEvent<HTMLInputElement>) {
setIsPrivate(Number(event.target.checked))
}

return (
<replyFetcher.Form
id="create-post"
Expand All @@ -26,12 +38,28 @@ export function PostForm({ className }: { className?: string }) {
onChange={event => setTextAreaValue(event.target.value)}
className="mb-2 w-full"
/>
<button
disabled={replyFetcher.state !== 'idle'}
className="rounded bg-blue-500 px-4 py-2 text-base font-bold text-white hover:bg-blue-700"
>
{replyFetcher.state === 'idle' ? 'Post' : 'submitting...'}
</button>
<div className={'flex flex-row'}>
{showPrivateFlag && (
<div className="mr-2 mt-2">
<input type="hidden" name="isPrivate" value={isPrivate} />
<input
className={'mr-2'}
type="checkbox"
name="isPrivateCheckbox"
onChange={handleCheckboxChange}
/>
<label className={'text-gray-700'} htmlFor="isPrivate">
private
</label>
</div>
)}
<button
disabled={replyFetcher.state !== 'idle'}
className="rounded bg-blue-500 px-4 py-2 text-base font-bold text-white hover:bg-blue-700"
>
{replyFetcher.state === 'idle' ? 'Post' : 'submitting...'}
</button>
</div>
</div>
</replyFetcher.Form>
)
Expand Down
9 changes: 8 additions & 1 deletion app/components/ui/post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ export function PostDetails({
action="/reply"
onSubmit={handleReplySubmit}
>
<ReplyForm post={post} className="mt-2" />
<ReplyForm
post={post}
isPrivate={Boolean(post.isPrivate)}
className="mt-2"
/>
</Form>
)}
</div>
Expand Down Expand Up @@ -211,14 +215,17 @@ export function ParentPost({ parentPost }: { parentPost: Post }) {

function ReplyForm({
post,
isPrivate,
className,
}: {
post: ScoredPost
isPrivate: boolean
className: string
}) {
return (
<div className={'flex flex-col items-end ' + className}>
<input type="hidden" name="parentId" value={post.id} />
<input type="hidden" name="isPrivate" value={Number(isPrivate)} />

<Textarea
name="content"
Expand Down
1 change: 1 addition & 0 deletions app/db/kysely-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type Post = {
authorId: string
createdAt: Generated<number>
deletedAt: number | null
isPrivate: number
}
export type PostStats = {
postId: number
Expand Down
13 changes: 10 additions & 3 deletions app/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ export async function createPost(
parentId: number | null, // TODO: use parentId?: number
content: string,
authorId: string,
withUpvote?: boolean,
options?: { isPrivate: boolean; withUpvote?: boolean },
): Promise<number> {
const persistedPost: Post = await trx
.insertInto('Post')
.values({ content, parentId, authorId })
.values({
content: content,
parentId: parentId,
authorId: authorId,
isPrivate: options ? Number(options.isPrivate) : 0,
})
.returningAll()
.executeTakeFirstOrThrow()

invariant(persistedPost, `Reply to ${parentId} not submitted successfully`)

if (withUpvote !== undefined ? withUpvote : true) {
if (options?.withUpvote !== undefined ? options.withUpvote : true) {
await vote(trx, authorId, persistedPost.id, null, Direction.Up)
}

Expand Down Expand Up @@ -158,6 +163,7 @@ export async function getTransitiveParents(
'content',
'createdAt',
'deletedAt',
'isPrivate',
])
.unionAll(db =>
db
Expand All @@ -170,6 +176,7 @@ export async function getTransitiveParents(
'P.content',
'P.createdAt',
'P.deletedAt',
'P.isPrivate',
]),
),
)
Expand Down
5 changes: 3 additions & 2 deletions app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Read [how Jabble makes conversations better](https://github.com/social-protocols
</div>

{showNewDiscussionForm ? (
<PostForm className="mb-4" />
<PostForm showPrivateFlag={true} className="mb-4" />
) : (
loggedIn && (
<div className="mb-4 flex justify-end">{newDiscussionButton()}</div>
Expand Down Expand Up @@ -80,7 +80,8 @@ Read [how Jabble makes conversations better](https://github.com/social-protocols
}

function PostList({ feed }: { feed: rankingTs.ScoredPost[] }) {
return feed.map(post => {
const filteredFeed = feed.filter(post => !post.isPrivate)
return filteredFeed.map(post => {
return <TopLevelPost key={post.id} post={post} className="flex-1" />
})
}
Expand Down
11 changes: 8 additions & 3 deletions app/routes/reply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { requireUserId } from '#app/utils/auth.server.ts'
const replySchema = zfd.formData({
parentId: z.coerce.number().optional(),
content: z.coerce.string(),
isPrivate: z.coerce.number(),
})

export const action = async (args: ActionFunctionArgs) => {
Expand All @@ -21,12 +22,16 @@ export const action = async (args: ActionFunctionArgs) => {

const content = parsedData.content
const parentId = parsedData.parentId || null
const isPrivate = Boolean(parsedData.isPrivate)

invariant(content, 'content !== undefined')

let postId = await db
.transaction()
.execute(async trx => createPost(trx, parentId, content, userId))
let postId = await db.transaction().execute(async trx =>
createPost(trx, parentId, content, userId, {
isPrivate: isPrivate,
withUpvote: true,
}),
)

return redirect(`/post/${postId}`)
}
9 changes: 6 additions & 3 deletions import-hn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ async function importHNPostsFromFile(filename: string) {
}
}

const postId = await db
.transaction()
.execute(async trx => createPost(trx, parentId, markdown, ourUserId))
const postId = await db.transaction().execute(async trx =>
createPost(trx, parentId, markdown, ourUserId, {
isPrivate: false,
withUpvote: true,
}),
)

idMap.set(item.id, postId)
bar1.update(++i)
Expand Down
7 changes: 7 additions & 0 deletions migrations/2024-06-03-private-flag-on-posts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type Kysely, sql } from 'kysely'

export async function up(db: Kysely<any>): Promise<void> {
await sql`
alter table post add column isPrivate integer not null default false
`.execute(db)
}
26 changes: 21 additions & 5 deletions other/import-society-library-debatemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ async function importQuestion(question: Question) {
let wording = removePrefix(question.question, '[question] ')

const postId = await db.transaction().execute(async trx => {
return createPost(trx, null, wording, userId, withUpvote)
return createPost(trx, null, wording, userId, {
isPrivate: true,
withUpvote: withUpvote,
})
})
console.log(`Inserted question. post ${postId}: ${wording}`)

Expand All @@ -87,7 +90,10 @@ async function importPosition(parentId: number, position: Position) {
let wording = removePrefix(position.position, '[position] ')

const postId = await db.transaction().execute(async trx => {
return createPost(trx, parentId, wording, userId, withUpvote)
return createPost(trx, parentId, wording, userId, {
isPrivate: true,
withUpvote: withUpvote,
})
})
console.log(`Inserted position. post ${postId}: ${wording}`)

Expand All @@ -106,7 +112,10 @@ async function importClaim(parentId: number, claim: Claim) {
let wording = removePrefix(claim.claim, '[for reasons like] ')

const postId = await db.transaction().execute(async trx => {
return createPost(trx, parentId, wording, userId, withUpvote)
return createPost(trx, parentId, wording, userId, {
isPrivate: true,
withUpvote: withUpvote,
})
})
console.log(`Inserted claim. post ${postId}: ${wording}`)

Expand All @@ -122,7 +131,10 @@ async function importExample(parentId: number, example: Example) {
let wording = removePrefix(example.original_example, '[original example] ')

const postId = await db.transaction().execute(async trx => {
return createPost(trx, parentId, wording, userId, withUpvote)
return createPost(trx, parentId, wording, userId, {
isPrivate: true,
withUpvote: withUpvote,
})
})
console.log(`Inserted example. post ${postId}: ${wording}`)

Expand All @@ -144,6 +156,7 @@ ${evidence.url}
${evidence.reasoning}
`,
userId,
{ isPrivate: true, withUpvote: withUpvote },
)
})

Expand All @@ -159,7 +172,10 @@ async function importCounterClaim(parentId: number, counterClaim: string) {
)

const postId = await db.transaction().execute(async trx => {
return createPost(trx, parentId, wording, userId, withUpvote)
return createPost(trx, parentId, wording, userId, {
isPrivate: true,
withUpvote: withUpvote,
})
})
console.log(`Inserted counter claim. post ${postId}: ${wording}`)
}
7 changes: 7 additions & 0 deletions seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export async function seed() {
null,
'So, pregnant people can’t cross state lines to get abortions but guys like Kyle Rittenhouse can cross state lines to murder people. Seems fair.',
alice,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -75,6 +76,7 @@ export async function seed() {
post1,
'Kyle Rittenhouse was acquitted of murder charges. Clear video evidence showed he acted in self defense.',
bob,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -93,6 +95,7 @@ export async function seed() {
post2,
'That trial was a sham. They were never going to convict.',
alice,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -103,6 +106,7 @@ export async function seed() {
null,
'Sudafed, Benadryl and most decongestants don’t work: FDA advisory panel https://trib.al/sJmOJBP',
alice,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -116,6 +120,7 @@ export async function seed() {
post4,
'This is misleading. Regular Benadryl is an antihistamine; it is not a decongestant. There is a Benadryl branded product that is impacted. https://www.nbcnews.com/news/amp/rcna104424',
bob,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -126,6 +131,7 @@ export async function seed() {
null,
"Right now, real wages for the average American worker is higher than it was before the pandemic, with lower wage workers seeing the largest gains. That's Bidenomics.",
alice,
{ isPrivate: false, withUpvote: true },
)
})

Expand All @@ -140,6 +146,7 @@ export async function seed() {
post6,
"The tweet's claim about real wages contains a factual error. On 3/15/20 when US COVID lockdowns began real wages adjusted for inflation (AFI) were $11.15. As of 7/16/23 real wages AFI are $11.05. Real wages AFI remain lower (not higher) than before the pandemic.",
bob,
{ isPrivate: false, withUpvote: true },
)
})

Expand Down