import { useRef } from "react"; import { Check, ChevronDown, Copy, Link2, Loader2, Trash2, Users } from "lucide-react"; import { Button } from "@/client/components/ui/button"; import { DropdownPortal } from "@/client/components/ui/dropdown-portal"; import { isActionEnabled, isActionVisible } from "@/client/lib/affordance/action-state"; import { deriveShareDialogRowAffordance } from "@/client/lib/affordance/share-dialog"; import type { PageShare } from "@/shared/types"; import { useShareDialogShell, useShareLink, useSharePeople } from "./context"; import type { SharePermission, WorkspaceRole } from "./types"; function PermissionSelect({ value, onChange }: { value: SharePermission; onChange: (v: SharePermission) => void }) { return (
); } export function SharePeopleSection() { const { creating, dialogAffordance, workspaceRole, online, currentUserId, deleteShare } = useShareDialogShell(); const { peopleInput, peoplePermission, showSuggestions, userShares, members, filteredSuggestions, hasMatchedMember, memberName, granteeName, setPeopleInput, setPeoplePermission, openSuggestions, dismissSuggestions, selectMember, submitPeopleShare, } = useSharePeople(); // Member role cannot invite by free-form email; the worker rejects it. // Surface that as an affordance: placeholder says "search", and submit // stays disabled until the input resolves to an actual workspace member. const placeholder = dialogAffordance.shareByEmail ? "Name or email..." : "Teammate..."; const ariaLabel = dialogAffordance.shareByEmail ? "Search people to share with" : "Search workspace members to share with"; const submitGuardedByMemberMatch = !dialogAffordance.shareByEmail && !hasMatchedMember; const submitDisabled = creating || !peopleInput.trim() || !isActionEnabled(dialogAffordance.createUserShare) || submitGuardedByMemberMatch; const submitTitle = dialogAffordance.createUserShare.kind === "disabled" ? dialogAffordance.createUserShare.reason : submitGuardedByMemberMatch ? "Members only" : undefined; const inputRef = useRef(null); const suggestionsOpen = showSuggestions && filteredSuggestions.length > 0 && peopleInput.trim().length > 0; return (

People

{ setPeopleInput(e.target.value); openSuggestions(); }} onFocus={openSuggestions} onKeyDown={(e) => { if (e.key === "Enter") { void submitPeopleShare(); } }} className="min-w-0 flex-1 rounded-md border border-zinc-700 bg-zinc-800 py-1.5 pl-2 text-sm text-zinc-300 outline-none focus:border-accent-500/50 focus:ring-1 focus:ring-accent-500/30" />
{suggestionsOpen && ( {filteredSuggestions.map((member) => ( ))} )} {userShares.length > 0 ? (
{userShares.map((share) => ( member.user_id === share.grantee_id)} onDelete={() => void deleteShare(share.id)} /> ))}
) : (

No people shares

)}
); } export function ShareLinkSection() { const { creating, dialogAffordance, workspaceRole, online, currentUserId, deleteShare } = useShareDialogShell(); const { linkPermission, linkShares, copiedId, setLinkPermission, createLinkShare, copyLink } = useShareLink(); return (

Link

{isActionVisible(dialogAffordance.createLinkShare) && (
)} {linkShares.length > 0 ? (
{linkShares.map((share) => ( copyLink(share)} onDelete={() => void deleteShare(share.id)} /> ))}
) : ( isActionVisible(dialogAffordance.createLinkShare) && (

No link shares

) )}
); } function ShareUserRow({ share, label, workspaceRole, online, currentUserId, granteeIsWorkspaceMember, onDelete, }: { share: PageShare; label: string; workspaceRole: WorkspaceRole; online: boolean; currentUserId: string | undefined; granteeIsWorkspaceMember: boolean; onDelete: () => void; }) { const rowAffordance = deriveShareDialogRowAffordance({ workspaceRole, online, currentUserId, share, granteeIsWorkspaceMember, }); return (
{label} {share.permission}
{isActionVisible(rowAffordance.revoke) && (
); } function ShareLinkRow({ share, copiedId, workspaceRole, online, currentUserId, onCopy, onDelete, }: { share: PageShare; copiedId: string | null; workspaceRole: WorkspaceRole; online: boolean; currentUserId: string | undefined; onCopy: () => void; onDelete: () => void; }) { const rowAffordance = deriveShareDialogRowAffordance({ workspaceRole, online, currentUserId, share, granteeIsWorkspaceMember: false, }); return (
{share.permission} link
{isActionVisible(rowAffordance.copyLink) && (
); }