reactions-store-fix
This commit is contained in:
parent
260b95f692
commit
6ec271fe7c
|
@ -1,5 +1,4 @@
|
||||||
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 { createStore, reconcile } from 'solid-js/store'
|
||||||
import { coreApiUrl } from '~/config'
|
import { coreApiUrl } from '~/config'
|
||||||
|
@ -47,23 +46,28 @@ 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 newReactionsByShout: Record<number, Reaction[]> = { ...reactionsByShout }
|
|
||||||
const newReactionsByAuthor: Record<number, Reaction[]> = { ...reactionsByAuthor }
|
|
||||||
const newReactionEntities = rrr.reduce(
|
const newReactionEntities = rrr.reduce(
|
||||||
(acc: { [reaction_id: number]: Reaction }, reaction: Reaction) => {
|
(acc: Record<number, Reaction>, reaction: Reaction) => {
|
||||||
acc[reaction.id] = reaction
|
acc[reaction.id] = reaction
|
||||||
if (!newReactionsByShout[reaction.shout.id]) newReactionsByShout[reaction.shout.id] = []
|
|
||||||
newReactionsByShout[reaction.shout.id].push(reaction)
|
|
||||||
if (!newReactionsByAuthor[reaction.created_by.id]) newReactionsByAuthor[reaction.created_by.id] = []
|
|
||||||
newReactionsByAuthor[reaction.created_by.id].push(reaction)
|
|
||||||
return acc
|
return acc
|
||||||
},
|
},
|
||||||
{ ...reactionEntities }
|
{ ...reactionEntities }
|
||||||
)
|
)
|
||||||
|
|
||||||
setReactionEntities(newReactionEntities)
|
const newReactionsByShout = { ...reactionsByShout }
|
||||||
setReactionsByShout(newReactionsByShout)
|
const newReactionsByAuthor = { ...reactionsByAuthor }
|
||||||
setReactionsByAuthor(newReactionsByAuthor)
|
|
||||||
|
rrr.forEach((reaction) => {
|
||||||
|
if (!newReactionsByShout[reaction.shout.id]) newReactionsByShout[reaction.shout.id] = []
|
||||||
|
newReactionsByShout[reaction.shout.id].push(reaction)
|
||||||
|
|
||||||
|
if (!newReactionsByAuthor[reaction.created_by.id]) newReactionsByAuthor[reaction.created_by.id] = []
|
||||||
|
newReactionsByAuthor[reaction.created_by.id].push(reaction)
|
||||||
|
})
|
||||||
|
|
||||||
|
setReactionEntities(reconcile(newReactionEntities))
|
||||||
|
setReactionsByShout(reconcile(newReactionsByShout))
|
||||||
|
setReactionsByAuthor(reconcile(newReactionsByAuthor))
|
||||||
|
|
||||||
const newCommentsByAuthor = Object.fromEntries(
|
const newCommentsByAuthor = Object.fromEntries(
|
||||||
Object.entries(newReactionsByAuthor).map(([authorId, reactions]) => [
|
Object.entries(newReactionsByAuthor).map(([authorId, reactions]) => [
|
||||||
|
@ -76,11 +80,11 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadReactionsBy = async (opts: QueryLoad_Reactions_ByArgs): Promise<Reaction[]> => {
|
const loadReactionsBy = async (opts: QueryLoad_Reactions_ByArgs): Promise<Reaction[]> => {
|
||||||
!opts.by && console.warn('reactions provider got wrong opts')
|
if (!opts.by) console.warn('reactions provider got wrong opts')
|
||||||
const fetcher = await loadReactions(opts)
|
const fetcher = await loadReactions(opts)
|
||||||
const result = (await fetcher()) || []
|
const result = (await fetcher()) || []
|
||||||
console.debug('[context.reactions] loaded', result)
|
console.debug('[context.reactions] loaded', result)
|
||||||
result && addShoutReactions(result)
|
if (result) addShoutReactions(result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,27 +93,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
const { error, reaction } = resp?.data?.create_reaction || {}
|
const { error, reaction } = resp?.data?.create_reaction || {}
|
||||||
if (error) await showSnackbar({ type: 'error', body: t(error) })
|
if (error) await showSnackbar({ type: 'error', body: t(error) })
|
||||||
if (!reaction) return
|
if (!reaction) return
|
||||||
const changes = { [reaction.id]: reaction }
|
|
||||||
|
|
||||||
if ([ReactionKind.Like, ReactionKind.Dislike].includes(reaction.kind)) {
|
|
||||||
const oppositeReactionKind =
|
|
||||||
reaction.kind === ReactionKind.Like ? ReactionKind.Dislike : ReactionKind.Like
|
|
||||||
|
|
||||||
const oppositeReaction = Object.values(reactionEntities).find(
|
|
||||||
(r) =>
|
|
||||||
r.kind === oppositeReactionKind &&
|
|
||||||
r.created_by.slug === reaction.created_by.slug &&
|
|
||||||
r.shout.id === reaction.shout.id &&
|
|
||||||
r.reply_to === reaction.reply_to
|
|
||||||
)
|
|
||||||
|
|
||||||
if (oppositeReaction) {
|
|
||||||
changes[oppositeReaction.id] = undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addShoutReactions([reaction])
|
addShoutReactions([reaction])
|
||||||
return reaction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteShoutReaction = async (
|
const deleteShoutReaction = async (
|
||||||
|
@ -118,11 +102,41 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
if (reaction_id) {
|
if (reaction_id) {
|
||||||
const resp = await client()?.mutation(destroyReactionMutation, { reaction_id }).toPromise()
|
const resp = await client()?.mutation(destroyReactionMutation, { reaction_id }).toPromise()
|
||||||
const result = resp?.data?.destroy_reaction
|
const result = resp?.data?.destroy_reaction
|
||||||
|
|
||||||
if (!result.error) {
|
if (!result.error) {
|
||||||
setReactionEntities({
|
// Находим реакцию, которую нужно удалить
|
||||||
[reaction_id]: undefined
|
const reactionToDelete = reactionEntities[reaction_id]
|
||||||
})
|
|
||||||
|
if (reactionToDelete) {
|
||||||
|
// Удаляем из reactionEntities
|
||||||
|
const newReactionEntities = { ...reactionEntities }
|
||||||
|
delete newReactionEntities[reaction_id]
|
||||||
|
|
||||||
|
// Удаляем из reactionsByShout
|
||||||
|
const newReactionsByShout = { ...reactionsByShout }
|
||||||
|
const shoutReactions = newReactionsByShout[reactionToDelete.shout.id]
|
||||||
|
if (shoutReactions) {
|
||||||
|
newReactionsByShout[reactionToDelete.shout.id] = shoutReactions.filter(
|
||||||
|
(r) => r.id !== reaction_id
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Удаляем из reactionsByAuthor
|
||||||
|
const newReactionsByAuthor = { ...reactionsByAuthor }
|
||||||
|
const authorReactions = newReactionsByAuthor[reactionToDelete.created_by.id]
|
||||||
|
if (authorReactions) {
|
||||||
|
newReactionsByAuthor[reactionToDelete.created_by.id] = authorReactions.filter(
|
||||||
|
(r) => r.id !== reaction_id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем стои с использованием reconcile
|
||||||
|
setReactionEntities(reconcile(newReactionEntities))
|
||||||
|
setReactionsByShout(reconcile(newReactionsByShout))
|
||||||
|
setReactionsByAuthor(reconcile(newReactionsByAuthor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
@ -134,7 +148,7 @@ 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)
|
if (reaction) setReactionEntities(reaction.id, reaction) // use setter to update store
|
||||||
return reaction
|
return reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +162,12 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
addShoutReactions
|
addShoutReactions
|
||||||
}
|
}
|
||||||
|
|
||||||
const value: ReactionsContextType = { reactionEntities, reactionsByShout, commentsByAuthor, ...actions }
|
const value: ReactionsContextType = {
|
||||||
|
reactionEntities,
|
||||||
|
reactionsByShout,
|
||||||
|
commentsByAuthor,
|
||||||
|
...actions
|
||||||
|
}
|
||||||
|
|
||||||
return <ReactionsContext.Provider value={value}>{props.children}</ReactionsContext.Provider>
|
return <ReactionsContext.Provider value={value}>{props.children}</ReactionsContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user