Skip to content
File

Blob: src/client/components/share/use-share-view.ts

typescript71 lines
1import { createContext, use } from "react";
2import { useActivePageState } from "@/client/components/active-page/use-active-page";
3import { deriveSharePagePresentation, type ShareRootPage } from "@/client/lib/share-page-model";
4import type { ResolvedViewerContext } from "@/shared/types";
5 
6export type { ShareRootPage };
7 
8export type ShareViewStatus = "loading" | "ready" | "error";
9 
10interface ShareViewBaseState {
11 token: string;
12}
13 
14export interface ShareViewLoadingState extends ShareViewBaseState {
15 status: "loading";
16 error: null;
17}
18 
19export interface ShareViewErrorState extends ShareViewBaseState {
20 status: "error";
21 error: string;
22}
23 
24export interface ShareViewReadyState extends ShareViewBaseState {
25 status: "ready";
26 error: null;
27 workspaceId: string;
28 viewer: ResolvedViewerContext;
29 rootPageId: string;
30 rootPage: ShareRootPage;
31 activePageId: string;
32 navigate: (pageId: string) => void;
33}
34 
35export type ShareViewState = ShareViewLoadingState | ShareViewErrorState | ShareViewReadyState;
36 
37export const ShareViewContext = createContext<ShareViewState | null>(null);
38 
39export function useShareView(): ShareViewState {
40 const ctx = use(ShareViewContext);
41 if (!ctx) throw new Error("useShareView must be used inside ShareViewProvider");
42 return ctx;
43}
44 
45export function useReadyShareView(): ShareViewReadyState {
46 const view = useShareView();
47 if (view.status !== "ready") {
48 throw new Error("useReadyShareView must be used in the ready share branch");
49 }
50 return view;
51}
52 
53export function useSharedPagePresentation() {
54 const share = useReadyShareView();
55 const activePageState = useActivePageState();
56 const presentation = deriveSharePagePresentation(share.rootPage, share.activePageId, activePageState);
57 const isRootActive = presentation.isRootActive;
58 
59 return {
60 ...presentation,
61 ancestors: isRootActive ? [] : presentation.ancestors,
62 isAncestorTrailLoading: isRootActive ? false : presentation.isAncestorTrailLoading,
63 rootPageId: share.rootPageId,
64 rootPage: share.rootPage,
65 workspaceId: share.workspaceId,
66 token: share.token,
67 navigate: share.navigate,
68 unavailableMessage: activePageState.kind === "unavailable" ? activePageState.message : null,
69 };
70}