2023-02-17 09:21:02 +00:00
|
|
|
import type { JSX } from 'solid-js'
|
|
|
|
import { createContext, onCleanup, useContext } from 'solid-js'
|
|
|
|
import type { Reaction, ReactionBy, ReactionInput } from '../graphql/types.gen'
|
2023-02-28 17:13:14 +00:00
|
|
|
import { ReactionKind } from '../graphql/types.gen'
|
2023-02-17 09:21:02 +00:00
|
|
|
import { apiClient } from '../utils/apiClient'
|
|
|
|
import { createStore } from 'solid-js/store'
|
|
|
|
|
|
|
|
type ReactionsContextType = {
|
|
|
|
reactionEntities: Record<number, Reaction>
|
|
|
|
actions: {
|
|
|
|
loadReactionsBy: ({ by, limit }: { by: ReactionBy; limit?: number }) => Promise<Reaction[]>
|
|
|
|
createReaction: (reaction: ReactionInput) => Promise<void>
|
|
|
|
updateReaction: (id: number, reaction: ReactionInput) => Promise<void>
|
|
|
|
deleteReaction: (id: number) => Promise<void>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const ReactionsContext = createContext<ReactionsContextType>()
|
|
|
|
|
|
|
|
export function useReactions() {
|
|
|
|
return useContext(ReactionsContext)
|
|
|
|
}
|
|
|
|
|
|
|
|
export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
|
|
|
const [reactionEntities, setReactionEntities] = createStore<Record<number, Reaction>>({})
|
|
|
|
|
|
|
|
const loadReactionsBy = async ({
|
|
|
|
by,
|
|
|
|
limit
|
|
|
|
}: {
|
|
|
|
by: ReactionBy
|
|
|
|
limit?: number
|
|
|
|
}): Promise<Reaction[]> => {
|
|
|
|
const reactions = await apiClient.getReactionsBy({ by, limit })
|
|
|
|
const newReactionEntities = reactions.reduce((acc, reaction) => {
|
|
|
|
acc[reaction.id] = reaction
|
|
|
|
return acc
|
|
|
|
}, {})
|
|
|
|
setReactionEntities(newReactionEntities)
|
|
|
|
return reactions
|
|
|
|
}
|
|
|
|
|
|
|
|
const createReaction = async (input: ReactionInput): Promise<void> => {
|
|
|
|
const reaction = await apiClient.createReaction(input)
|
2023-02-28 17:13:14 +00:00
|
|
|
|
|
|
|
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.createdBy.slug === reaction.createdBy.slug &&
|
|
|
|
r.shout.id === reaction.shout.id &&
|
|
|
|
r.replyTo === reaction.replyTo
|
|
|
|
)
|
|
|
|
|
|
|
|
if (oppositeReaction) {
|
|
|
|
changes[oppositeReaction.id] = undefined
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setReactionEntities(changes)
|
2023-02-17 09:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const deleteReaction = async (id: number): Promise<void> => {
|
|
|
|
const reaction = await apiClient.destroyReaction(id)
|
2023-02-25 14:16:11 +00:00
|
|
|
setReactionEntities((oldState) => ({
|
|
|
|
...oldState,
|
|
|
|
[reaction.id]: undefined
|
|
|
|
}))
|
2023-02-17 09:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const updateReaction = async (id: number, input: ReactionInput): Promise<void> => {
|
|
|
|
const reaction = await apiClient.updateReaction(id, input)
|
|
|
|
setReactionEntities(reaction.id, reaction)
|
|
|
|
}
|
|
|
|
|
|
|
|
onCleanup(() => setReactionEntities({}))
|
|
|
|
|
|
|
|
const actions = {
|
|
|
|
loadReactionsBy,
|
|
|
|
createReaction,
|
|
|
|
updateReaction,
|
|
|
|
deleteReaction
|
|
|
|
}
|
|
|
|
|
|
|
|
const value: ReactionsContextType = { reactionEntities, actions }
|
|
|
|
|
|
|
|
return <ReactionsContext.Provider value={value}>{props.children}</ReactionsContext.Provider>
|
|
|
|
}
|