mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Board-member upload permission for documents & bids/quotes
Add a "Allow document & bid/quote uploads" toggle on board member profiles (board_members.can_upload). When enabled, that board member can upload association documents and create/manage bids & quotes for their association(s); otherwise the board portal stays read-only for them. - Migration (prod): board_members.can_upload column; tighten the documents insert + storage 'files' upload policies to require can_upload; add a bids_quotes board policy gated on can_upload. - BoardMembersPage: permission switch (load/save). - BoardAssociationContext: expose canUpload for the selected association. - DocumentsPage: board upload gated by the flag (was always-on for board). - BidsQuotesPage: permitted board members can add/manage bids (was hidden); board inserts target the board's association. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,11 +16,11 @@ 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;
|
||||
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, association_id: "" };
|
||||
const emptyForm = { member_name: "", member_email: "", phone: "", role: "Member", approval_authority: false, can_upload: false, association_id: "" };
|
||||
|
||||
export default function BoardMembersPage() {
|
||||
const { toast } = useToast();
|
||||
@@ -55,7 +55,7 @@ export default function BoardMembersPage() {
|
||||
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, association_id: m.association_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);
|
||||
};
|
||||
|
||||
@@ -68,10 +68,11 @@ export default function BoardMembersPage() {
|
||||
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).eq("id", editingId)
|
||||
: await supabase.from("board_members").insert(payload);
|
||||
? 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);
|
||||
@@ -208,6 +209,10 @@ export default function BoardMembersPage() {
|
||||
<Switch checked={form.approval_authority} onCheckedChange={v => setForm({ ...form, approval_authority: v })} />
|
||||
<Label>Approval Authority</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Switch checked={form.can_upload} onCheckedChange={v => setForm({ ...form, can_upload: v })} />
|
||||
<Label>Allow document & bid/quote uploads</Label>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setFormOpen(false)}>Cancel</Button>
|
||||
|
||||
Reference in New Issue
Block a user