Something went wrong. Try again.
leaflet fork for copy edit / bug fixes forked from leaflet.pub/leaflet
Something went wrong. Try again.
3.2 kB · 95 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596"use client";import { getIdentityData } from "actions/getIdentityData";import { getCurrentSessionToken } from "actions/savedAccounts";import { createContext, useContext, useEffect } from "react";import useSWR, { KeyedMutator, mutate } from "swr";import type { DashboardState } from "./PageLayouts/dashboardState";import { supabaseBrowserClient } from "supabase/browserClient";import { produce, Draft } from "immer";import { mutateSavedAccounts, upsertSavedAccountEntry,} from "src/hooks/useSavedAccounts";
export type InterfaceState = { dashboards: { [id: string]: DashboardState | undefined };};export type Identity = Awaited<ReturnType<typeof getIdentityData>>;let IdentityContext = createContext({ identity: null as Identity, mutate: (() => {}) as KeyedMutator<Identity>,});export const useIdentityData = () => useContext(IdentityContext);
export function mutateIdentityData( mutate: KeyedMutator<Identity>, recipe: (draft: Draft<NonNullable<Identity>>) => void,) { mutate( (data) => { if (!data) return data; return produce(data, recipe); }, { revalidate: false }, );}export function IdentityContextProvider(props: { children: React.ReactNode; initialValue: Identity;}) { let { data: identity, mutate } = useSWR("identity", () => getIdentityData(), { fallbackData: props.initialValue, revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, revalidateOnMount: false, }); useEffect(() => { mutate(props.initialValue); }, [props.initialValue]); // Remember the current session in the saved-accounts list so the account // switcher can offer it later. The token is always re-fetched — the cookie // is httpOnly, and a re-login mints a fresh token for the same identity, so // a shortcut that trusts the stored entry would pin a dead token forever. useEffect(() => { if (!identity?.id) return; let identityId = identity.id; let snapshot = { email: identity.email, did: identity.atp_did, handle: identity.bsky_profiles?.record.handle ?? null, displayName: identity.bsky_profiles?.record.displayName ?? null, avatar: identity.bsky_profiles?.record.avatar ?? null, }; getCurrentSessionToken() .then((session) => { if (session?.identity !== identityId) return; upsertSavedAccountEntry({ token: session.token, identity: identityId, ...snapshot, }); mutateSavedAccounts(); }) // Recording is best-effort bookkeeping — a failed call must never // surface; the entry is written on a later load instead. .catch(() => {}); }, [identity?.id]); useEffect(() => { if (!identity?.atp_did) return; let supabase = supabaseBrowserClient(); let channel = supabase.channel(`identity.atp_did:${identity.atp_did}`); channel.on("broadcast", { event: "notification" }, () => { mutate(); }); channel.subscribe(); return () => { channel.unsubscribe(); }; }, [identity?.atp_did]); return ( <IdentityContext.Provider value={{ identity, mutate }}> {props.children} </IdentityContext.Provider> );}