"use client"; import { useParams } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; import { api } from "@/lib/api/client"; import type { components } from "@/lib/api/schema"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; type Member = components["schemas"]["MembershipRead"]; type Role = components["schemas"]["MembershipRole"]; const ROLES: Role[] = ["owner", "editor", "viewer"]; export default function MembersPage() { const { id: treeId } = useParams<{ id: string }>(); const [members, setMembers] = useState([]); const [meId, setMeId] = useState(null); const [email, setEmail] = useState(""); const [role, setRole] = useState("viewer"); const [msg, setMsg] = useState(null); const [ready, setReady] = useState(false); const load = useCallback(async () => { const [me, mem] = await Promise.all([ api.GET("/api/v1/users/me"), api.GET("/api/v1/trees/{tree_id}/members", { params: { path: { tree_id: treeId } } }), ]); setMeId(me.data?.id ?? null); setMembers(mem.data ?? []); setReady(true); }, [treeId]); useEffect(() => { load(); }, [load]); const myRole = members.find((m) => m.user_id === meId)?.role; const isOwner = myRole === "owner"; async function addMember(e: React.FormEvent) { e.preventDefault(); setMsg(null); const { error, response } = await api.POST("/api/v1/trees/{tree_id}/members", { params: { path: { tree_id: treeId } }, body: { email: email.trim(), role }, }); if (error) { setMsg( response.status === 404 ? "No account on this site has that email — they need to register first." : response.status === 409 ? "That person is already a member." : "Couldn't add that member.", ); return; } setEmail(""); load(); } async function changeRole(membershipId: string, newRole: Role) { const { error } = await api.PATCH("/api/v1/trees/{tree_id}/members/{membership_id}", { params: { path: { tree_id: treeId, membership_id: membershipId } }, body: { role: newRole }, }); if (error) setMsg("Couldn't change role (a tree must keep at least one owner)."); load(); } async function remove(membershipId: string) { const { error } = await api.DELETE("/api/v1/trees/{tree_id}/members/{membership_id}", { params: { path: { tree_id: treeId, membership_id: membershipId } }, }); if (error) setMsg("Couldn't remove (a tree must keep at least one owner)."); load(); } if (!ready) return

Loading…

; return (

Members

Who can see and edit this tree. {isOwner ? "You're the owner." : `Your role: ${myRole}.`}

{isOwner && (
{msg &&

{msg}

}
)} {members.map((m, i) => (
0 ? "border-t border-[var(--border)]" : "" }`} >
{m.display_name || m.email}
{m.email}
{isOwner ? (
) : ( {m.role} )}
))}
); }