recursive comments

This commit is contained in:
bniwredyc 2023-01-04 14:26:18 +01:00
parent 8efde302a6
commit 0cd5dd1498
3 changed files with 26 additions and 36 deletions

View File

@ -1,33 +1,34 @@
import styles from './Comment.module.scss' import styles from './Comment.module.scss'
import type { JSX } from 'solid-js/jsx-runtime'
import { Icon } from '../_shared/Icon' import { Icon } from '../_shared/Icon'
import { AuthorCard } from '../Author/Card' import { AuthorCard } from '../Author/Card'
import { Show, createMemo, createSignal, createEffect } from 'solid-js' import { Show, createMemo, createSignal, For } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import type { Author, Reaction as Point } from '../../graphql/types.gen' import type { Author, Reaction } from '../../graphql/types.gen'
import { t } from '../../utils/intl' import { t } from '../../utils/intl'
import { createReaction, updateReaction, deleteReaction } from '../../stores/zine/reactions' import { deleteReaction } from '../../stores/zine/reactions'
import MD from './MD' import MD from './MD'
import { formatDate } from '../../utils' import { formatDate } from '../../utils'
import { SharePopup } from './SharePopup' import { SharePopup } from './SharePopup'
import stylesHeader from '../Nav/Header.module.scss' import stylesHeader from '../Nav/Header.module.scss'
import Userpic from '../Author/Userpic' import Userpic from '../Author/Userpic'
import { apiClient } from '../../utils/apiClient' import { apiClient } from '../../utils/apiClient'
import { ReactionKind } from '../../graphql/types.gen' import { useSession } from '../../context/session'
type Props = { type Props = {
level?: number level: number
comment: Partial<Point> comment: Reaction
canEdit?: boolean
compact?: boolean compact?: boolean
children?: JSX.Element[] reactions: Reaction[]
parent?: number
} }
export default (props: Props) => { export const Comment = (props: Props) => {
const [isReplyVisible, setIsReplyVisible] = createSignal(false) const [isReplyVisible, setIsReplyVisible] = createSignal(false)
const [postMessageText, setPostMessageText] = createSignal('') const [postMessageText, setPostMessageText] = createSignal('')
const { session } = useSession()
const canEdit = createMemo(() => props.comment.createdBy?.slug === session()?.user?.slug)
const comment = createMemo(() => props.comment) const comment = createMemo(() => props.comment)
const body = createMemo(() => (comment().body || '').trim()) const body = createMemo(() => (comment().body || '').trim())
const remove = () => { const remove = () => {
@ -43,7 +44,7 @@ export default (props: Props) => {
// await createReaction({ // await createReaction({
await apiClient.createReaction({ await apiClient.createReaction({
kind: 7, kind: 7,
replyTo: props.parent, replyTo: props.comment.id,
body: postMessageText(), body: postMessageText(),
shout: comment().shout.id shout: comment().shout.id
}) })
@ -95,7 +96,7 @@ export default (props: Props) => {
<div <div
class={styles.commentBody} class={styles.commentBody}
contenteditable={props.canEdit} contenteditable={canEdit()}
id={'comment-' + (comment().id || '')} id={'comment-' + (comment().id || '')}
> >
<MD body={body()} /> <MD body={body()} />
@ -111,7 +112,7 @@ export default (props: Props) => {
{t('Reply')} {t('Reply')}
</button> </button>
<Show when={props.canEdit}> <Show when={canEdit()}>
{/*FIXME implement edit comment modal*/} {/*FIXME implement edit comment modal*/}
{/*<button*/} {/*<button*/}
{/* class={clsx(styles.commentControl, styles.commentControlEdit)}*/} {/* class={clsx(styles.commentControl, styles.commentControlEdit)}*/}
@ -169,9 +170,11 @@ export default (props: Props) => {
</Show> </Show>
</div> </div>
</Show> </Show>
<Show when={props.children}> <ul>
<ul>{props.children}</ul> <For each={props.reactions.filter((r) => r.replyTo === props.comment.id)}>
</Show> {(reaction) => <Comment reactions={props.reactions} comment={reaction} level={props.level + 1} />}
</For>
</ul>
</li> </li>
) )
} }

View File

@ -1,6 +1,6 @@
import { For, Show, createMemo, createSignal, onMount, createEffect } from 'solid-js' import { For, Show, createMemo, createSignal, onMount, createEffect } from 'solid-js'
import { useSession } from '../../context/session' import { useSession } from '../../context/session'
import Comment from './Comment' import { Comment } from './Comment'
import { t } from '../../utils/intl' import { t } from '../../utils/intl'
import { showModal } from '../../stores/ui' import { showModal } from '../../stores/ui'
import styles from '../../styles/Article.module.scss' import styles from '../../styles/Article.module.scss'
@ -10,10 +10,6 @@ import { clsx } from 'clsx'
import { byCreated, byStat } from '../../utils/sortby' import { byCreated, byStat } from '../../utils/sortby'
import { Loading } from '../Loading' import { Loading } from '../Loading'
type NestedReaction = {
children: Reaction[] | []
} & Reaction
const ARTICLE_COMMENTS_PAGE_SIZE = 50 const ARTICLE_COMMENTS_PAGE_SIZE = 50
const MAX_COMMENT_LEVEL = 6 const MAX_COMMENT_LEVEL = 6
@ -106,18 +102,8 @@ export const CommentsTree = (props: { shoutSlug: string }) => {
</div> </div>
<ul class={styles.comments}> <ul class={styles.comments}>
<For each={nestComments(reactions().reverse())}> <For each={reactions().filter((r) => !r.replyTo)}>
{(reaction: NestedReaction) => ( {(reaction) => <Comment level={0} reactions={reactions()} comment={reaction} />}
<Comment
comment={reaction}
parent={reaction.id}
level={getCommentLevel(reaction)}
canEdit={reaction?.createdBy?.slug === session()?.user?.slug}
children={(reaction.children || []).map((r) => {
return <Comment comment={r} parent={reaction.id} />
})}
/>
)}
</For> </For>
</ul> </ul>

View File

@ -7,7 +7,7 @@ import { ArticleCard } from '../Feed/Card'
import { AuthorCard } from '../Author/Card' import { AuthorCard } from '../Author/Card'
import { t } from '../../utils/intl' import { t } from '../../utils/intl'
import { FeedSidebar } from '../Feed/Sidebar' import { FeedSidebar } from '../Feed/Sidebar'
import CommentCard from '../Article/Comment' import { Comment as CommentCard } from '../Article/Comment'
import { loadShouts, useArticlesStore } from '../../stores/zine/articles' import { loadShouts, useArticlesStore } from '../../stores/zine/articles'
import { useReactionsStore } from '../../stores/zine/reactions' import { useReactionsStore } from '../../stores/zine/reactions'
import { useAuthorsStore } from '../../stores/zine/authors' import { useAuthorsStore } from '../../stores/zine/authors'
@ -128,7 +128,8 @@ export const FeedView = () => {
<section class="feed-comments"> <section class="feed-comments">
<h4>{t('Comments')}</h4> <h4>{t('Comments')}</h4>
<For each={topComments()}> <For each={topComments()}>
{(comment) => <CommentCard comment={comment} compact={true} />} {/*FIXME: different components/better comment props*/}
{(comment) => <CommentCard comment={comment} level={0} reactions={[]} compact={true} />}
</For> </For>
</section> </section>
<Show when={topTopics().length > 0}> <Show when={topTopics().length > 0}>