Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
5.6 kB · 168 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169"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<ReturnType<typeof getPollData>>; children: React.ReactNode;}) { return ( <SWRConfig value={{ fallback: { poll_data: props.poll_data, [`${props.leaflet_id}-leaflet_data`]: props.leaflet_data.data, }, }} > {props.children} </SWRConfig> );}
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, };}