Comment tree rerender Rerender fix

This commit is contained in:
ilya-bkv 2023-01-07 13:28:14 +03:00
parent 0cd5dd1498
commit 971e4e97a6
8 changed files with 48 additions and 64 deletions

View File

@ -5,20 +5,19 @@ import { Show, createMemo, createSignal, For } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import type { Author, Reaction } from '../../graphql/types.gen' import type { Author, Reaction } from '../../graphql/types.gen'
import { t } from '../../utils/intl' import { t } from '../../utils/intl'
import { deleteReaction } from '../../stores/zine/reactions' import { createReaction, 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 { useSession } from '../../context/session' import { useSession } from '../../context/session'
import { ReactionKind } from '../../graphql/types.gen'
type Props = { type Props = {
level: number
comment: Reaction comment: Reaction
compact?: boolean compact?: boolean
reactions: Reaction[] reactions?: Reaction[]
} }
export const Comment = (props: Props) => { export const Comment = (props: Props) => {
@ -41,20 +40,24 @@ export const Comment = (props: Props) => {
const compose = (event) => setPostMessageText(event.target.value) const compose = (event) => setPostMessageText(event.target.value)
const handleCreate = async (event) => { const handleCreate = async (event) => {
event.preventDefault() event.preventDefault()
// await createReaction({ try {
await apiClient.createReaction({ await createReaction({
kind: 7, kind: ReactionKind.Comment,
replyTo: props.comment.id, replyTo: props.comment.id,
body: postMessageText(), body: postMessageText(),
shout: comment().shout.id shout: comment().shout.id
}) })
setIsReplyVisible(false)
} catch (error) {
console.log('!!! err:', error)
}
} }
const formattedDate = createMemo(() => const formattedDate = createMemo(() =>
formatDate(new Date(comment()?.createdAt), { hour: 'numeric', minute: 'numeric' }) formatDate(new Date(comment()?.createdAt), { hour: 'numeric', minute: 'numeric' })
) )
return ( return (
<li class={clsx(styles.comment, { [styles[`commentLevel${props.level}`]]: Boolean(props.level) })}> <li class={styles.comment}>
<Show when={!!body()}> <Show when={!!body()}>
<div class={styles.commentContent}> <div class={styles.commentContent}>
<Show <Show
@ -93,7 +96,7 @@ export const Comment = (props: Props) => {
</div> </div>
</div> </div>
</Show> </Show>
<div style={{ color: 'red' }}>{comment().id}</div>
<div <div
class={styles.commentBody} class={styles.commentBody}
contenteditable={canEdit()} contenteditable={canEdit()}
@ -170,11 +173,13 @@ export const Comment = (props: Props) => {
</Show> </Show>
</div> </div>
</Show> </Show>
<Show when={props.reactions}>
<ul> <ul>
<For each={props.reactions.filter((r) => r.replyTo === props.comment.id)}> <For each={props.reactions.filter((r) => r.replyTo === props.comment.id)}>
{(reaction) => <Comment reactions={props.reactions} comment={reaction} level={props.level + 1} />} {(reaction) => <Comment reactions={props.reactions} comment={reaction} />}
</For> </For>
</ul> </ul>
</Show>
</li> </li>
) )
} }

View File

@ -21,11 +21,12 @@ export const CommentsTree = (props: { shoutSlug: string }) => {
const { session } = useSession() const { session } = useSession()
const { sortedReactions, loadReactionsBy } = useReactionsStore() const { sortedReactions, loadReactionsBy } = useReactionsStore()
const reactions = createMemo<Reaction[]>(() => const reactions = createMemo<Reaction[]>(() =>
sortedReactions() sortedReactions().sort(commentsOrder() === 'rating' ? byStat('rating') : byCreated)
.sort(commentsOrder() === 'rating' ? byStat('rating') : byCreated)
.filter((r) => r.shout.slug === props.shoutSlug)
) )
createEffect(() => {
console.log('!!! sortedReactions():', sortedReactions())
})
const loadMore = async () => { const loadMore = async () => {
try { try {
const page = getCommentsPage() const page = getCommentsPage()
@ -49,24 +50,6 @@ export const CommentsTree = (props: { shoutSlug: string }) => {
} }
onMount(async () => await loadMore()) onMount(async () => await loadMore())
const nestComments = (commentList) => {
const commentMap = {}
commentList.forEach((comment) => {
commentMap[comment.id] = comment
if (comment.replyTo !== null) {
const parent = commentMap[comment.replyTo] ?? []
;(parent.children = parent.children || []).push(comment)
}
})
return commentList.filter((comment) => {
return !comment.replyTo
})
}
createEffect(() => {
console.log('!!! re:', nestComments(reactions()))
})
return ( return (
<> <>
<Show when={!isCommentsLoading()} fallback={<Loading />}> <Show when={!isCommentsLoading()} fallback={<Loading />}>
@ -103,7 +86,7 @@ export const CommentsTree = (props: { shoutSlug: string }) => {
<ul class={styles.comments}> <ul class={styles.comments}>
<For each={reactions().filter((r) => !r.replyTo)}> <For each={reactions().filter((r) => !r.replyTo)}>
{(reaction) => <Comment level={0} reactions={reactions()} comment={reaction} />} {(reaction) => <Comment reactions={reactions()} comment={reaction} />}
</For> </For>
</ul> </ul>

View File

@ -36,11 +36,13 @@ export const AuthorCard = (props: AuthorCardProps) => {
actions: { loadSession } actions: { loadSession }
} = useSession() } = useSession()
if (!props.author) return false // FIXME: с сервера должен приходить автор реакции (ApiClient.CreateReaction)
const [isSubscribing, setIsSubscribing] = createSignal(false) const [isSubscribing, setIsSubscribing] = createSignal(false)
const subscribed = createMemo<boolean>( const subscribed = createMemo<boolean>(() => {
() => session()?.news?.authors?.some((u) => u === props.author.slug) || false return session()?.news?.authors?.some((u) => u === props.author.slug) || false
) })
const subscribe = async (really = true) => { const subscribe = async (really = true) => {
setIsSubscribing(true) setIsSubscribing(true)

View File

@ -8,12 +8,9 @@ import { follow, unfollow } from '../../stores/zine/common'
import { getLogger } from '../../utils/logger' import { getLogger } from '../../utils/logger'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { useSession } from '../../context/session' import { useSession } from '../../context/session'
import { StatMetrics } from '../_shared/StatMetrics'
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient' import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
import { Icon } from '../_shared/Icon' import { Icon } from '../_shared/Icon'
const log = getLogger('TopicCard')
interface TopicProps { interface TopicProps {
topic: Topic topic: Topic
compact?: boolean compact?: boolean

View File

@ -6,19 +6,10 @@ export default gql`
error error
reaction { reaction {
id id
createdBy {
slug
name
userpic
}
body body
kind kind
range range
createdAt createdAt
shout {
id
slug
}
replyTo replyTo
} }
} }

View File

@ -498,7 +498,7 @@ export type ReactionBy = {
export type ReactionInput = { export type ReactionInput = {
body?: InputMaybe<Scalars['String']> body?: InputMaybe<Scalars['String']>
kind: Scalars['Int'] kind: ReactionKind
range?: InputMaybe<Scalars['String']> range?: InputMaybe<Scalars['String']>
replyTo?: InputMaybe<Scalars['Int']> replyTo?: InputMaybe<Scalars['Int']>
shout: Scalars['Int'] shout: Scalars['Int']

View File

@ -23,9 +23,16 @@ export const loadReactionsBy = async ({
setSortedReactions(data) setSortedReactions(data)
return { hasMore } return { hasMore }
} }
export const createReaction = async (reaction: ReactionInput) => {
const { reaction: r } = await apiClient.createReaction(reaction) export const createReaction = async (input: ReactionInput) => {
return r try {
const reaction = await apiClient.createReaction(input)
console.log('!!! reaction:', reaction)
reaction.shout = { slug: input.shout }
setSortedReactions((prev) => [...prev, reaction])
} catch (error) {
console.error('[createReaction]', error)
}
} }
export const updateReaction = async (reaction: Reaction) => { export const updateReaction = async (reaction: Reaction) => {
const { reaction: r } = await apiClient.updateReaction({ reaction }) const { reaction: r } = await apiClient.updateReaction({ reaction })

View File

@ -230,11 +230,10 @@ export const apiClient = {
console.debug('createArticle response:', response) console.debug('createArticle response:', response)
return response.data.createShout return response.data.createShout
}, },
createReaction: async (reaction) => { createReaction: async (input: ReactionInput) => {
//TODO: add ReactionInput Type after debug const response = await privateGraphQLClient.mutation(reactionCreate, { reaction: input }).toPromise()
const response = await privateGraphQLClient.mutation(reactionCreate, { reaction }).toPromise() console.debug('[createReaction]:', response.data)
console.log('!!! response:', response) return response.data.createReaction.reaction
return response.data
}, },
// CUDL // CUDL