"use client"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useAtomValue, useSetAtom } from "jotai"; import { Earth, User, Users } from "lucide-react"; import { useParams, useRouter } from "next/navigation"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom"; import { myAccessAtom } from "@/atoms/members/members-query.atoms"; import { createPublicChatSnapshotMutationAtom } from "@/atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { chatThreadsApiService } from "@/lib/apis/chat-threads-api.service"; import { type ChatVisibility, type ThreadRecord, updateThreadVisibility, } from "@/lib/chat/thread-persistence"; import { cn } from "@/lib/utils"; interface ChatShareButtonProps { thread: ThreadRecord | null; onVisibilityChange?: (visibility: ChatVisibility) => void; className?: string; } const visibilityOptions: { value: ChatVisibility; label: string; description: string; icon: typeof User; }[] = [ { value: "PRIVATE", label: "Private", description: "Only you can access this chat", icon: User, }, { value: "SEARCH_SPACE", label: "Search Space", description: "All members of this search space can access", icon: Users, }, ]; export function ChatShareButton({ thread, onVisibilityChange, className }: ChatShareButtonProps) { const queryClient = useQueryClient(); const router = useRouter(); const params = useParams(); const [open, setOpen] = useState(false); // Use Jotai atom for visibility (single source of truth) const currentThreadState = useAtomValue(currentThreadAtom); const setThreadVisibility = useSetAtom(setThreadVisibilityAtom); // Snapshot creation mutation const { mutateAsync: createSnapshot, isPending: isCreatingSnapshot } = useAtomValue( createPublicChatSnapshotMutationAtom ); // Permission check for public sharing const { data: access } = useAtomValue(myAccessAtom); const canCreatePublicLink = useMemo(() => { if (!access) return false; if (access.is_owner) return true; return access.permissions?.includes("public_sharing:create") ?? false; }, [access]); // Query to check if thread has public snapshots const { data: snapshotsData } = useQuery({ queryKey: ["thread-snapshots", thread?.id], queryFn: () => chatThreadsApiService.listPublicChatSnapshots({ thread_id: thread!.id }), enabled: !!thread?.id, staleTime: 30000, // Cache for 30 seconds }); const hasPublicSnapshots = (snapshotsData?.snapshots?.length ?? 0) > 0; const snapshotCount = snapshotsData?.snapshots?.length ?? 0; // Use Jotai visibility if available (synced from chat page), otherwise fall back to thread prop const currentVisibility = currentThreadState.visibility ?? thread?.visibility ?? "PRIVATE"; const handleVisibilityChange = useCallback( async (newVisibility: ChatVisibility) => { if (!thread || newVisibility === currentVisibility) { setOpen(false); return; } // Update Jotai atom immediately for instant UI feedback setThreadVisibility(newVisibility); try { await updateThreadVisibility(thread.id, newVisibility); // Refetch threads list to update sidebar await queryClient.refetchQueries({ predicate: (query) => Array.isArray(query.queryKey) && query.queryKey[0] === "threads", }); onVisibilityChange?.(newVisibility); toast.success( newVisibility === "SEARCH_SPACE" ? "Chat shared with search space" : "Chat is now private" ); setOpen(false); } catch (error) { console.error("Failed to update visibility:", error); // Revert Jotai state on error setThreadVisibility(thread.visibility ?? "PRIVATE"); toast.error("Failed to update sharing settings"); } }, [thread, currentVisibility, onVisibilityChange, queryClient, setThreadVisibility] ); const handleCreatePublicLink = useCallback(async () => { if (!thread) return; try { await createSnapshot({ thread_id: thread.id }); // Refetch snapshots to show the globe indicator await queryClient.invalidateQueries({ queryKey: ["thread-snapshots", thread.id] }); setOpen(false); } catch (error) { console.error("Failed to create public link:", error); } }, [thread, createSnapshot, queryClient]); // Don't show if no thread (new chat that hasn't been created yet) if (!thread) { return null; } const CurrentIcon = currentVisibility === "PRIVATE" ? User : Users; const buttonLabel = currentVisibility === "PRIVATE" ? "Private" : "Shared"; return (