From b1f88b3866f54f8674093728ba1846706f433abd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 11 Sep 2024 14:59:17 -0500 Subject: [PATCH] Set up nux API --- src/state/queries/nux/definitions.ts | 29 +++++++++ src/state/queries/nux/index.ts | 83 ++++++++++++++++++++++++++ src/state/queries/nux/types.ts | 9 +++ src/state/queries/nux/util.ts | 52 ++++++++++++++++ src/state/queries/preferences/const.ts | 1 + 5 files changed, 174 insertions(+) create mode 100644 src/state/queries/nux/definitions.ts create mode 100644 src/state/queries/nux/index.ts create mode 100644 src/state/queries/nux/types.ts create mode 100644 src/state/queries/nux/util.ts diff --git a/src/state/queries/nux/definitions.ts b/src/state/queries/nux/definitions.ts new file mode 100644 index 0000000000..e62364f1c8 --- /dev/null +++ b/src/state/queries/nux/definitions.ts @@ -0,0 +1,29 @@ +import zod from 'zod' + +import {BaseNux} from '#/state/queries/nux/types' + +export enum Nux { + One = 'one', + Two = 'two', +} + +export const nuxNames = new Set(Object.values(Nux)) + +export type AppNux = + | BaseNux<{ + id: Nux.One + data: { + likes: number + } + }> + | BaseNux<{ + id: Nux.Two + data: undefined + }> + +export const NuxSchemas = { + [Nux.One]: zod.object({ + likes: zod.number(), + }), + [Nux.Two]: undefined, +} diff --git a/src/state/queries/nux/index.ts b/src/state/queries/nux/index.ts new file mode 100644 index 0000000000..b31eb12582 --- /dev/null +++ b/src/state/queries/nux/index.ts @@ -0,0 +1,83 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query' + +import {AppNux, Nux} from '#/state/queries/nux/definitions' +import {parseAppNux, serializeAppNux} from '#/state/queries/nux/util' +import { + preferencesQueryKey, + usePreferencesQuery, +} from '#/state/queries/preferences' +import {useAgent} from '#/state/session' + +export {Nux} from '#/state/queries/nux/definitions' + +export function useNuxs() { + const {data, ...rest} = usePreferencesQuery() + + if (data && rest.isSuccess) { + const nuxs = data.bskyAppState.nuxs + ?.map(parseAppNux) + ?.filter(Boolean) as AppNux[] + + if (nuxs) { + return { + nuxs, + ...rest, + } + } + } + + return { + nuxs: undefined, + ...rest, + } +} + +export function useNux(id: T) { + const {nuxs, ...rest} = useNuxs() + + if (nuxs && rest.isSuccess) { + const nux = nuxs.find(nux => nux.id === id) + + if (nux) { + return { + nux: nux as Extract, + ...rest, + } + } + } + + return { + nux: undefined, + ...rest, + } +} + +export function useUpsertNuxMutation() { + const queryClient = useQueryClient() + const agent = useAgent() + + return useMutation({ + mutationFn: async (nux: AppNux) => { + await agent.bskyAppUpsertNux(serializeAppNux(nux)) + // triggers a refetch + await queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + }) + }, + }) +} + +export function useRemoveNuxsMutation() { + const queryClient = useQueryClient() + const agent = useAgent() + + return useMutation({ + mutationFn: async (ids: string[]) => { + await agent.bskyAppRemoveNuxs(ids) + // triggers a refetch + await queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + }) + }, + }) +} diff --git a/src/state/queries/nux/types.ts b/src/state/queries/nux/types.ts new file mode 100644 index 0000000000..5b79184704 --- /dev/null +++ b/src/state/queries/nux/types.ts @@ -0,0 +1,9 @@ +import {AppBskyActorDefs} from '@atproto/api' + +export type Data = Record | undefined + +export type BaseNux< + T extends Pick & {data: Data}, +> = T & { + completed: boolean +} diff --git a/src/state/queries/nux/util.ts b/src/state/queries/nux/util.ts new file mode 100644 index 0000000000..00a5ef5e00 --- /dev/null +++ b/src/state/queries/nux/util.ts @@ -0,0 +1,52 @@ +import {AppBskyActorDefs, nuxSchema} from '@atproto/api' + +import { + AppNux, + Nux, + nuxNames, + NuxSchemas, +} from '#/state/queries/nux/definitions' + +export function parseAppNux(nux: AppBskyActorDefs.Nux): AppNux | undefined { + if (!nuxNames.has(nux.id as Nux)) return + if (!nuxSchema.safeParse(nux).success) return + + const {data, ...rest} = nux + + const schema = NuxSchemas[nux.id as Nux] + + if (schema && data) { + const parsedData = JSON.parse(data) + + if (!schema.safeParse(parsedData).success) return + + return { + ...rest, + data: parsedData, + } as AppNux + } + + return { + ...rest, + data: undefined, + } as AppNux +} + +export function serializeAppNux(nux: AppNux): AppBskyActorDefs.Nux { + const {data, ...rest} = nux + const schema = NuxSchemas[nux.id as Nux] + + const result: AppBskyActorDefs.Nux = { + ...rest, + data: undefined, + } + + if (schema) { + schema.parse(data) + result.data = JSON.stringify(data) + } + + nuxSchema.parse(result) + + return result +} diff --git a/src/state/queries/preferences/const.ts b/src/state/queries/preferences/const.ts index 1ae7d20684..e07f40ec52 100644 --- a/src/state/queries/preferences/const.ts +++ b/src/state/queries/preferences/const.ts @@ -37,5 +37,6 @@ export const DEFAULT_LOGGED_OUT_PREFERENCES: UsePreferencesQueryResponse = { bskyAppState: { queuedNudges: [], activeProgressGuide: undefined, + nuxs: [], }, }