reactions-store-fix

This commit is contained in:
Untone 2024-09-06 08:33:44 +03:00
parent 6ec271fe7c
commit 8824fbab2f

View File

@ -1,6 +1,5 @@
import type { Accessor, JSX } from 'solid-js' import type { Accessor, JSX } from 'solid-js'
import { createContext, createMemo, createSignal, onCleanup, useContext } from 'solid-js' import { createContext, createMemo, createSignal, onCleanup, useContext } from 'solid-js'
import { createStore, reconcile } from 'solid-js/store'
import { coreApiUrl } from '~/config' import { coreApiUrl } from '~/config'
import { loadReactions } from '~/graphql/api/public' import { loadReactions } from '~/graphql/api/public'
import createReactionMutation from '~/graphql/mutation/core/reaction-create' import createReactionMutation from '~/graphql/mutation/core/reaction-create'
@ -19,8 +18,8 @@ import { useSession } from './session'
import { useSnackbar } from './ui' import { useSnackbar } from './ui'
type ReactionsContextType = { type ReactionsContextType = {
reactionEntities: Record<number, Reaction> reactionEntities: Accessor<Record<number, Reaction>>
reactionsByShout: Record<number, Reaction[]> reactionsByShout: Accessor<Record<number, Reaction[]>>
commentsByAuthor: Accessor<Record<number, Reaction[]>> commentsByAuthor: Accessor<Record<number, Reaction[]>>
loadReactionsBy: (args: QueryLoad_Reactions_ByArgs) => Promise<Reaction[]> loadReactionsBy: (args: QueryLoad_Reactions_ByArgs) => Promise<Reaction[]>
createShoutReaction: (reaction: MutationCreate_ReactionArgs) => Promise<void> createShoutReaction: (reaction: MutationCreate_ReactionArgs) => Promise<void>
@ -36,9 +35,9 @@ export function useReactions() {
} }
export const ReactionsProvider = (props: { children: JSX.Element }) => { export const ReactionsProvider = (props: { children: JSX.Element }) => {
const [reactionEntities, setReactionEntities] = createStore<Record<number, Reaction>>({}) const [reactionEntities, setReactionEntities] = createSignal<Record<number, Reaction>>({})
const [reactionsByShout, setReactionsByShout] = createStore<Record<number, Reaction[]>>({}) const [reactionsByShout, setReactionsByShout] = createSignal<Record<number, Reaction[]>>({})
const [reactionsByAuthor, setReactionsByAuthor] = createStore<Record<number, Reaction[]>>({}) const [reactionsByAuthor, setReactionsByAuthor] = createSignal<Record<number, Reaction[]>>({})
const [commentsByAuthor, setCommentsByAuthor] = createSignal<Record<number, Reaction[]>>({}) const [commentsByAuthor, setCommentsByAuthor] = createSignal<Record<number, Reaction[]>>({})
const { t } = useLocalize() const { t } = useLocalize()
const { showSnackbar } = useSnackbar() const { showSnackbar } = useSnackbar()
@ -46,18 +45,13 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token)) const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token))
const addShoutReactions = (rrr: Reaction[]) => { const addShoutReactions = (rrr: Reaction[]) => {
const newReactionEntities = rrr.reduce( const newReactionEntities = { ...reactionEntities() }
(acc: Record<number, Reaction>, reaction: Reaction) => { const newReactionsByShout = { ...reactionsByShout() }
acc[reaction.id] = reaction const newReactionsByAuthor = { ...reactionsByAuthor() }
return acc
},
{ ...reactionEntities }
)
const newReactionsByShout = { ...reactionsByShout }
const newReactionsByAuthor = { ...reactionsByAuthor }
rrr.forEach((reaction) => { rrr.forEach((reaction) => {
newReactionEntities[reaction.id] = reaction
if (!newReactionsByShout[reaction.shout.id]) newReactionsByShout[reaction.shout.id] = [] if (!newReactionsByShout[reaction.shout.id]) newReactionsByShout[reaction.shout.id] = []
newReactionsByShout[reaction.shout.id].push(reaction) newReactionsByShout[reaction.shout.id].push(reaction)
@ -65,14 +59,14 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
newReactionsByAuthor[reaction.created_by.id].push(reaction) newReactionsByAuthor[reaction.created_by.id].push(reaction)
}) })
setReactionEntities(reconcile(newReactionEntities)) setReactionEntities(newReactionEntities)
setReactionsByShout(reconcile(newReactionsByShout)) setReactionsByShout(newReactionsByShout)
setReactionsByAuthor(reconcile(newReactionsByAuthor)) setReactionsByAuthor(newReactionsByAuthor)
const newCommentsByAuthor = Object.fromEntries( const newCommentsByAuthor = Object.fromEntries(
Object.entries(newReactionsByAuthor).map(([authorId, reactions]) => [ Object.entries(newReactionsByAuthor).map(([authorId, reactions]) => [
authorId, authorId,
reactions.filter((x: Reaction) => x.kind === ReactionKind.Comment) reactions.filter((x) => x.kind === ReactionKind.Comment)
]) ])
) )
@ -104,16 +98,13 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
const result = resp?.data?.destroy_reaction const result = resp?.data?.destroy_reaction
if (!result.error) { if (!result.error) {
// Находим реакцию, которую нужно удалить const reactionToDelete = reactionEntities()[reaction_id]
const reactionToDelete = reactionEntities[reaction_id]
if (reactionToDelete) { if (reactionToDelete) {
// Удаляем из reactionEntities const newReactionEntities = { ...reactionEntities() }
const newReactionEntities = { ...reactionEntities }
delete newReactionEntities[reaction_id] delete newReactionEntities[reaction_id]
// Удаляем из reactionsByShout const newReactionsByShout = { ...reactionsByShout() }
const newReactionsByShout = { ...reactionsByShout }
const shoutReactions = newReactionsByShout[reactionToDelete.shout.id] const shoutReactions = newReactionsByShout[reactionToDelete.shout.id]
if (shoutReactions) { if (shoutReactions) {
newReactionsByShout[reactionToDelete.shout.id] = shoutReactions.filter( newReactionsByShout[reactionToDelete.shout.id] = shoutReactions.filter(
@ -121,8 +112,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
) )
} }
// Удаляем из reactionsByAuthor const newReactionsByAuthor = { ...reactionsByAuthor() }
const newReactionsByAuthor = { ...reactionsByAuthor }
const authorReactions = newReactionsByAuthor[reactionToDelete.created_by.id] const authorReactions = newReactionsByAuthor[reactionToDelete.created_by.id]
if (authorReactions) { if (authorReactions) {
newReactionsByAuthor[reactionToDelete.created_by.id] = authorReactions.filter( newReactionsByAuthor[reactionToDelete.created_by.id] = authorReactions.filter(
@ -130,10 +120,9 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
) )
} }
// Обновляем стои с использованием reconcile setReactionEntities(newReactionEntities)
setReactionEntities(reconcile(newReactionEntities)) setReactionsByShout(newReactionsByShout)
setReactionsByShout(reconcile(newReactionsByShout)) setReactionsByAuthor(newReactionsByAuthor)
setReactionsByAuthor(reconcile(newReactionsByAuthor))
} }
} }
@ -148,11 +137,15 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
if (!result) throw new Error('cannot update reaction') if (!result) throw new Error('cannot update reaction')
const { error, reaction } = result const { error, reaction } = result
if (error) await showSnackbar({ type: 'error', body: t(error) }) if (error) await showSnackbar({ type: 'error', body: t(error) })
if (reaction) setReactionEntities(reaction.id, reaction) // use setter to update store if (reaction) {
const newReactionEntities = { ...reactionEntities() }
newReactionEntities[reaction.id] = reaction
setReactionEntities(newReactionEntities)
}
return reaction return reaction
} }
onCleanup(() => setReactionEntities(reconcile({}))) onCleanup(() => setReactionEntities({}))
const actions = { const actions = {
loadReactionsBy, loadReactionsBy,