"use client" import { useState, useEffect } from "react" import { useSession } from "next-auth/react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Users, Mail, Trash2, Plus, Shield, Eye, Edit } from "lucide-react" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { useFamily } from "@/context/family-context" import { useDialog } from "@/components/ui/alert-dialog-custom" interface Collaborator { id: string userId: string role: "EDITOR" | "VIEWER" invitedAt: string user: { id: string name: string | null email: string avatar: string | null } } export function CollaboratorManager() { const { data: session } = useSession() const { currentTree } = useFamily() const { showConfirm, showAlert } = useDialog() const [collaborators, setCollaborators] = useState([]) const [isLoading, setIsLoading] = useState(false) const [isInviting, setIsInviting] = useState(false) const [email, setEmail] = useState("") const [role, setRole] = useState<"EDITOR" | "VIEWER">("VIEWER") const [password, setPassword] = useState("") const [error, setError] = useState("") const [success, setSuccess] = useState("") // 加载协作者 useEffect(() => { if (currentTree?.id) { loadCollaborators() } }, [currentTree?.id]) const loadCollaborators = async () => { if (!currentTree?.id) return try { const res = await fetch(`/api/trees/${currentTree.id}/collaborators`) if (res.ok) { const data = await res.json() setCollaborators(data.collaborators) } } catch (err) { console.error("加载协作者失败:", err) } } const handleInvite = async (e: React.FormEvent) => { e.preventDefault() if (!currentTree?.id) return setIsInviting(true) setError("") setSuccess("") try { const res = await fetch(`/api/trees/${currentTree.id}/invite`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email, role, password: password || undefined, // 只有填写了才发送 }), }) const data = await res.json() if (!res.ok) { throw new Error(data.error || "邀请失败") } setSuccess(data.message) setEmail("") setPassword("") loadCollaborators() } catch (err: any) { setError(err.message) } finally { setIsInviting(false) } } const handleRemove = async (userId: string) => { if (!currentTree?.id) return const confirmed = await showConfirm("确定要移除此协作者吗?", "移除协作者") if (!confirmed) return try { const res = await fetch(`/api/trees/${currentTree.id}/collaborators?userId=${userId}`, { method: 'DELETE', }) if (!res.ok) throw new Error('移除失败') loadCollaborators() } catch (err) { console.error(err) await showAlert("移除失败", "错误") } } if (!currentTree) return null // 只有所有者可以看到此组件 if (currentTree.ownerId !== session?.user?.id) return null return ( 协作管理 邀请其他用户协作编辑或查看您的家族树"{currentTree.name}" {/* 邀请表单 */}
setEmail(e.target.value)} required />
setPassword(e.target.value)} minLength={6} />
{error && ( 错误 {error} )} {success && ( 成功 {success} )}
{/* 协作者列表 */}

现有协作者

{collaborators.length === 0 ? (

暂无协作者

) : (
{collaborators.map((collab) => (
{collab.user.name?.charAt(0).toUpperCase() || collab.user.email.charAt(0).toUpperCase()}
{collab.user.name || "用户"}
{collab.user.email}
{collab.role === 'EDITOR' ? '编辑者' : '查看者'}
))}
)}
) }