webapp/src/context/reactions.tsx

111 lines
3.1 KiB
TypeScript
Raw Normal View History

2023-02-17 09:21:02 +00:00
import type { JSX } from 'solid-js'
2023-12-20 16:54:20 +00:00
import { createContext, onCleanup, useContext } from 'solid-js'
import { createStore, reconcile } from 'solid-js/store'
2023-12-19 09:34:24 +00:00
import { apiClient } from '../graphql/client/core'
2023-11-28 13:18:25 +00:00
import { Reaction, ReactionBy, ReactionInput, ReactionKind } from '../graphql/schema/core.gen'
2023-02-17 09:21:02 +00:00
type ReactionsContextType = {
reactionEntities: Record<number, Reaction>
actions: {
2023-11-30 08:07:31 +00:00
loadReactionsBy: ({
by,
limit,
offset,
}: {
by: ReactionBy
limit?: number
offset?: number
}) => Promise<Reaction[]>
2023-02-17 09:21:02 +00:00
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,
2023-11-30 08:07:31 +00:00
offset,
2023-02-17 09:21:02 +00:00
}: {
by: ReactionBy
limit?: number
2023-11-30 08:07:31 +00:00
offset?: number
2023-02-17 09:21:02 +00:00
}): Promise<Reaction[]> => {
2023-12-19 09:34:24 +00:00
const reactions = await apiClient.getReactionsBy({ by, limit, offset })
2024-01-23 16:32:57 +00:00
const newReactionEntities = reactions.reduce(
(acc: { [reaction_id: number]: Reaction }, reaction: Reaction) => {
acc[reaction.id] = reaction
return acc
},
{},
)
2023-02-17 09:21:02 +00:00
setReactionEntities(newReactionEntities)
return reactions
}
const createReaction = async (input: ReactionInput): Promise<void> => {
2023-12-19 09:34:24 +00:00
const reaction = await apiClient.createReaction(input)
2024-01-31 12:34:15 +00:00
if (!reaction) return
2023-02-28 17:13:14 +00:00
const changes = {
[reaction.id]: reaction,
2023-02-28 17:13:14 +00:00
}
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 &&
2023-11-28 13:18:25 +00:00
r.created_by.slug === reaction.created_by.slug &&
2023-02-28 17:13:14 +00:00
r.shout.id === reaction.shout.id &&
2023-11-28 13:18:25 +00:00
r.reply_to === reaction.reply_to,
2023-02-28 17:13:14 +00:00
)
if (oppositeReaction) {
changes[oppositeReaction.id] = undefined
}
}
setReactionEntities(changes)
2023-02-17 09:21:02 +00:00
}
2024-01-23 14:41:49 +00:00
const deleteReaction = async (reaction_id: number): Promise<void> => {
2024-01-25 18:19:59 +00:00
if (reaction_id) {
await apiClient.destroyReaction(reaction_id)
setReactionEntities({
[reaction_id]: undefined,
})
}
2023-02-17 09:21:02 +00:00
}
const updateReaction = async (id: number, input: ReactionInput): Promise<void> => {
2023-12-19 09:34:24 +00:00
const reaction = await apiClient.updateReaction(id, input)
2023-02-17 09:21:02 +00:00
setReactionEntities(reaction.id, reaction)
}
2023-03-02 18:48:39 +00:00
onCleanup(() => setReactionEntities(reconcile({})))
2023-02-17 09:21:02 +00:00
const actions = {
loadReactionsBy,
createReaction,
updateReaction,
deleteReaction,
2023-02-17 09:21:02 +00:00
}
const value: ReactionsContextType = { reactionEntities, actions }
return <ReactionsContext.Provider value={value}>{props.children}</ReactionsContext.Provider>
}