import React from "react"; import { Account, AccountClass, AnyAccountSchema, CoValueClassOrSchema, CoValueLoadingState, Loaded, MaybeLoaded, ResolveQuery, ResolveQueryStrict, } from "jazz-tools"; import { useAccountSubscription, useCoValueSubscription, useSubscriptionSelector, } from "./hooks.js"; import type { CoValueSubscription } from "./types.js"; export function createCoValueSubscriptionContext< S extends CoValueClassOrSchema, const R extends ResolveQuery = true, >(schema: S, resolve?: ResolveQueryStrict) { const Context = React.createContext>(null); return { Provider: ({ id, options, loadingFallback, unavailableFallback, children, }: React.PropsWithChildren<{ id: string | undefined | null; options?: Omit< Parameters>[2], "resolve" >; loadingFallback?: React.ReactNode; unavailableFallback?: React.ReactNode; }>) => { const subscription = useCoValueSubscription( schema, id, { ...options, resolve: resolve, }, "CoValueSubscriptionProvider", ); const loadState = useSubscriptionSelector(subscription, { select: (value) => value.$jazz.loadingState, }); if (loadState === CoValueLoadingState.LOADING) { return loadingFallback ?? null; } if ( loadState === CoValueLoadingState.UNAUTHORIZED || loadState === CoValueLoadingState.UNAVAILABLE ) { return unavailableFallback ?? null; } return ( {children} ); }, useSelector: >(options?: { select?: (value: Loaded) => TSelectorReturn; equalityFn?: (a: TSelectorReturn, b: TSelectorReturn) => boolean; }) => { const subscription = React.useContext(Context); if (!subscription) { throw new Error( "useSelector must be used within a coValue subscription provider", ); } return useSubscriptionSelector( subscription, options as Parameters< typeof useSubscriptionSelector >[1], ); }, }; } export function createAccountSubscriptionContext< A extends AccountClass | AnyAccountSchema, const R extends ResolveQuery = true, >(schema: A, resolve?: ResolveQueryStrict) { const Context = React.createContext>(null); return { Provider: ({ options, loadingFallback, unavailableFallback, children, }: React.PropsWithChildren<{ options?: Omit< Parameters>[1], "resolve" >; loadingFallback?: React.ReactNode; unavailableFallback?: React.ReactNode; }>) => { const subscription = useAccountSubscription( schema, { ...options, resolve: resolve, }, "AccountSubscriptionProvider", ); const loadState = useSubscriptionSelector(subscription, { select: (value) => value.$jazz.loadingState, }); if (loadState === CoValueLoadingState.LOADING) { return loadingFallback ?? null; } if ( loadState === CoValueLoadingState.UNAUTHORIZED || loadState === CoValueLoadingState.UNAVAILABLE ) { return unavailableFallback ?? null; } return ( {children} ); }, useSelector: >(options?: { select?: (value: Loaded) => TSelectorReturn; equalityFn?: (a: TSelectorReturn, b: TSelectorReturn) => boolean; }) => { const subscription = React.useContext(Context); if (!subscription) { throw new Error( "useSelector must be used within an account subscription provider", ); } return useSubscriptionSelector( subscription, options as Parameters< typeof useSubscriptionSelector >[1], ); }, }; }