a tool for shared writing and social publishing
at refactor/page-perf 157 lines 5.0 kB view raw
1"use client"; 2import { getRSVPData } from "actions/getRSVPData"; 3import { SWRConfig } from "swr"; 4import { useReplicache } from "src/replicache"; 5import useSWR from "swr"; 6import { callRPC } from "app/api/rpc/client"; 7import { getPollData } from "actions/pollActions"; 8import type { GetLeafletDataReturnType } from "app/api/rpc/[command]/get_leaflet_data"; 9import { createContext, useContext, useMemo } from "react"; 10import { getPublicationMetadataFromLeafletData } from "src/utils/getPublicationMetadataFromLeafletData"; 11import { getPublicationURL, getDocumentURL } from "app/lish/createPub/getPublicationURL"; 12import { AtUri } from "@atproto/syntax"; 13import { 14 normalizeDocumentRecord, 15 normalizePublicationRecord, 16 type NormalizedDocument, 17 type NormalizedPublication, 18} from "src/utils/normalizeRecords"; 19 20export const StaticLeafletDataContext = createContext< 21 null | GetLeafletDataReturnType["result"]["data"] 22>(null); 23export function PageSWRDataProvider(props: { 24 leaflet_id: string; 25 leaflet_data: GetLeafletDataReturnType["result"]["data"]; 26 children: React.ReactNode; 27}) { 28 return ( 29 <SWRConfig 30 value={{ 31 fallback: { 32 [`${props.leaflet_id}-leaflet_data`]: props.leaflet_data, 33 }, 34 }} 35 > 36 {props.children} 37 </SWRConfig> 38 ); 39} 40 41export function useRSVPData() { 42 let { permission_token } = useReplicache(); 43 return useSWR(`rsvp_data`, () => 44 getRSVPData( 45 permission_token.permission_token_rights.map((pr) => pr.entity_set), 46 ), 47 ); 48} 49export function usePollData() { 50 let { permission_token } = useReplicache(); 51 return useSWR(`poll_data`, () => 52 getPollData( 53 permission_token.permission_token_rights.map((pr) => pr.entity_set), 54 ), 55 ); 56} 57 58let useLeafletData = () => { 59 let { permission_token } = useReplicache(); 60 let staticLeafletData = useContext(StaticLeafletDataContext); 61 let res = useSWR( 62 staticLeafletData ? null : `${permission_token.id}-leaflet_data`, 63 async () => 64 permission_token.id 65 ? (await callRPC("get_leaflet_data", { token_id: permission_token.id })) 66 ?.result.data 67 : undefined, 68 ); 69 if (staticLeafletData) return { data: staticLeafletData, mutate: res.mutate }; 70 return res; 71}; 72export function useLeafletPublicationData() { 73 let { data, mutate } = useLeafletData(); 74 75 // First check for leaflets in publications 76 let pubData = getPublicationMetadataFromLeafletData(data); 77 78 // Normalize records so consumers don't have to 79 const normalizedPublication = useMemo( 80 () => normalizePublicationRecord(pubData?.publications?.record), 81 [pubData?.publications?.record] 82 ); 83 const normalizedDocument = useMemo( 84 () => normalizeDocumentRecord(pubData?.documents?.data), 85 [pubData?.documents?.data] 86 ); 87 88 return { 89 data: pubData || null, 90 // Pre-normalized data - consumers should use these instead of normalizing themselves 91 normalizedPublication, 92 normalizedDocument, 93 mutate, 94 }; 95} 96export function useLeafletDomains() { 97 let { data, mutate } = useLeafletData(); 98 return { data: data?.custom_domain_routes, mutate: mutate }; 99} 100 101export function useLeafletPublicationStatus() { 102 const data = useContext(StaticLeafletDataContext); 103 if (!data) return null; 104 105 const publishedInPublication = data.leaflets_in_publications?.find( 106 (l) => l.doc, 107 ); 108 const publishedStandalone = data.leaflets_to_documents?.find( 109 (l) => !!l.documents, 110 ); 111 112 const documentUri = 113 publishedInPublication?.documents?.uri ?? publishedStandalone?.document; 114 115 // Compute the full post URL for sharing 116 let postShareLink: string | undefined; 117 if (publishedInPublication?.publications && publishedInPublication.documents) { 118 const normalizedDoc = normalizeDocumentRecord( 119 publishedInPublication.documents.data, 120 publishedInPublication.documents.uri, 121 ); 122 if (normalizedDoc) { 123 postShareLink = getDocumentURL( 124 normalizedDoc, 125 publishedInPublication.documents.uri, 126 publishedInPublication.publications, 127 ); 128 } 129 } else if (publishedStandalone?.document) { 130 const normalizedDoc = publishedStandalone.documents 131 ? normalizeDocumentRecord(publishedStandalone.documents.data, publishedStandalone.document) 132 : null; 133 if (normalizedDoc) { 134 postShareLink = getDocumentURL(normalizedDoc, publishedStandalone.document); 135 } else { 136 const docUri = new AtUri(publishedStandalone.document); 137 postShareLink = `/p/${docUri.host}/${docUri.rkey}`; 138 } 139 } 140 141 return { 142 token: data, 143 leafletId: data.root_entity, 144 shareLink: data.id, 145 // Draft state - in a publication but not yet published 146 draftInPublication: 147 data.leaflets_in_publications?.[0]?.publication ?? undefined, 148 // Published state 149 isPublished: !!(publishedInPublication || publishedStandalone), 150 publishedAt: 151 publishedInPublication?.documents?.indexed_at ?? 152 publishedStandalone?.documents?.indexed_at, 153 documentUri, 154 // Full URL for sharing published posts 155 postShareLink, 156 }; 157}