"use client"; import { useState } from "react"; import { UserPlus, X } from "lucide-react"; import { toast } from "sonner"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; type Role = "viewer" | "editor"; interface Member { id: string; userId: string; role: Role; createdAt: string; user: { name: string; username: string | null; avatarUrl: string | null; }; } interface Props { collectionId: string; } export function ShareCollectionButton({ collectionId }: Props) { const [open, setOpen] = useState(false); const [email, setEmail] = useState(""); const [role, setRole] = useState("viewer"); const [members, setMembers] = useState([]); const [loading, setLoading] = useState(false); const [inviting, setInviting] = useState(false); async function fetchMembers() { setLoading(true); try { const res = await fetch(`/api/v1/collections/${collectionId}/members`); if (!res.ok) throw new Error("Failed to load members"); const data = await res.json() as Member[]; setMembers(data); } catch { toast.error("Could not load members"); } finally { setLoading(false); } } function handleOpenChange(next: boolean) { setOpen(next); if (next) { void fetchMembers(); } else { setEmail(""); setRole("viewer"); } } async function handleInvite() { if (!email.trim()) { toast.error("Enter an email address"); return; } setInviting(true); try { const res = await fetch(`/api/v1/collections/${collectionId}/members`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: email.trim(), role }), }); if (res.status === 409) { toast.error("Already a member"); return; } if (res.status === 404) { toast.error("User not found"); return; } if (!res.ok) { toast.error("Could not invite user"); return; } toast.success("Invitation sent"); setEmail(""); await fetchMembers(); } catch { toast.error("Could not invite user"); } finally { setInviting(false); } } async function handleRemove(memberId: string) { try { const res = await fetch( `/api/v1/collections/${collectionId}/members?memberId=${memberId}`, { method: "DELETE" }, ); if (!res.ok) { toast.error("Could not remove member"); return; } setMembers((prev) => prev.filter((m) => m.id !== memberId)); toast.success("Member removed"); } catch { toast.error("Could not remove member"); } } return ( <> Share collection Invite people to view or edit this collection. {/* Invite form */}
setEmail(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") void handleInvite(); }} className="flex-1" />
{/* Members list */}
{loading && (

Loading members…

)} {!loading && members.length === 0 && (

No members yet.

)} {members.map((m) => (
{m.user.name} {m.user.username && ( @{m.user.username} )}
{m.role}
))}
); }