File
Blob: src/client/components/workspace/share-dialog/controller.ts
| 1 | import { useCallback, useMemo, useState } from "react"; |
| 2 | |
| 3 | import { useWorkspaceRole } from "@/client/components/workspace/use-workspace-view"; |
| 4 | import { deriveSitePublishAffordance } from "@/client/lib/affordance/site-publish"; |
| 5 | import { useOnline } from "@/client/hooks/use-online"; |
| 6 | import { useAuthStore } from "@/client/stores/auth-store"; |
| 7 | import { getSitePublishingEntitlements } from "@/shared/entitlements"; |
| 8 | |
| 9 | import { useShareController } from "./share-controller"; |
| 10 | import { useSitePublishController } from "./site-publish-controller"; |
| 11 | import type { DialogTab, ShareDialogProps, ShareDialogShellValue, ShareDialogSlices, WorkspaceRole } from "./types"; |
| 12 | |
| 13 | export function useShareDialogController({ |
| 14 | pageId, |
| 15 | workspaceId, |
| 16 | pageKind, |
| 17 | disabled, |
| 18 | title, |
| 19 | }: ShareDialogProps): ShareDialogSlices { |
| 20 | const [open, setOpen] = useState(false); |
| 21 | const [activeTab, setActiveTab] = useState<DialogTab>("share"); |
| 22 | const user = useAuthStore((s) => s.user); |
| 23 | const online = useOnline(); |
| 24 | const workspaceRole: WorkspaceRole = useWorkspaceRole() ?? "none"; |
| 25 | const currentUserId = user?.id; |
| 26 | |
| 27 | const share = useShareController({ |
| 28 | pageId, |
| 29 | disabled, |
| 30 | open, |
| 31 | workspaceRole, |
| 32 | online, |
| 33 | currentUserId, |
| 34 | }); |
| 35 | |
| 36 | const siteEntitlements = getSitePublishingEntitlements(workspaceRole); |
| 37 | const publish = useSitePublishController({ |
| 38 | pageId, |
| 39 | workspaceId, |
| 40 | pageKind, |
| 41 | canManageSite: siteEntitlements.manageSite, |
| 42 | canViewPagePublishStatus: siteEntitlements.viewPagePublishStatus, |
| 43 | open: open && !disabled, |
| 44 | }); |
| 45 | |
| 46 | const publishAffordance = useMemo( |
| 47 | () => |
| 48 | deriveSitePublishAffordance({ |
| 49 | entitlements: siteEntitlements, |
| 50 | online, |
| 51 | pageKind, |
| 52 | }), |
| 53 | [siteEntitlements, online, pageKind], |
| 54 | ); |
| 55 | |
| 56 | const close = useCallback(() => { |
| 57 | setOpen(false); |
| 58 | share.people.dismissSuggestions(); |
| 59 | }, [share.people]); |
| 60 | |
| 61 | const toggleOpen = useCallback(() => { |
| 62 | if (disabled) return; |
| 63 | if (!open) { |
| 64 | share.resetTransient(); |
| 65 | } |
| 66 | setOpen((current) => !current); |
| 67 | }, [disabled, open, share]); |
| 68 | |
| 69 | const shell = useMemo<ShareDialogShellValue>( |
| 70 | () => ({ |
| 71 | disabled: disabled ?? false, |
| 72 | title, |
| 73 | open, |
| 74 | loading: share.loading, |
| 75 | creating: share.creating, |
| 76 | error: share.error, |
| 77 | dialogAffordance: share.dialogAffordance, |
| 78 | publishAffordance, |
| 79 | workspaceRole, |
| 80 | online, |
| 81 | currentUserId, |
| 82 | activeTab, |
| 83 | setActiveTab, |
| 84 | toggleOpen, |
| 85 | close, |
| 86 | deleteShare: share.deleteShare, |
| 87 | }), |
| 88 | [ |
| 89 | disabled, |
| 90 | title, |
| 91 | open, |
| 92 | share.loading, |
| 93 | share.creating, |
| 94 | share.error, |
| 95 | share.dialogAffordance, |
| 96 | share.deleteShare, |
| 97 | publishAffordance, |
| 98 | workspaceRole, |
| 99 | online, |
| 100 | currentUserId, |
| 101 | activeTab, |
| 102 | toggleOpen, |
| 103 | close, |
| 104 | ], |
| 105 | ); |
| 106 | |
| 107 | return { shell, people: share.people, link: share.link, publish }; |
| 108 | } |