"use client"; import { SWRConfig } from "swr"; import { useReplicache } from "src/replicache"; import useSWR from "swr"; import { callRPC } from "app/api/rpc/client"; import { getPollData } from "actions/pollActions"; import type { GetLeafletDataReturnType } from "app/api/rpc/[command]/get_leaflet_data"; import { createContext, useContext, useMemo } from "react"; import { getPublicationMetadataFromLeafletData } from "src/utils/getPublicationMetadataFromLeafletData"; import { getPublicationURL, getDocumentURL } from "src/utils/getPublicationURL"; import { AtUri } from "@atproto/syntax"; import { normalizeDocumentRecord, normalizePublicationRecord, type NormalizedDocument, type NormalizedPublication, } from "src/utils/normalizeRecords"; export const StaticLeafletDataContext = createContext< null | GetLeafletDataReturnType["result"]["data"] >(null); export function PageSWRDataProvider(props: { leaflet_id: string; leaflet_data: GetLeafletDataReturnType["result"]; poll_data: Awaited>; children: React.ReactNode; }) { return ( {props.children} ); } export function usePollData() { let { permission_token } = useReplicache(); return useSWR(`poll_data`, () => getPollData( permission_token.permission_token_rights.map((pr) => pr.entity_set), ), ); } let useLeafletData = () => { let { permission_token } = useReplicache(); let staticLeafletData = useContext(StaticLeafletDataContext); let res = useSWR( staticLeafletData ? null : `${permission_token.id}-leaflet_data`, async () => permission_token.id ? (await callRPC("get_leaflet_data", { token_id: permission_token.id })) ?.result.data : undefined, ); if (staticLeafletData) return { data: staticLeafletData, mutate: res.mutate }; return res; }; export function useLeafletPublicationData() { let { data, mutate } = useLeafletData(); // First check for leaflets in publications let pubData = getPublicationMetadataFromLeafletData(data); // Normalize records so consumers don't have to const normalizedPublication = useMemo( () => normalizePublicationRecord(pubData?.publications?.record), [pubData?.publications?.record], ); const normalizedDocument = useMemo( () => normalizeDocumentRecord(pubData?.documents?.data), [pubData?.documents?.data], ); return { data: pubData || null, // Pre-normalized data - consumers should use these instead of normalizing themselves normalizedPublication, normalizedDocument, mutate, }; } export function useLeafletDomains() { let { data, mutate } = useLeafletData(); return { data: data?.custom_domain_routes, mutate: mutate }; } /** * Returns the publication this leaflet is the draft leaflet of, if any — * i.e. whether we're editing a publication's pages rather than a post or a * standalone leaflet. */ export function useLeafletPublicationPage() { let { data } = useLeafletData(); return data?.publications?.[0] ?? null; } export function useLeafletPublicationStatus() { const data = useContext(StaticLeafletDataContext); if (!data) return null; // Published state is read off the join rows' own `doc`/`document` columns // rather than the `documents`/`publications` embeds: the home and looseleafs // lists feed this context from getIdentityData, which carries the join rows // without the record payloads that get_leaflet_data embeds. Both columns are // FKs to documents.uri that cascade on delete, so a set column always means // a live published document. const publishedInPublication = data.leaflets_in_publications?.find( (l) => l.doc, ); const publishedStandalone = data.leaflets_to_documents?.find( (l) => !!l.document, ); const documentUri = publishedInPublication?.doc ?? publishedStandalone?.document; // The pretty URL needs the document and publication records; without them // fall back to the canonical /p/ permalink, which resolves any document by // its uri. let postShareLink: string | undefined; const publishedRecord = publishedInPublication?.documents ?? publishedStandalone?.documents; if (documentUri && publishedRecord) { const normalizedDoc = normalizeDocumentRecord( publishedRecord.data, documentUri, ); if (normalizedDoc) postShareLink = getDocumentURL( normalizedDoc, documentUri, publishedInPublication?.publications ?? undefined, ); } if (!postShareLink && documentUri) { const docUri = new AtUri(documentUri); postShareLink = `/p/${docUri.host}/${docUri.rkey}`; } return { token: data, leafletId: data.root_entity, shareLink: data.id, // Draft state - in a publication but not yet published draftInPublication: data.leaflets_in_publications?.[0]?.publication ?? undefined, // The publication this leaflet belongs to, whether published or not publicationUri: publishedInPublication?.publication ?? data.leaflets_in_publications?.[0]?.publication ?? undefined, // Published state isPublished: !!(publishedInPublication || publishedStandalone), publishedAt: publishedInPublication?.documents?.indexed_at ?? publishedStandalone?.documents?.indexed_at, documentUri, // Full URL for sharing published posts postShareLink, }; }