@daveyplate/better-auth-ui
Version:
Plug & play shadcn/ui components for better-auth
83 lines (74 loc) • 2.6 kB
text/typescript
import type {
FetchResult,
Models,
SchemaQuery,
SubscriptionOptions,
SubscriptionSignalPayload,
TriplitClient
} from "@triplit/client"
import type { WorkerClient } from "@triplit/client/worker-client"
import { createStateSubscription } from "@triplit/react"
import { useCallback, useMemo, useState, useSyncExternalStore } from "react"
export function useConditionalQuery<
M extends Models<M>,
Q extends SchemaQuery<M>
>(
client: TriplitClient<M> | WorkerClient<M>,
query?: Q | false | null | "" | 0,
options?: Partial<SubscriptionOptions> & { disabled?: boolean }
) {
const stringifiedQuery =
!options?.disabled && query && JSON.stringify(query)
const localOnly = !!options?.localOnly
const [remoteFulfilled, setRemoteFulfilled] = useState(false)
const defaultValue: SubscriptionSignalPayload<M, Q> = {
results: undefined,
fetching: true,
fetchingLocal: false,
fetchingRemote: false,
error: undefined
}
// biome-ignore lint/correctness/useExhaustiveDependencies: prevent infinite re-renders
const [subscribe, snapshot] = useMemo(
() =>
stringifiedQuery
? createStateSubscription(client, query, {
...options,
onRemoteFulfilled: () => setRemoteFulfilled(true)
})
: [() => () => {}, () => defaultValue],
[stringifiedQuery, localOnly]
)
const getServerSnapshot = useCallback(() => snapshot(), [snapshot])
const { fetching, ...rest } = useSyncExternalStore(
subscribe,
snapshot,
getServerSnapshot
)
return { fetching: fetching && !remoteFulfilled, ...rest }
}
type useConditionalQueryOnePayload<
M extends Models<M>,
Q extends SchemaQuery<M>
> = Omit<SubscriptionSignalPayload<M, Q>, "results"> & {
result: FetchResult<M, Q, "one">
}
export function useConditionalQueryOne<
M extends Models<M>,
Q extends SchemaQuery<M>
>(
client: TriplitClient<M> | WorkerClient<M>,
query?: Q | false | null | "" | 0,
options?: Partial<SubscriptionOptions> & { disabled?: boolean }
): useConditionalQueryOnePayload<M, Q> {
const { fetching, fetchingLocal, fetchingRemote, results, error } =
useConditionalQuery(
client,
query ? ({ ...query, limit: 1 } as Q) : query,
options
)
const result = useMemo(() => {
return results?.[0] ?? null
}, [results])
return { fetching, fetchingLocal, fetchingRemote, result, error }
}