Files
acmcc/supabase/functions/_shared/transactional-email-templates/registry.ts
T
admin 2c723410a4 Bill approvals: surface approvers, fix email path, schema cleanup
UI

- Dashboard BillApprovalsCard: render approver name chips (color-coded
  by vote status) per pending bill instead of leaving the approver
  identity invisible.
- BillDetailPage: collapse the duplicate "Requested Approvers" card
  into the existing "Approvers" table. Approve/deny handler now stamps
  approved_by = auth.uid() for audit trail.
- MasterBoardDashboardPage: the "pending approvals for me" count was
  filtering on a non-existent bill_approvals.approver_user_id column.
  Replaced with a board_members.member_name -> bill_approvals.approver_name
  join (matches the RLS policy).
- BillApprovalRequestDialog + AIInvoiceParserPage: bill_approvals inserts
  now set created_by.

Database

- Rename public.bill_approvals.vendor_name -> approver_name. RLS policies
  auto-rewritten by ALTER TABLE RENAME COLUMN; the column was misnamed
  (it stores the approver's board-member name, never a vendor).
- Restore the bill_approval_email_tokens table + lookup_/record_
  bill_approval_by_token RPCs. The original 20260520153409 migration
  was never applied successfully; rewrote it to use approver_name and
  to populate approved_by/created_by from board_members.user_id on
  token-driven votes. Added the v2 migration that matches the live DB
  state.
- accounting trigger: void on accounting.bills cascades to
  public.bills.status='cancelled' (existing forward sync then drops the
  accounting row per accounting.bill_should_mirror).

Edge function

- send-transactional-email: add bill-approval-request and
  bill-approval-vote-invite templates (caller paths in BillApprovalsPage
  + send-bill-approval-invites referenced templates that weren't in the
  registry, so every email 404'd). Restored the local copies of
  election-invite, board-vote-invite, and the missing registry.ts so the
  repo matches what's deployed. Deployed to send-transactional-email v35.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-04 17:17:05 -04:00

36 lines
1.6 KiB
TypeScript

/// <reference types="npm:@types/react@18.3.1" />
import * as React from 'npm:react@18.3.1'
export interface TemplateEntry {
component: React.ComponentType<any>
subject: string | ((data: Record<string, any>) => string)
to?: string
displayName?: string
previewData?: Record<string, any>
}
import { template as tenantInfoRequest } from './tenant-info-request.tsx'
import { template as ticketSubmitted } from './ticket-submitted.tsx'
import { template as ticketResponse } from './ticket-response.tsx'
import { template as vendorInsuranceRequest } from './vendor-insurance-request.tsx'
import { template as vendorProfileRequest } from './vendor-profile-request.tsx'
import { template as signupCodeInvite } from './signup-code-invite.tsx'
import { template as taskNotification } from './task-notification.tsx'
import { template as electionInvite } from './election-invite.tsx'
import { template as boardVoteInvite } from './board-vote-invite.tsx'
import { template as billApprovalRequest } from './bill-approval-request.tsx'
import { template as billApprovalVoteInvite } from './bill-approval-vote-invite.tsx'
export const TEMPLATES: Record<string, TemplateEntry> = {
'ticket-submitted': ticketSubmitted,
'ticket-response': ticketResponse,
'vendor-insurance-request': vendorInsuranceRequest,
'vendor-profile-request': vendorProfileRequest,
'signup-code-invite': signupCodeInvite,
'task-notification': taskNotification,
'election-invite': electionInvite,
'board-vote-invite': boardVoteInvite,
'tenant-info-request': tenantInfoRequest,
'bill-approval-request': billApprovalRequest,
'bill-approval-vote-invite': billApprovalVoteInvite,
}