import { useState, useEffect } from "react"; import { supabase } from "@/integrations/supabase/client"; import { useToast } from "@/hooks/use-toast"; import { Card, CardContent, 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 { Badge } from "@/components/ui/badge"; import { Switch } from "@/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Plus, Edit, Trash2, Shield, Loader2, FilterX } from "lucide-react"; import RecordImportButton from "@/components/RecordImportButton"; import type { Tables } from "@/integrations/supabase/types"; type BoardMember = { id: string; association_id: string; member_name: string; member_email: string | null; phone: string | null; role: string | null; approval_authority: boolean; can_upload: boolean; created_at: string; associations?: { name: string } | null; }; const emptyForm = { member_name: "", member_email: "", phone: "", role: "Member", approval_authority: false, can_upload: false, association_id: "" }; export default function BoardMembersPage() { const { toast } = useToast(); const [members, setMembers] = useState([]); const [associations, setAssociations] = useState[]>([]); const [loading, setLoading] = useState(true); const [selectedAssoc, setSelectedAssoc] = useState("all"); const [formOpen, setFormOpen] = useState(false); const [editingId, setEditingId] = useState(null); const [form, setForm] = useState(emptyForm); const [saving, setSaving] = useState(false); const [deleteOpen, setDeleteOpen] = useState(false); const [deleteMember, setDeleteMember] = useState(null); useEffect(() => { fetchData(); }, []); const fetchData = async () => { setLoading(true); const [mRes, aRes] = await Promise.all([ supabase.from("board_members").select("*, associations(name)").order("created_at", { ascending: false }), supabase.from("associations").select("id, name").eq("status", "active").order("name"), ]); if (mRes.data) setMembers(mRes.data as BoardMember[]); if (aRes.data) setAssociations(aRes.data as Tables<"associations">[]); setLoading(false); }; const filtered = members.filter(m => selectedAssoc === "all" || m.association_id === selectedAssoc); const openAdd = () => { setEditingId(null); setForm({ ...emptyForm }); setFormOpen(true); }; const openEdit = (m: BoardMember) => { setEditingId(m.id); setForm({ member_name: m.member_name, member_email: m.member_email || "", phone: m.phone || "", role: m.role || "Member", approval_authority: m.approval_authority, can_upload: m.can_upload ?? false, association_id: m.association_id }); setFormOpen(true); }; const handleSave = async () => { if (!form.member_name || !form.association_id) { toast({ variant: "destructive", title: "Name and association are required" }); return; } setSaving(true); const payload = { association_id: form.association_id, member_name: form.member_name, member_email: form.member_email || null, phone: form.phone || null, role: form.role || "Member", approval_authority: form.approval_authority, can_upload: form.can_upload, }; const { error } = editingId ? await supabase.from("board_members").update(payload as any).eq("id", editingId) : await supabase.from("board_members").insert(payload as any); if (error) toast({ variant: "destructive", title: "Error", description: error.message }); else { toast({ title: editingId ? "Member updated" : "Member added" }); setFormOpen(false); fetchData(); } setSaving(false); }; const handleDelete = async () => { if (!deleteMember) return; const { error } = await supabase.from("board_members").delete().eq("id", deleteMember.id); if (error) toast({ variant: "destructive", title: "Error", description: error.message }); else { toast({ title: "Deleted" }); fetchData(); } setDeleteOpen(false); setDeleteMember(null); }; return (

Board Members

Manage association board members and approval authorities.

{ const assocId = associations[0]?.id; if (!assocId) throw new Error("Create an association first"); const payload = rows.map(r => ({ member_name: r.member_name || "Unknown", member_email: r.member_email || null, phone: r.phone || null, role: r.role || "Member", association_id: assocId, })); const { error } = await supabase.from("board_members").insert(payload); if (error) throw error; toast({ title: `Imported ${rows.length} board members` }); fetchData(); }} templateFileName="board_members_template.xlsx" />
Member Directory
{selectedAssoc !== "all" && }
Name Email Association Role Authority Actions {loading ? ( ) : filtered.length === 0 ? ( No board members found. ) : filtered.map(m => ( {m.member_name} {m.member_email || "—"} {m.associations?.name || "—"} {m.role || "Member"} {m.approval_authority ? Approver : None} ))}
{/* Add/Edit Dialog */} {editingId ? "Edit" : "Add"} Board Member
setForm({ ...form, member_name: e.target.value })} />
setForm({ ...form, member_email: e.target.value })} />
setForm({ ...form, phone: e.target.value })} />
setForm({ ...form, approval_authority: v })} />
setForm({ ...form, can_upload: v })} />
{/* Delete Confirmation */} Confirm Deletion Are you sure you want to delete {deleteMember?.member_name}? This cannot be undone.
); }