@fayz-ai/plugin-agenda 0.12.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridges/create-financial-bridge.d.ts.map +1 -1
- package/dist/{chunk-ISLJXP7O.js → chunk-PDYBAVXU.js} +6 -4
- package/dist/chunk-PDYBAVXU.js.map +1 -0
- package/dist/components/AppointmentModal.d.ts.map +1 -1
- package/dist/components/CalendarSidebar.d.ts.map +1 -1
- package/dist/components/CheckinDialog.d.ts +24 -0
- package/dist/components/CheckinDialog.d.ts.map +1 -0
- package/dist/components/FilterRail.d.ts +42 -0
- package/dist/components/FilterRail.d.ts.map +1 -0
- package/dist/components/MiniCalendar.d.ts +1 -8
- package/dist/components/MiniCalendar.d.ts.map +1 -1
- package/dist/components/PaymentStatusBadge.d.ts +4 -9
- package/dist/components/PaymentStatusBadge.d.ts.map +1 -1
- package/dist/components/StatusBadge.d.ts +6 -0
- package/dist/components/StatusBadge.d.ts.map +1 -1
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/data/mock.d.ts.map +1 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/types.d.ts +2 -2
- package/dist/data/types.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2343 -472
- package/dist/index.js.map +1 -1
- package/dist/integrations/google-calendar/connectorDef.d.ts +1 -1
- package/dist/integrations/google-calendar/credentials.d.ts +1 -1
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +7 -21
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/public/index.js +2 -2
- package/dist/store.d.ts +8 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/views/CalendarView.d.ts +16 -0
- package/dist/views/CalendarView.d.ts.map +1 -1
- package/dist/views/CheckinPage.d.ts +12 -0
- package/dist/views/CheckinPage.d.ts.map +1 -0
- package/dist/views/CheckinView.d.ts +13 -0
- package/dist/views/CheckinView.d.ts.map +1 -0
- package/package.json +5 -5
- package/dist/chunk-ISLJXP7O.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/message-events.ts","../src/config.ts","../src/context.tsx","../src/styles/calendar-styles.ts","../src/hooks/useAgendaSettings.ts","../src/components/MiniCalendar.tsx","../src/components/BookingPaymentPanel.tsx","../src/types.ts","../src/components/AppointmentModal.tsx","../src/components/FloatingPanel.tsx","../src/components/AppointmentPopover.tsx","../src/components/EventContextMenu.tsx","../src/components/AgendaMobileList.tsx","../src/lib/calendar-events.ts","../src/views/CalendarView.tsx","../src/lib/tenant.ts","../src/views/AgendaPage.tsx","../src/data/supabase.ts","../src/lib/booking-events.ts","../src/store.ts","../src/data/registries.ts","../src/components/AgendaGeneralSettings.tsx","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/migrations/index.ts","../src/bridges/create-financial-bridge.ts","../src/integrations/google-calendar/mapping.ts","../src/integrations/google-calendar/credentials.ts","../src/integrations/google-calendar/data/tables.ts","../src/integrations/google-calendar/data/supabase.ts","../src/integrations/google-calendar/health.ts","../src/integrations/google-calendar/panel-data.ts","../src/integrations/google-calendar/components/CalendarColorDot.tsx","../src/integrations/google-calendar/components/useAgendaLookups.ts","../src/integrations/google-calendar/components/ChannelMappingList.tsx","../src/integrations/google-calendar/components/ImportEventsWizard.tsx","../src/integrations/google-calendar/connectorDef.tsx","../src/integrations/google-calendar/migrations/index.ts","../src/integrations/google-calendar/connector.ts","../src/integrations/google-calendar/index.ts","../src/index.ts"],"names":["React","formatCurrency","t","jsxs","jsx","useState","useEffect","Fragment","createPortal","useTranslation","getCurrentLocale","provider","useMemo","getSupabaseClientOptional","X","Check","STYLE_ID","useRef","fmtCurrency","Clock","User","MapPin","FileText","HandCoins","DollarSign","AlertTriangle","Tooltip","Pencil","Trash2","usePluginPrefs","useCallback","booking","t2","PersonLink","Plus","ChevronLeft","ChevronRight","Button","getActiveTenantId","bookingToEvent","localTimeZone","toast","Loader2","AlertCircle","RefreshCw","Checkbox","Badge","setScheduleBlockConfig","getScheduleBlockConfig"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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A;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAugBjC,IAAM,wBAAA,GAA2B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmRjC,IAAM,+BAAA,GAAkC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAwKxC,IAAM,qCAAA,GAAwC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAuM9C,IAAM,uCAAA,GAA0C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAyJhD,IAAM,qCAAA,GAAwC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"index.js","sourcesContent":["import type {\n PluginEventDefinition, MessageDefaultsDef, EventField, MessageAction,\n} from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Os FATOS da agenda, e — separadamente — o texto sugerido para cada um.\n//\n// buildAgendaDomainEvents() o contrato do fato: o que houve, que dados\n// vêm junto, se entra na auditoria. Webhook,\n// Google Agenda e auditoria leem isto.\n// buildAgendaMessageDefaults() uma REAÇÃO: canal + texto. Só as automações.\n//\n// É aqui que mora a automação que todo salão e toda clínica esperam ter no\n// primeiro dia: o lembrete de véspera. Cliente que não aparece é prejuízo\n// direto, e o lembrete é a mensagem que se paga sozinha.\n// ---------------------------------------------------------------------------\n\nconst BOOKING_FIELDS: EventField[] = [\n { name: 'customer_name', label: 'Cliente', type: 'string', example: 'Maria Silva' },\n // Para ONDE a mensagem vai — não é texto de mensagem nenhuma, é o endereço.\n // A automação de WhatsApp lê este campo (`recipientField`, padrão\n // 'customer_phone') e pula o disparo quando ele vem vazio: sem número não há\n // envio, e um evento sem ele é um lembrete que nunca sai.\n { name: 'customer_phone', label: 'Telefone do cliente', type: 'string', example: '(21) 99889-9889' },\n { name: 'service_name', label: 'Serviço', type: 'string', example: 'Corte + Escova' },\n { name: 'professional_name', label: 'Profissional', type: 'string', example: 'Camila Duarte' },\n { name: 'booking_date', label: 'Data', type: 'date', example: '12/08/2026' },\n { name: 'booking_time', label: 'Horário', type: 'string', example: '14:30' },\n { name: 'location_name', label: 'Local', type: 'string', example: 'Unidade Centro' },\n // Not in bookingPayload on purpose: the browser has no reliable source for\n // the tenant's public name, so the SENDER fills this slot (messaging-send\n // reads the tenants row). The field stays declared because templates use it\n // and the editor needs its placeholder.\n { name: 'business_name', label: 'Seu negócio', type: 'string', example: 'Seu Negócio' },\n]\n\n/**\n * Os FATOS da agenda.\n *\n * `audit: true` em todos: marcar, remarcar e cancelar um horário são ATOS de\n * alguém — e \"quem cancelou este atendimento?\" é exatamente a pergunta que a\n * trilha de auditoria existe para responder. Nenhum evento aqui é a ausência\n * de um ato: até 'no_show' é registrado por alguém da recepção.\n */\nexport function buildAgendaDomainEvents(): PluginEventDefinition[] {\n return [\n { name: 'agenda.booking_created', title: 'Agendamento criado', icon: 'CalendarPlus', audit: true,\n description: 'Um horário foi marcado',\n trigger: 'Quando o agendamento é criado (recepção, site ou app)',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_reminder', title: 'Lembrete de horário', icon: 'BellRing', audit: false,\n description: 'Véspera do atendimento',\n trigger: 'No dia anterior ao horário marcado',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_rescheduled', title: 'Horário remarcado', icon: 'CalendarClock', audit: true,\n description: 'O atendimento mudou de dia ou de hora',\n trigger: 'Quando a data ou o horário do agendamento muda',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_cancelled', title: 'Agendamento cancelado', icon: 'CalendarX', audit: true,\n description: 'O horário foi desmarcado',\n trigger: 'Quando o agendamento é cancelado',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_completed', title: 'Atendimento concluído', icon: 'CalendarCheck', audit: true,\n description: 'O atendimento aconteceu',\n trigger: 'Quando o agendamento é marcado como concluído',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_no_show', title: 'Cliente não compareceu', icon: 'UserX', audit: true,\n description: 'O horário foi perdido',\n trigger: 'Quando o agendamento é marcado como falta',\n fields: BOOKING_FIELDS },\n ]\n}\n\n/**\n * Confirmar / Cancelar, os dois botões que resolvem a conversa inteira.\n *\n * O `id` é o que VOLTA: ele viaja no payload do botão junto com o id do\n * agendamento, e é isso que faz a resposta atualizar o horário certo. O jeito\n * antigo — casar a palavra que a cliente digitou (\"sim\", \"confirmo\") — confirmava\n * todos os horários futuros dela de uma vez, e é essa classe de bug que o botão\n * com id apaga.\n */\nconst CONFIRM_OR_CANCEL: MessageAction[] = [\n { id: 'confirm', label: 'Confirma', kind: 'reply' },\n { id: 'cancel', label: 'Cancela', kind: 'reply' },\n]\n\nexport function buildAgendaMessageDefaults(): MessageDefaultsDef[] {\n return [\n {\n eventKey: 'agenda.booking_created',\n kind: 'transactional',\n // WhatsApp na frente em toda a agenda: confirmação de horário é lida no\n // celular, e no Brasil é lá que a cliente responde.\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // Curto porque os botões dizem o resto: a linha \"qualquer coisa é só\n // chamar\" virou Confirmar/Cancelar, que além de ser menos texto já\n // atualiza o agendamento sozinho.\n // Sem botões, de propósito (decisão do founder 2026-08-24): esta é a\n // confirmação informativa de que a reserva EXISTE. Confirmar presença é\n // trabalho do lembrete de véspera, onde a resposta ainda muda o dia.\n body: 'Oi {{customer_name}}! Tudo certo — seu horário foi reservado na nossa agenda ✅\\n\\nServiço: *{{service_name}}*\\nData: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nSe precisar ajustar alguma coisa, é só responder esta mensagem.\\n\\nEquipe {{business_name}} agradece a preferência!',\n },\n email: {\n subject: 'Horário confirmado — {{booking_date}} às {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário está confirmado:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n{{location_name}}\\n\\nAté lá!\\n{{business_name}}',\n },\n },\n // Confirmar por e-mail é o mínimo que se espera de quem acabou de marcar\n // um horário — nasce ligado. O WhatsApp custa por mensagem e exige número\n // aprovado; ligá-lo sozinho gastaria o dinheiro de alguém sem ser pedido.\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_reminder',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // AQUI moram Confirma/Cancela: na véspera a resposta ainda muda o dia —\n // libera o horário ou garante a presença.\n body: 'Oi {{customer_name}}! Passando para lembrar do seu horário amanhã 💇\\n\\nServiço: *{{service_name}}*\\nData: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nConsegue vir? É só tocar em Confirma ou Cancela aqui embaixo — e se precisar de outro horário, responde esta mensagem.\\n\\nEquipe {{business_name}} te espera!',\n actions: CONFIRM_OR_CANCEL,\n },\n email: {\n subject: 'Lembrete: seu horário é amanhã, {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário é amanhã:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n{{location_name}}\\n\\nSe precisar remarcar, é só responder este e-mail.\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_rescheduled',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}! Seu horário foi remarcado 🗓\\n\\nServiço: *{{service_name}}*\\nNova data: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nSe a nova data não funcionar para você, é só responder esta mensagem ou usar os botões abaixo.\\n\\nEquipe {{business_name}} agradece a compreensão!',\n // A data mudou, então a confirmação vale de novo: é o momento em que\n // mais gente some sem avisar.\n actions: CONFIRM_OR_CANCEL,\n },\n email: {\n subject: 'Seu horário mudou para {{booking_date}}, {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário foi remarcado:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_cancelled',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // Sem botões, de propósito: não há o que confirmar num horário que já\n // foi desmarcado, e um \"Confirmar\" aqui só poderia dar erro.\n body: 'Oi {{customer_name}}, seu horário de {{booking_date}} às {{booking_time}} foi cancelado.\\n\\nQuer que eu veja outra data? A equipe {{business_name}} fica à disposição.',\n },\n email: {\n subject: 'Horário de {{booking_date}} cancelado',\n body: 'Olá {{customer_name}},\\n\\nSeu horário de {{booking_date}} às {{booking_time}} foi cancelado.\\n\\nSe quiser remarcar, é só responder este e-mail.\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_completed',\n kind: 'marketing',\n // Pedir opinião é iniciativa do negócio, não resposta a um ato da\n // pessoa — e é por isso que nasce desligado.\n channels: ['whatsapp'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}! Foi ótimo te atender hoje 💛\\n\\nComo foi a experiência com {{professional_name}}? Sua opinião ajuda demais a equipe {{business_name}} a melhorar sempre.',\n },\n },\n },\n {\n eventKey: 'agenda.booking_no_show',\n kind: 'transactional',\n channels: ['whatsapp'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}, senti sua falta no horário de {{booking_date}} 😔\\n\\nAconteceu alguma coisa? Se quiser, já deixo outro horário separado para você aqui na {{business_name}}, é só responder.',\n },\n },\n },\n ]\n}\n","import type { PluginRegistryDef, PluginScope, VerticalId } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport type { AgendaDataProvider } from './data/types'\nimport type { StatusConfig, BookingTypeConfig } from './types'\nimport type { AgendaFinancialBridge } from './bridges/financial-bridge'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Public options interface\n// ---------------------------------------------------------------------------\n\nexport interface AgendaPluginLabels {\n pageTitle: string\n pageSubtitle: string\n calendar: string\n dayView: string\n weekView: string\n monthView: string\n listView: string\n workingHours: string\n confirmations: string\n newAppointment: string\n filters: string\n}\n\nexport interface ConfirmationChannelOption {\n id: string\n label: string\n icon: string\n}\n\nexport interface CancellationReasonOption {\n id: string\n label: string\n requiresNotes?: boolean\n}\n\nexport interface CancellationDetailsProvider {\n listReasons(): Promise<CancellationReasonOption[]>\n saveCancellationDetails(input: {\n bookingId: string\n reasonId: string\n notes?: string\n cancelledAt?: string\n }): Promise<void>\n}\n\nexport interface ExternalBookingSource {\n type: string\n id?: string\n [key: string]: unknown\n}\n\nexport interface LocationOption {\n id: string\n name: string\n isHQ?: boolean\n}\n\nexport interface AgendaPluginOptions {\n modules?: {\n workingHours?: boolean\n confirmations?: boolean\n conflictDetection?: boolean\n dragAndDrop?: boolean\n locationSelection?: boolean\n /** Enable financial integration (auto-enabled when financialBridge is provided) */\n financial?: boolean\n }\n labels?: Partial<AgendaPluginLabels>\n currency?: { code?: string; locale?: string; symbol?: string }\n\n /** Booking kind used in public.appointments.kind (default: 'appointment') */\n bookingKind?: string\n\n /** Order kind for financial records (default: 'service_order') */\n orderKind?: string\n\n /** Schedule kind in public.schedules.kind (default: 'working_hours') */\n scheduleKind?: string\n\n /** Booking type tabs shown in the appointment modal */\n bookingTypes?: BookingTypeConfig[]\n\n /**\n * Simplifies the agenda to Google-Calendar-style events (no client /\n * professional / service). When set to 'simple', the plugin exposes a single\n * \"Evento\" booking type whose modal shows only title / date-time / notes.\n * Ignored when an explicit `bookingTypes` override is provided.\n */\n eventMode?: 'simple'\n\n /** Booking status options */\n statuses?: StatusConfig[]\n\n /** Default calendar view (default: 'resourceTimeGridWeek'). Options: 'dayGridMonth', 'timeGridWeek', 'resourceTimeGridWeek', 'listWeek' */\n defaultCalendarView?: string\n\n /** Calendar visible time range (default: '07:00'-'21:00') */\n businessHours?: { startTime: string; endTime: string }\n\n /** Slot duration in minutes (default: 30) */\n slotDuration?: number\n\n /** Person kind for professionals (default: 'staff') */\n professionalKind?: string\n\n /** Person kind for clients (default: 'customer') */\n clientKind?: string\n\n /** Auto-create an order when creating a booking (default: true) */\n autoCreateOrder?: boolean\n\n /** Contact/client lookup */\n contactLookup?: EntityLookup\n\n /** Client entity definition for the Client tab in booking modal */\n clientEntityDef?: EntityDef\n\n /** Service lookup */\n serviceLookup?: EntityLookup\n\n /** Professional/staff lookup */\n professionalLookup?: EntityLookup\n\n /** Location lookup */\n locationLookup?: EntityLookup\n\n /** Called when user clicks a selected entity link (e.g. view client profile) */\n onEntityClick?: (type: 'client' | 'service' | 'professional', id: string) => void\n\n /** Business locations for unit filtering */\n locations?: LocationOption[]\n\n /** Confirmation channel options */\n confirmationChannels?: ConfirmationChannelOption[]\n\n /** Optional app/plugin bridge for cancel-time reason capture. */\n cancellationDetails?: CancellationDetailsProvider\n\n /** Called after a booking is created from an external operational source. */\n onBookingCreated?: (input: { bookingId: string; source?: ExternalBookingSource }) => void | Promise<void>\n\n /** App-owned registries shown under /settings/agenda Properties. */\n settingsRegistries?: PluginRegistryDef[]\n\n /** Financial bridge for agenda × financial cross-plugin integration */\n financialBridge?: AgendaFinancialBridge\n\n /** Data provider — defaults to Supabase, falls back to mock */\n dataProvider?: AgendaDataProvider\n\n /** Default values for schedule block advanced settings */\n scheduleBlockDefaults?: {\n bufferMinutes?: number\n maxConcurrent?: number\n minAdvanceHours?: number\n maxAdvanceDays?: number\n }\n\n navPosition?: number\n navSection?: 'main' | 'secondary'\n scope?: PluginScope\n verticalId?: VerticalId\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: AgendaPluginLabels = {\n pageTitle: 'Agenda',\n pageSubtitle: 'Calendar and appointment management',\n calendar: 'Calendar',\n dayView: 'Day',\n weekView: 'Week',\n monthView: 'Month',\n listView: 'Agenda',\n workingHours: 'Working Hours',\n confirmations: 'Confirmations',\n newAppointment: 'New Appointment',\n filters: 'Filters',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\nconst DEFAULT_STATUSES: StatusConfig[] = [\n { value: 'scheduled', label: 'Scheduled', color: '#6366f1' },\n { value: 'confirmed', label: 'Confirmed', color: '#3b82f6' },\n { value: 'in_progress', label: 'In Progress', color: '#f59e0b', availableWhen: 'today_only' },\n { value: 'completed', label: 'Completed', color: '#10b981', availableWhen: 'today_or_past' },\n { value: 'cancelled', label: 'Cancelled', color: '#ef4444' },\n { value: 'no_show', label: 'No Show', color: '#6b7280', availableWhen: 'today_or_past' },\n]\n\nconst DEFAULT_BOOKING_TYPES: BookingTypeConfig[] = [\n {\n id: 'appointment', label: 'Appointment', icon: 'Calendar', color: '#6366f1',\n fields: { client: true, professional: true, services: true, location: true, status: true },\n requiresServices: true, requiresClient: true,\n },\n {\n id: 'task', label: 'Task', icon: 'CheckSquare', color: '#f59e0b',\n fields: { client: false, professional: true, services: false, location: false, status: true },\n requiresServices: false, requiresClient: false,\n },\n {\n id: 'block', label: 'Block', icon: 'Ban', color: '#6b7280',\n fields: { client: false, professional: true, services: false, location: false, status: false },\n requiresServices: false, requiresClient: false,\n },\n]\n\n// Simple / Google-Calendar-style event — a single \"Evento\" type with just a\n// free-text title, date-time and notes. No client / professional / service.\n// Used by personal-finance-style agendas (see eventMode: 'simple').\nconst SIMPLE_EVENT_BOOKING_TYPES: BookingTypeConfig[] = [\n {\n id: 'event', label: 'Event', icon: 'Calendar', color: '#6366f1',\n fields: { title: true, client: false, professional: false, services: false, location: false, status: false },\n requiresServices: false, requiresClient: false,\n },\n]\n\n// ---------------------------------------------------------------------------\n// Resolved config — fully merged, no optionals\n// ---------------------------------------------------------------------------\n\nexport interface AgendaModules {\n workingHours: boolean\n confirmations: boolean\n conflictDetection: boolean\n dragAndDrop: boolean\n locationSelection: boolean\n financial: boolean\n}\n\n/**\n * Derived UI capabilities — computed ONCE in resolveConfig from the resolved\n * bookingTypes so no component ever re-derives \"is this a simple event agenda?\"\n * ad-hoc. A capability is enabled when ANY booking type uses that field. In\n * eventMode:'simple' the single \"Evento\" type disables\n * client/professional/services/location/status, so every consumer (popover,\n * filter rail, modal) hides the professional/service/status machinery in one\n * place instead of scattering `eventMode === 'simple'` checks.\n */\nexport interface AgendaCapabilities {\n title: boolean\n client: boolean\n professional: boolean\n services: boolean\n location: boolean\n status: boolean\n}\n\nexport interface AgendaCurrency {\n code: string\n locale: string\n symbol: string\n}\n\nexport interface ResolvedAgendaConfig {\n modules: AgendaModules\n /** Whether this is a simple Google-Calendar-style event agenda (eventMode:'simple'). */\n simpleMode: boolean\n /** Derived once from bookingTypes — see AgendaCapabilities. */\n capabilities: AgendaCapabilities\n labels: AgendaPluginLabels\n currency: AgendaCurrency\n bookingKind: string\n orderKind: string\n scheduleKind: string\n statuses: StatusConfig[]\n bookingTypes: BookingTypeConfig[]\n businessHours: { startTime: string; endTime: string }\n slotDuration: number\n professionalKind: string\n clientKind: string\n autoCreateOrder: boolean\n locations: LocationOption[]\n confirmationChannels: ConfirmationChannelOption[]\n cancellationDetails?: CancellationDetailsProvider\n onBookingCreated?: (input: { bookingId: string; source?: ExternalBookingSource }) => void | Promise<void>\n contactLookup?: EntityLookup\n clientEntityDef?: EntityDef\n serviceLookup?: EntityLookup\n professionalLookup?: EntityLookup\n locationLookup?: EntityLookup\n onEntityClick?: (type: 'client' | 'service' | 'professional', id: string) => void\n financialBridge?: AgendaFinancialBridge\n scheduleBlockDefaults: {\n bufferMinutes: number\n maxConcurrent: number\n minAdvanceHours: number\n maxAdvanceDays: number\n }\n defaultCalendarView: string\n}\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nexport function resolveConfig(options?: AgendaPluginOptions): ResolvedAgendaConfig {\n // ── eventMode:'simple' derives ALL module + capability defaults ONCE, here. ──\n // Simple = Google-Calendar-style events (title/description + timestamp). It\n // flips professional/service machinery OFF by default: no working-hours /\n // schedule checks, no confirmations outreach, no conflict (double-booking)\n // detection, no location. Explicit `modules.*` re-enable individually. Full\n // mode (beauty) is unchanged — every default below matches the old behavior\n // when `simple` is false. Field-level machinery (client/professional/\n // services/location/status/title) is derived into `capabilities` from the\n // resolved bookingTypes, so components never test eventMode themselves.\n const simple = options?.eventMode === 'simple'\n const bookingTypes = options?.bookingTypes\n ?? (simple ? SIMPLE_EVENT_BOOKING_TYPES : DEFAULT_BOOKING_TYPES)\n const capabilities: AgendaCapabilities = {\n title: bookingTypes.some((bt) => bt.fields.title === true),\n client: bookingTypes.some((bt) => bt.fields.client),\n professional: bookingTypes.some((bt) => bt.fields.professional),\n services: bookingTypes.some((bt) => bt.fields.services),\n location: bookingTypes.some((bt) => bt.fields.location),\n status: bookingTypes.some((bt) => bt.fields.status),\n }\n return {\n modules: {\n // Off-unless-explicit in simple mode (`?? !simple`); default-on in full.\n workingHours: options?.modules?.workingHours ?? !simple,\n confirmations: options?.modules?.confirmations ?? !simple,\n conflictDetection: options?.modules?.conflictDetection ?? !simple,\n dragAndDrop: options?.modules?.dragAndDrop !== false,\n locationSelection: options?.modules?.locationSelection === true,\n financial: options?.modules?.financial ?? !!options?.financialBridge,\n },\n simpleMode: simple,\n capabilities,\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n bookingKind: options?.bookingKind ?? 'appointment',\n orderKind: options?.orderKind ?? 'service_order',\n scheduleKind: options?.scheduleKind ?? 'working_hours',\n statuses: options?.statuses ?? DEFAULT_STATUSES,\n bookingTypes,\n businessHours: options?.businessHours ?? { startTime: '07:00', endTime: '21:00' },\n slotDuration: options?.slotDuration ?? 30,\n professionalKind: options?.professionalKind ?? 'staff',\n clientKind: options?.clientKind ?? 'customer',\n autoCreateOrder: options?.autoCreateOrder !== false,\n locations: options?.locations ?? [],\n confirmationChannels: options?.confirmationChannels ?? [],\n cancellationDetails: options?.cancellationDetails,\n onBookingCreated: options?.onBookingCreated,\n contactLookup: options?.contactLookup,\n clientEntityDef: options?.clientEntityDef,\n serviceLookup: options?.serviceLookup,\n professionalLookup: options?.professionalLookup,\n locationLookup: options?.locationLookup,\n onEntityClick: options?.onEntityClick,\n financialBridge: options?.financialBridge,\n scheduleBlockDefaults: {\n bufferMinutes: options?.scheduleBlockDefaults?.bufferMinutes ?? 0,\n maxConcurrent: options?.scheduleBlockDefaults?.maxConcurrent ?? 1,\n minAdvanceHours: options?.scheduleBlockDefaults?.minAdvanceHours ?? 0,\n maxAdvanceDays: options?.scheduleBlockDefaults?.maxAdvanceDays ?? 60,\n },\n defaultCalendarView: options?.defaultCalendarView ?? 'resourceTimeGridWeek',\n }\n}\n","import { createPluginContext } from '@fayz-ai/admin'\nimport type { ResolvedAgendaConfig } from './config'\nimport type { AgendaDataProvider } from './data/types'\nimport type { AgendaUIState } from './store'\n\nconst ctx = createPluginContext<ResolvedAgendaConfig, AgendaDataProvider, AgendaUIState>('AgendaPage')\n\nexport const AgendaContextProvider = ctx.ContextProvider\nexport const useAgendaConfig = ctx.useConfig\nexport const useAgendaProvider = ctx.useProvider\nexport const useAgendaStore = ctx.useStore\n","/**\n * Injects agenda calendar CSS at runtime.\n * This ensures styles work both in symlinked dev mode and when consumed\n * as a built package (where CSS side-effect imports are extracted by tsup\n * and not automatically loaded).\n */\n\nconst STYLE_ID = 'saas-agenda-calendar-styles'\n\nconst css = /* css */ `\n/* Dark mode content background — uses the content token */\n.dark .agenda-calendar,\n.dark .agenda-calendar .fc,\n.dark .agenda-calendar .fc-view-harness,\n.dark .agenda-calendar .fc-timegrid,\n.dark .agenda-calendar .fc-scrollgrid,\n.dark .agenda-calendar .fc-timegrid-col,\n.dark .agenda-calendar .fc-daygrid-body,\n.dark .agenda-calendar .fc-timegrid-slot-lane {\n background-color: hsl(var(--content));\n}\n\n/* FullCalendar — Google Calendar inspired theme */\n\n.agenda-calendar {\n --fc-border-color: hsl(var(--border));\n --fc-today-bg-color: transparent;\n --fc-now-indicator-color: hsl(var(--destructive));\n --fc-highlight-color: hsl(var(--primary) / 0.06);\n --fc-non-business-color: hsl(var(--muted) / 0.15);\n --fc-neutral-bg-color: transparent;\n --fc-page-bg-color: transparent;\n --fc-event-border-color: transparent;\n}\n\n.agenda-calendar .fc {\n font-family: inherit;\n background: transparent;\n}\n\n.agenda-calendar .fc .fc-view-harness {\n background: transparent;\n}\n\n/* ── Column headers ── */\n.agenda-calendar .fc-col-header-cell {\n background: transparent;\n border-bottom: 1px solid var(--fc-border-color);\n border-left: none;\n border-right: none;\n border-top: none;\n}\n\n.agenda-calendar .fc-col-header-cell-cushion {\n padding: 8px 4px;\n font-weight: 400;\n font-size: 0.7rem;\n color: hsl(var(--muted-foreground));\n text-decoration: none;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n/* Today's column header */\n.agenda-calendar .fc-day-today .fc-col-header-cell-cushion {\n color: hsl(var(--primary));\n font-weight: 600;\n}\n\n/* Resource header (professional columns) */\n.agenda-calendar .fc .fc-resource-header {\n background: transparent;\n border-bottom: 1px solid var(--fc-border-color);\n}\n\n/* ── Time slots — compact ── */\n.agenda-calendar .fc-timegrid-slot {\n height: 1.5rem;\n border-bottom: 1px solid hsl(var(--border) / 0.4);\n}\n\n.agenda-calendar .fc-timegrid-slot-label {\n vertical-align: top;\n border: none;\n}\n\n.agenda-calendar .fc-timegrid-slot-label-cushion {\n font-size: 0.65rem;\n color: hsl(var(--muted-foreground) / 0.7);\n padding: 1px 8px 0 0;\n}\n\n/* Half-hour lines lighter */\n.agenda-calendar .fc-timegrid-slot-minor {\n border-bottom-style: none;\n}\n\n/* Column dividers */\n.agenda-calendar .fc-timegrid-col {\n border-right: 1px solid hsl(var(--border) / 0.5);\n}\n\n/* ── Events ── */\n.agenda-calendar .fc-event {\n border-radius: 6px;\n border-width: 0;\n border-left: 4px solid;\n cursor: pointer;\n transition: opacity 0.15s, box-shadow 0.15s, backdrop-filter 0.15s;\n font-size: 0.7rem;\n line-height: 1.3;\n margin: 0 2px;\n overflow: hidden;\n backdrop-filter: blur(8px) saturate(140%);\n -webkit-backdrop-filter: blur(8px) saturate(140%);\n}\n\n.agenda-calendar .fc-event .fc-event-main {\n background: inherit;\n border-radius: inherit;\n overflow: hidden;\n}\n\n.agenda-calendar .fc-event:not(.fc-bg-event):hover {\n opacity: 0.92;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n backdrop-filter: blur(12px) saturate(160%);\n -webkit-backdrop-filter: blur(12px) saturate(160%);\n}\n\n.agenda-calendar .fc-bg-event {\n pointer-events: none;\n}\n\n/* ── Now indicator ── */\n.agenda-calendar .fc-timegrid-now-indicator-line {\n border-color: hsl(var(--destructive));\n border-width: 2px;\n}\n\n.agenda-calendar .fc-timegrid-now-indicator-arrow {\n border-top-color: hsl(var(--destructive));\n}\n\n/* ── Month view ── */\n.agenda-calendar .fc-daygrid-day-number {\n font-size: 0.8rem;\n padding: 4px 8px;\n text-decoration: none;\n color: hsl(var(--foreground));\n}\n\n.agenda-calendar .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {\n background-color: hsl(var(--primary));\n color: hsl(var(--primary-foreground));\n border-radius: 50%;\n width: 1.5rem;\n height: 1.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n}\n\n/* ── Selection ── */\n.agenda-calendar .fc-highlight {\n background: hsl(var(--primary) / 0.08);\n}\n\n/* ── Links ── */\n.agenda-calendar .fc a {\n text-decoration: none;\n color: inherit;\n}\n\n/* ── Scrollbar ── */\n.agenda-calendar .fc-scroller {\n scrollbar-width: thin;\n scrollbar-color: hsl(var(--muted-foreground) / 0.12) transparent;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar {\n width: 6px;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar-thumb {\n background: hsl(var(--muted-foreground) / 0.12);\n border-radius: 3px;\n}\n\n/* ── Clean up borders ── */\n.agenda-calendar .fc .fc-timegrid {\n border: none;\n}\n\n.agenda-calendar .fc-scrollgrid {\n border: none !important;\n}\n\n.agenda-calendar .fc-scrollgrid td:last-child {\n border-right: none;\n}\n\n/* ── Unavailable time background — opaque/disabled feel ── */\n.agenda-calendar .fc-unavailable-bg {\n background: hsl(var(--muted-foreground) / 0.08) !important;\n background-image: repeating-linear-gradient(\n 45deg,\n transparent,\n transparent 4px,\n hsl(var(--muted-foreground) / 0.04) 4px,\n hsl(var(--muted-foreground) / 0.04) 8px\n ) !important;\n border-radius: 0;\n border-left: none !important;\n}\n\n/* ── Location label on schedule blocks ── */\n.agenda-calendar .fc-location-label {\n background: transparent !important;\n border: none !important;\n border-left-width: 0 !important;\n cursor: default !important;\n pointer-events: none;\n box-shadow: none !important;\n z-index: 1 !important;\n margin: 0 4px !important;\n font-weight: 500 !important;\n}\n\n.agenda-calendar .fc-location-label .fc-event-main {\n padding: 0 !important;\n}\n\n/* Week view day header with date */\n.agenda-calendar .fc-timegrid .fc-col-header-cell {\n padding: 4px 0;\n}\n\n/* ── Alternating resource column backgrounds ── */\n.agenda-calendar .fc-resource-alt {\n background-color: hsl(var(--muted) / 0.4) !important;\n}\n\n.dark .agenda-calendar .fc-resource-alt {\n background-color: hsl(var(--muted-foreground) / 0.08) !important;\n}\n\n/* Resource group header separator — stronger border between professionals */\n.agenda-calendar .fc-resource-group {\n border-left: 2px solid hsl(var(--border));\n}\n\n/* Also stripe the resource header label for the alt group */\n.agenda-calendar th.fc-resource-alt {\n background-color: hsl(var(--muted) / 0.4) !important;\n}\n\n.dark .agenda-calendar th.fc-resource-alt {\n background-color: hsl(var(--muted-foreground) / 0.06) !important;\n}\n`\n\nlet injected = false\n\nexport function injectCalendarStyles(): void {\n if (injected) return\n if (typeof document === 'undefined') return\n\n // Check if already present (e.g. from CSS import in dev mode)\n if (document.getElementById(STYLE_ID)) {\n injected = true\n return\n }\n\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = css\n document.head.appendChild(style)\n injected = true\n}\n","import { usePluginPrefs } from '@fayz-ai/admin'\n\nconst DEFAULTS = {\n startTime: '07:00',\n endTime: '21:00',\n}\n\nexport function useAgendaSettings() {\n const prefs = usePluginPrefs('agenda', DEFAULTS)\n\n return {\n startTime: prefs.get('startTime'),\n endTime: prefs.get('endTime'),\n setStartTime: (v: string) => prefs.set('startTime', v),\n setEndTime: (v: string) => prefs.set('endTime', v),\n }\n}\n","import React, { useMemo } from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\nimport { getCurrentLocale } from '@fayz-ai/core'\n\ninterface MiniCalendarProps {\n selectedDate: Date\n onDateSelect: (date: Date) => void\n onMonthChange?: (date: Date) => void\n}\n\nconst DAY_LABELS: Record<string, string[]> = {\n en: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],\n 'pt-BR': ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'],\n}\n\nfunction isSameDay(a: Date, b: Date) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()\n}\n\nfunction isToday(d: Date) {\n return isSameDay(d, new Date())\n}\n\nfunction toDateLocale(locale: string): string {\n if (locale === 'pt-BR') return 'pt-BR'\n return 'en-US'\n}\n\nexport function MiniCalendar({ selectedDate, onDateSelect, onMonthChange }: MiniCalendarProps) {\n const locale = getCurrentLocale()\n const [viewMonth, setViewMonth] = React.useState(() => new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1))\n\n const monthLabel = viewMonth.toLocaleDateString(toDateLocale(locale), { month: 'long', year: 'numeric' })\n const dayLabels = DAY_LABELS[locale] ?? DAY_LABELS.en\n\n const weeks = useMemo(() => {\n const year = viewMonth.getFullYear()\n const month = viewMonth.getMonth()\n const firstDay = new Date(year, month, 1)\n const startOffset = firstDay.getDay()\n const daysInMonth = new Date(year, month + 1, 0).getDate()\n\n const cells: (Date | null)[] = []\n for (let i = 0; i < startOffset; i++) cells.push(null)\n for (let d = 1; d <= daysInMonth; d++) cells.push(new Date(year, month, d))\n while (cells.length % 7 !== 0) cells.push(null)\n\n const rows: (Date | null)[][] = []\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7))\n return rows\n }, [viewMonth])\n\n function prevMonth() {\n const d = new Date(viewMonth.getFullYear(), viewMonth.getMonth() - 1, 1)\n setViewMonth(d)\n onMonthChange?.(d)\n }\n\n function nextMonth() {\n const d = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + 1, 1)\n setViewMonth(d)\n onMonthChange?.(d)\n }\n\n function handleClick(date: Date) {\n onDateSelect(date)\n }\n\n return (\n <div className=\"select-none\">\n {/* Month header */}\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm font-medium capitalize\">{monthLabel}</span>\n <div className=\"flex items-center gap-0.5\">\n <button onClick={prevMonth} className=\"flex h-6 w-6 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronLeft className=\"h-3.5 w-3.5\" />\n </button>\n <button onClick={nextMonth} className=\"flex h-6 w-6 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n\n {/* Day labels */}\n <div className=\"grid grid-cols-7 mb-0.5\">\n {dayLabels.map((label, i) => (\n <div key={i} className=\"flex h-6 w-6 items-center justify-center text-[10px] font-medium text-muted-foreground mx-auto\">\n {label}\n </div>\n ))}\n </div>\n\n {/* Dates */}\n {weeks.map((week, wi) => (\n <div key={wi} className=\"grid grid-cols-7\">\n {week.map((date, di) => {\n if (!date) return <div key={di} className=\"h-6 w-6 mx-auto\" />\n const selected = isSameDay(date, selectedDate)\n const today = isToday(date)\n return (\n <button\n key={di}\n onClick={() => handleClick(date)}\n className={`flex h-6 w-6 items-center justify-center rounded-full text-[11px] mx-auto transition-colors ${\n selected\n ? 'bg-primary text-primary-foreground'\n : today\n ? 'bg-primary/10 text-primary font-semibold'\n : 'hover:bg-muted text-foreground'\n }`}\n >\n {date.getDate()}\n </button>\n )\n })}\n </div>\n ))}\n </div>\n )\n}\n","import React, { useState, useEffect } from 'react'\nimport { createPortal } from 'react-dom'\nimport { X, Check, Banknote, QrCode, CreditCard, ArrowRightLeft, FileCheck, ExternalLink } from 'lucide-react'\nimport { useAgendaConfig } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { BookingPaymentDetail } from '../bridges/financial-bridge'\n\n// ---------------------------------------------------------------------------\n// Payment method type visuals (mirrors financial PaymentModal)\n// ---------------------------------------------------------------------------\n\nconst TYPE_ICONS: Record<string, React.ElementType> = {\n cash: Banknote, pix: QrCode, credit_card: CreditCard, debit_card: CreditCard,\n bank_transfer: ArrowRightLeft, check: FileCheck,\n}\n\nconst TYPE_COLORS: Record<string, string> = {\n cash: 'border-success/30 bg-success/5 hover:bg-success/10 data-[active=true]:border-success data-[active=true]:bg-success/15',\n pix: 'border-teal-500/30 bg-teal-500/5 hover:bg-teal-500/10 data-[active=true]:border-teal-500 data-[active=true]:bg-teal-500/15',\n credit_card: 'border-info/30 bg-info/5 hover:bg-info/10 data-[active=true]:border-info data-[active=true]:bg-info/15',\n debit_card: 'border-magic/30 bg-magic/5 hover:bg-magic/10 data-[active=true]:border-magic data-[active=true]:bg-magic/15',\n bank_transfer: 'border-warning/30 bg-warning/5 hover:bg-warning/10 data-[active=true]:border-warning data-[active=true]:bg-warning/15',\n check: 'border-input/30 bg-muted/5 hover:bg-muted/10 data-[active=true]:border-input data-[active=true]:bg-muted/15',\n}\n\nconst ICON_COLORS: Record<string, string> = {\n cash: 'text-success', pix: 'text-teal-500', credit_card: 'text-info',\n debit_card: 'text-magic', bank_transfer: 'text-warning', check: 'text-muted-foreground',\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\ninterface Props {\n orderId: string\n orderTotal: number\n services?: Array<{ name: string; price: number; durationMinutes: number }>\n onClose: () => void\n onPaymentChange?: () => void\n formatCurrency: (amount: number) => string\n /** Render inline (no portal overlay) — for embedding in tabs */\n inline?: boolean\n}\n\nexport function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPaymentChange, formatCurrency, inline }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const bridge = config.financialBridge!\n\n const [visible, setVisible] = useState(false)\n const [loading, setLoading] = useState(true)\n const [detail, setDetail] = useState<BookingPaymentDetail | null>(null)\n\n // Payment form\n const [selectedTypeId, setSelectedTypeId] = useState('')\n const [paymentTypes, setPaymentTypes] = useState<Array<{ id: string; name: string; transactionType?: string }>>([])\n const [bankAccounts, setBankAccounts] = useState<Array<{ id: string; name: string; accountType: string }>>([])\n const [filteredMethods, setFilteredMethods] = useState<Array<{ id: string; name: string }>>([])\n const [selectedBankId, setSelectedBankId] = useState('')\n const [paymentMethodId, setPaymentMethodId] = useState('')\n const [cardBrand, setCardBrand] = useState('')\n const [cardInstallments, setCardInstallments] = useState(1)\n const [processing, setProcessing] = useState(false)\n const [justPaid, setJustPaid] = useState(false)\n\n useEffect(() => { requestAnimationFrame(() => setVisible(true)) }, [])\n\n // Single combined fetch for all initial data\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n Promise.all([\n bridge.getPaymentDetail(orderId).catch(() => null),\n bridge.getPaymentMethodTypes().catch(() => [] as typeof paymentTypes),\n bridge.getBankAccounts().catch(() => [] as typeof bankAccounts),\n ]).then(([d, types, accounts]) => {\n if (cancelled) return\n setDetail(d)\n setPaymentTypes(types)\n setBankAccounts(accounts)\n setLoading(false)\n })\n return () => { cancelled = true }\n }, [orderId])\n\n function handleClose() {\n setVisible(false)\n setTimeout(onClose, 200)\n }\n\n const selectedType = paymentTypes.find((t) => t.id === selectedTypeId)\n const txType = selectedType?.transactionType ?? ''\n const needsBank = ['bank_transfer', 'pix', 'check'].includes(txType)\n const needsCard = txType === 'credit_card' || txType === 'debit_card'\n const needsCardInstallments = txType === 'credit_card'\n\n function handleSelectType(typeId: string) {\n setSelectedTypeId(typeId)\n setSelectedBankId('')\n setPaymentMethodId('')\n setCardBrand('')\n setCardInstallments(1)\n // Fetch specific payment methods for this type\n if (bridge.getPaymentMethods) {\n bridge.getPaymentMethods(typeId).then(setFilteredMethods).catch(() => setFilteredMethods([]))\n }\n }\n\n async function handleCheckout() {\n if (!selectedTypeId) return\n setProcessing(true)\n try {\n const result = await bridge.checkout(orderId, {\n paymentMethodTypeId: selectedTypeId,\n paymentMethodId: paymentMethodId || undefined,\n bankAccountId: needsBank ? selectedBankId || undefined : undefined,\n cardBrand: needsCard ? cardBrand || undefined : undefined,\n cardInstallments: needsCardInstallments ? cardInstallments : undefined,\n })\n setDetail(result)\n setJustPaid(true)\n onPaymentChange?.()\n // Show confirmation animation, then transition to summary\n setTimeout(() => setJustPaid(false), 2200)\n } catch { /* toast */ }\n setProcessing(false)\n }\n\n const isPaid = detail?.status === 'paid'\n\n const content = (\n <div className=\"px-5 py-4 space-y-4\">\n\n {/* Loading */}\n {loading && (\n <div className=\"space-y-3 py-2\">\n {[...Array(3)].map((_, i) => (\n <div key={i} className=\"h-8 rounded-lg bg-muted animate-pulse\" />\n ))}\n </div>\n )}\n\n {/* Just paid — confirmation animation */}\n {!loading && isPaid && justPaid && (\n <div className=\"text-center py-8 space-y-2 animate-in fade-in zoom-in-95 duration-300\">\n <div className=\"flex h-14 w-14 mx-auto items-center justify-center rounded-full bg-success/10 animate-bounce\" style={{ animationDuration: '600ms', animationIterationCount: '2' }}>\n <Check className=\"h-7 w-7 text-success\" />\n </div>\n <p className=\"text-sm font-semibold text-success\">{t('agenda.payment.checkoutComplete')}</p>\n <p className=\"text-xs text-muted-foreground\">{formatCurrency(detail!.totalAmount)}</p>\n </div>\n )}\n\n {/* Invoice summary — shown after animation or when returning to an already-paid/pending booking */}\n {!loading && detail && detail.status !== 'none' && !justPaid && (\n <div className=\"space-y-3 animate-in fade-in duration-300\">\n {/* Movement rows with inline status badge */}\n {detail.movements.length > 0 ? (\n <div className=\"space-y-1.5\">\n {detail.movements.map((mov) => {\n const methodName = mov.paymentMethodTypeName\n const txKey = (methodName ?? '').toLowerCase().replace(/\\s+/g, '_')\n const Icon = TYPE_ICONS[txKey] ?? Banknote\n const iconColor = ICON_COLORS[txKey] ?? 'text-muted-foreground'\n const isMovPaid = mov.status === 'paid'\n const isPartial = mov.status === 'partial'\n const isOverdue = mov.status === 'overdue'\n\n return (\n <div key={mov.id} className=\"flex items-center gap-3 rounded-lg border px-3 py-2.5\">\n <Icon className={`h-4 w-4 shrink-0 ${isMovPaid ? iconColor : 'text-muted-foreground'}`} />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">\n {methodName ?? '—'}\n {mov.cardBrand ? ` · ${mov.cardBrand}` : ''}\n {mov.cardInstallments && mov.cardInstallments > 1 ? ` ${mov.cardInstallments}x` : ''}\n </p>\n <p className=\"text-[10px] text-muted-foreground\">\n {mov.paymentDate ?? mov.dueDate}\n {detail.movements.length > 1 && mov.installmentNumber ? ` · ${t('agenda.payment.installment')} ${mov.installmentNumber}` : ''}\n </p>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {isMovPaid && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-[10px] font-medium text-success\">\n <Check className=\"h-2.5 w-2.5\" /> {t('agenda.payment.paid')}\n </span>\n )}\n {isPartial && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-warning/10 px-2 py-0.5 text-[10px] font-medium text-warning\">\n ! {formatCurrency(mov.paidAmount)}/{formatCurrency(mov.amount)}\n </span>\n )}\n {isOverdue && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-destructive/10 px-2 py-0.5 text-[10px] font-medium text-destructive\">\n ! {t('agenda.payment.overdue')}\n </span>\n )}\n {mov.status === 'pending' && (\n <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground\">\n {t('agenda.payment.pending')}\n </span>\n )}\n <span className=\"text-sm font-semibold\">{formatCurrency(mov.paidAmount || mov.amount)}</span>\n </div>\n </div>\n )\n })}\n </div>\n ) : (\n <div className=\"flex items-center justify-between text-sm px-1\">\n <span className=\"text-muted-foreground\">{t('agenda.payment.total')}</span>\n <span className=\"font-semibold\">{formatCurrency(detail.totalAmount)}</span>\n </div>\n )}\n\n {/* Invoice ref + link */}\n <div className=\"flex items-center justify-between\">\n {detail.referenceNumber && (\n <span className=\"text-[10px] font-mono text-muted-foreground\">#{detail.referenceNumber}</span>\n )}\n <a\n href={`#/financial/receivables/detail/${detail.invoiceId}`}\n className=\"inline-flex items-center gap-1.5 text-xs font-medium text-primary hover:underline ml-auto\"\n >\n {t('agenda.payment.viewInvoice')}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n </div>\n )}\n\n {/* Checkout view — only when no invoice exists yet */}\n {!loading && (!detail || detail.movements.length === 0) && (\n <>\n {/* Service summary */}\n {services && services.length > 0 && (\n <div>\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.payment.serviceSummary')}</p>\n <div className=\"space-y-0.5\">\n {services.map((svc, i) => (\n <div key={i} className=\"flex items-center justify-between text-sm py-1\">\n <span className=\"truncate\">{svc.name}</span>\n <span className=\"shrink-0 text-muted-foreground\">{formatCurrency(svc.price)}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Total */}\n <div className=\"flex items-center justify-between text-sm font-semibold pt-2 border-t\">\n <span>{t('agenda.payment.total')}</span>\n <span>{formatCurrency(orderTotal)}</span>\n </div>\n\n {/* Payment method grid */}\n <div>\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.payment.paymentMethod')}</p>\n {paymentTypes.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-input bg-muted/30 px-3 py-3 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('agenda.payment.noMethods')}</p>\n <a href=\"#/financial/settings\" className=\"mt-1.5 inline-block text-xs font-medium text-primary hover:underline\">\n {t('agenda.payment.configureMethods')} →\n </a>\n </div>\n ) : (\n <div className=\"grid grid-cols-3 gap-1.5\">\n {paymentTypes.map((pt) => {\n const ptTx = pt.transactionType ?? pt.name.toLowerCase().replace(/\\s+/g, '_')\n const Icon = TYPE_ICONS[ptTx] ?? Banknote\n const colorClass = TYPE_COLORS[ptTx] ?? TYPE_COLORS.cash\n const iconColor = ICON_COLORS[ptTx] ?? ICON_COLORS.cash\n const isActive = selectedTypeId === pt.id\n return (\n <button\n key={pt.id}\n type=\"button\"\n data-active={isActive}\n onClick={() => handleSelectType(pt.id)}\n className={`flex flex-col items-center gap-1 rounded-lg border p-2.5 text-[10px] font-medium transition-all ${colorClass}`}\n >\n <Icon className={`h-4 w-4 ${iconColor}`} />\n <span className=\"truncate w-full text-center\">{pt.name}</span>\n </button>\n )\n })}\n </div>\n )}\n </div>\n\n {/* Extra fields based on payment type */}\n {selectedTypeId && (\n <div className=\"space-y-3\">\n {/* Specific payment method (filtered by type) */}\n {filteredMethods.length > 0 && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">\n {needsCard ? t('agenda.payment.card') : t('agenda.payment.method')}\n </label>\n <select value={paymentMethodId} onChange={(e) => setPaymentMethodId(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.select')}</option>\n {filteredMethods.map((m) => <option key={m.id} value={m.id}>{m.name}</option>)}\n </select>\n </div>\n )}\n\n {/* Card brand + installments */}\n {needsCard && (\n <div className={`grid gap-2.5 ${needsCardInstallments ? 'grid-cols-2' : 'grid-cols-1'}`}>\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.cardBrand')}</label>\n <select value={cardBrand} onChange={(e) => setCardBrand(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.selectBrand')}</option>\n {['Visa', 'Mastercard', 'American Express', 'Elo', 'Hipercard', 'Diners Club'].map((b) => (\n <option key={b} value={b}>{b}</option>\n ))}\n </select>\n </div>\n {needsCardInstallments && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.cardInstallments')}</label>\n <select value={cardInstallments} onChange={(e) => setCardInstallments(Number(e.target.value))}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n {Array.from({ length: 12 }, (_, i) => i + 1).map((n) => (\n <option key={n} value={n}>{n}x {n > 1 ? formatCurrency(orderTotal / n) : ''}</option>\n ))}\n </select>\n </div>\n )}\n </div>\n )}\n\n {/* Bank account */}\n {needsBank && bankAccounts.length > 0 && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.bankAccount')}</label>\n <select value={selectedBankId} onChange={(e) => setSelectedBankId(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.selectAccount')}</option>\n {bankAccounts.map((a) => (\n <option key={a.id} value={a.id}>{a.name}</option>\n ))}\n </select>\n </div>\n )}\n </div>\n )}\n\n {/* Confirm button */}\n <button\n type=\"button\"\n onClick={handleCheckout}\n disabled={processing || !selectedTypeId}\n className=\"w-full rounded-lg bg-primary border border-primary py-2.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\"\n >\n {processing\n ? t('agenda.payment.checkingOut')\n : `${t('agenda.payment.checkout')} ${formatCurrency(orderTotal)}`\n }\n </button>\n </>\n )}\n </div>\n )\n\n if (inline) return content\n\n return createPortal(\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center transition-colors duration-200\"\n style={{ backgroundColor: visible ? 'rgba(0,0,0,0.5)' : 'rgba(0,0,0,0)' }}\n onClick={handleClose}\n >\n <div\n className=\"w-full max-w-md rounded-modal border bg-card shadow-2xl mx-4 transition-all duration-200 max-h-[90vh] overflow-y-auto\"\n style={{ opacity: visible ? 1 : 0, transform: visible ? 'scale(1) translateY(0)' : 'scale(0.95) translateY(8px)' }}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between px-5 py-4 border-b sticky top-0 bg-card z-10\">\n <h3 className=\"text-base font-semibold\">{t('agenda.payment.title')}</h3>\n <button onClick={handleClose} className=\"p-1 text-muted-foreground hover:text-foreground transition-colors\">\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n {content}\n </div>\n </div>,\n document.body,\n )\n}\n","// ---------------------------------------------------------------------------\n// Agenda Plugin — Pure TypeScript types\n// Zero dependencies. Maps to public archetype tables.\n// ---------------------------------------------------------------------------\n\n// ============================================================\n// ENUMS / LITERALS\n// ============================================================\n\n/** Booking status lifecycle */\nexport type BookingStatus =\n | 'scheduled'\n | 'confirmed'\n | 'in_progress'\n | 'completed'\n | 'cancelled'\n | 'no_show'\n\n/** Confirmation outreach status */\nexport type ConfirmationStatus = 'pending' | 'sent' | 'confirmed' | 'declined'\n\n/** Booking type identifier — extensible via string literal union */\nexport type BookingTypeId = 'appointment' | 'task' | 'out_of_office' | 'block' | (string & {})\n\n/** Configuration for a booking type (event type) */\nexport interface BookingTypeConfig {\n id: BookingTypeId\n label: string\n icon: string\n color: string\n fields: {\n /** Free-text event title (maps to the booking's display name). Used by\n * simple / Google-Calendar-style events that have no client party. */\n title?: boolean\n client: boolean\n professional: boolean\n services: boolean\n location: boolean\n status: boolean\n }\n requiresServices: boolean\n requiresClient: boolean\n}\n\n// ============================================================\n// CORE ENTITIES\n// ============================================================\n\n/** A booking service line item (from public.appointment_items) */\nexport interface BookingService {\n id: string\n serviceId: string | null\n name: string\n durationMinutes: number\n price: number\n assigneeId: string | null\n}\n\n/** Calendar booking — the main entity rendered on the calendar (from v_appointments view on orders) */\nexport interface CalendarBooking {\n id: string\n tenantId: string\n kind: string\n /** Lifecycle stage: booked, invoiced, paid, etc. */\n stage?: string\n /** Financial direction: credit, debit, null */\n direction?: string | null\n startsAt: string\n endsAt: string | null\n status: BookingStatus\n notes: string | null\n /** In unified model, orderId === id (the booking IS the order) */\n orderId: string | null\n locationId: string | null\n metadata: Record<string, unknown>\n\n // Client (party)\n clientId: string | null\n clientName: string | null\n clientPhone: string | null\n clientEmail: string | null\n clientAvatarUrl: string | null\n\n // Professional (assignee)\n professionalId: string | null\n professionalName: string | null\n professionalAvatarUrl: string | null\n\n // Location\n locationName: string | null\n\n // Order totals\n orderTotal: number | null\n orderStatus: string | null\n /** Payment status from financial bridge (enriched at runtime) */\n paymentStatus?: import('./bridges/financial-bridge').BookingPaymentStatus\n\n // Aggregated services\n services: BookingService[] | null\n totalDurationMinutes: number | null\n\n createdAt: string\n updatedAt: string\n}\n\n/** Professional / staff resource for the calendar */\nexport interface Professional {\n id: string\n name: string\n avatarUrl: string | null\n locationId: string | null\n locationName: string | null\n isActive: boolean\n}\n\n/** Working hours schedule (from public.schedules) */\nexport interface Schedule {\n id: string\n tenantId: string\n kind: string\n assigneeId: string | null\n locationId: string | null\n dayOfWeek: number | null\n specificDate: string | null\n startsAt: string\n endsAt: string\n isActive: boolean\n metadata: Record<string, unknown>\n}\n\n/** Available time slot */\nexport interface TimeSlot {\n start: string\n end: string\n}\n\n/** Confirmation record stored in booking metadata */\nexport interface ConfirmationRecord {\n channel: string\n sentAt: string\n status: ConfirmationStatus\n confirmedAt?: string\n}\n\n// ============================================================\n// STATUS CONFIGURATION\n// ============================================================\n\n/**\n * When a status is available for selection relative to the booking date.\n * - 'always' — any date (e.g. scheduled, confirmed, cancelled)\n * - 'today_or_past' — booking is today or earlier (e.g. completed, no_show)\n * - 'today_only' — booking is today (e.g. in_progress)\n */\nexport type StatusAvailability = 'always' | 'today_or_past' | 'today_only'\n\nexport interface StatusConfig {\n value: string\n label: string\n color: string\n /** When this status can be selected (default: 'always') */\n availableWhen?: StatusAvailability\n}\n\n/** Check if a status is available for a given booking date */\nexport function isStatusAvailable(status: StatusConfig, bookingStartsAt: string): boolean {\n const when = status.availableWhen ?? 'always'\n if (when === 'always') return true\n const bookingDate = bookingStartsAt.slice(0, 10)\n const today = new Date().toISOString().slice(0, 10)\n if (when === 'today_or_past') return bookingDate <= today\n if (when === 'today_only') return bookingDate === today\n return true\n}\n\n// ============================================================\n// MODAL TAB EXTENSION\n// ============================================================\n\n/** Props passed to every booking modal tab component */\nexport interface BookingModalTabProps {\n bookingId?: string\n clientId: string\n orderId: string | null\n services: Array<{ name: string; price: number; durationMinutes: number }>\n formatCurrency: (amount: number) => string\n onDataChange?: () => void\n}\n\n/** A tab registered in the booking edit modal */\nexport interface BookingModalTab {\n id: string\n label: string\n icon: string\n order: number\n component: React.ComponentType<BookingModalTabProps>\n visible?: (ctx: { mode: 'create' | 'edit'; clientId?: string; orderId?: string }) => boolean\n}\n\n// ============================================================\n// INPUT TYPES (create / mutate)\n// ============================================================\n\nexport interface CreateBookingInput {\n kind?: BookingTypeId\n clientId: string\n professionalId: string\n locationId?: string\n startsAt: string\n notes?: string\n /** Free-text event title for simple events (no client party). Maps to the\n * booking's display name (clientName in the read model). */\n title?: string\n services: CreateBookingServiceInput[]\n}\n\nexport interface CreateBookingServiceInput {\n serviceId: string\n name: string\n durationMinutes: number\n price: number\n assigneeId?: string\n}\n\nexport interface UpdateBookingInput {\n clientId?: string\n professionalId?: string\n locationId?: string\n startsAt?: string\n endsAt?: string\n status?: BookingStatus\n notes?: string\n /** Free-text event title for simple events (no client party). */\n title?: string\n services?: CreateBookingServiceInput[]\n}\n\nexport interface SaveScheduleInput {\n assigneeId: string\n locationId?: string\n dayOfWeek?: number\n specificDate?: string\n startsAt: string\n endsAt: string\n isActive?: boolean\n metadata?: Record<string, unknown>\n}\n\n// ============================================================\n// QUERY / FILTER TYPES\n// ============================================================\n\nexport interface BookingQuery {\n dateRange: { start: string; end: string }\n professionalIds?: string[]\n locationId?: string\n statuses?: string[]\n kind?: string\n}\n\nexport interface ConflictCheckParams {\n assigneeId: string\n startsAt: string\n endsAt: string\n excludeBookingId?: string\n}\n\nexport interface AvailableSlotsParams {\n assigneeId: string\n date: string\n durationMinutes: number\n slotInterval?: number\n}\n","import React, { useState, useEffect, useMemo, useRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Clock, AlertTriangle, X, User, Briefcase, FileText, CircleDot, Plus, MapPin, Calendar, DollarSign, CheckSquare, Ban, Check, HandCoins } from 'lucide-react'\n\nconst BOOKING_TYPE_ICONS: Record<string, React.ElementType> = {\n Calendar, CheckSquare, Ban,\n}\nimport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@fayz-ai/ui'\nimport { cn } from '@fayz-ai/ui'\nimport { SearchCombobox, type ComboboxOption } from '@fayz-ai/ui'\nimport { ContactPicker, RightRailPage } from '@fayz-ai/admin'\nimport { BookingPaymentPanel } from './BookingPaymentPanel'\nimport { CrudDetailPage } from '@fayz-ai/admin'\nimport { CrudFormPage } from '@fayz-ai/admin'\nimport { useLimitGuard, invalidateLimit, useLookupCreate } from '@fayz-ai/admin'\nimport { Button } from '@fayz-ai/ui'\nimport { useAgendaConfig, useAgendaProvider, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { getCurrentLocale } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CreateBookingInput, BookingTypeId } from '../types'\nimport type { ExternalBookingSource } from '../config'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtCurrency(amount: number, locale: string, code: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(amount)\n}\n\nfunction formatCompactDate(dateStr: string, locale: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n return d.toLocaleDateString(locale === 'pt-BR' ? 'pt-BR' : 'en-US', {\n weekday: 'short', month: 'short', day: 'numeric',\n })\n}\n\ninterface ServiceItem { serviceId: string; name: string; durationMinutes: number; price: number }\ninterface CancellationReasonItem { id: string; label: string; requiresNotes?: boolean }\n\n// ---------------------------------------------------------------------------\n// Inline editable number — allows clearing, commits on blur/enter\n// ---------------------------------------------------------------------------\n\nfunction InlineNumber({ value, onChange, min = 0, step = 1, className, disabled, tooltip }: {\n value: number; onChange: (v: number) => void; min?: number; step?: number\n className?: string; disabled?: boolean; tooltip?: string\n}) {\n const [draft, setDraft] = useState(String(value))\n const [focused, setFocused] = useState(false)\n\n useEffect(() => { if (!focused) setDraft(String(value)) }, [value, focused])\n\n function commit() {\n setFocused(false)\n const v = parseFloat(draft)\n if (!isNaN(v) && v >= min) {\n onChange(v)\n } else {\n setDraft(String(value))\n }\n }\n\n const input = (\n <input\n type=\"text\"\n inputMode=\"decimal\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onFocus={(e) => { setFocused(true); e.target.select() }}\n onBlur={commit}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); commit() } }}\n disabled={disabled}\n className={cn(\n 'text-right text-[11px] text-muted-foreground bg-transparent border-b border-transparent hover:border-muted-foreground/40 focus:border-foreground focus:outline-none tabular-nums',\n className,\n )}\n />\n )\n\n if (!tooltip) return input\n\n return (\n <TooltipProvider delayDuration={400}>\n <Tooltip>\n <TooltipTrigger asChild>{input}</TooltipTrigger>\n <TooltipContent side=\"top\" className=\"text-xs\">{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Custom Status Select\n// ---------------------------------------------------------------------------\n\nfunction StatusSelect({ value, onChange, statuses, bookingDate }: {\n value: string; onChange: (v: string) => void\n statuses: Array<{ value: string; label: string; color: string; availableWhen?: string }>\n bookingDate?: string\n}) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const dropdownRef = useRef<HTMLDivElement>(null)\n const current = statuses.find((s) => s.value === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n const target = e.target as Node\n if (ref.current?.contains(target)) return\n if (dropdownRef.current?.contains(target)) return\n setOpen(false)\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const btnRef = useRef<HTMLButtonElement>(null)\n const [dropRect, setDropRect] = useState<DOMRect | null>(null)\n\n function handleOpen() {\n if (btnRef.current) setDropRect(btnRef.current.getBoundingClientRect())\n setOpen((p) => !p)\n }\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button ref={btnRef} type=\"button\" onClick={handleOpen}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left w-full\">\n {current && <>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: current.color }} />\n <span>{current.label}</span>\n </>}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && dropRect && createPortal(\n <div ref={dropdownRef} data-modal-passthrough style={{ position: 'fixed', left: dropRect.left, top: dropRect.bottom + 4, width: dropRect.width, zIndex: 9999, pointerEvents: 'auto' }}\n className=\"fayz-glass-surface rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100\">\n {statuses.map((s: any) => {\n const available = !bookingDate || isStatusAvailable(s as any, bookingDate)\n return (\n <button key={s.value} type=\"button\" disabled={!available}\n onClick={() => { if (available) { onChange(s.value); setOpen(false) } }}\n className={`flex w-full items-center gap-2.5 px-3 py-1.5 text-sm transition-colors ${\n !available ? 'opacity-30 cursor-not-allowed' : s.value === value ? 'bg-muted/30' : 'hover:bg-muted/50'\n }`}>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: s.color }} />\n <span>{s.label}</span>\n </button>\n )\n })}\n </div>,\n document.body,\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Professional Select — compact inline dropdown with initials\n// ---------------------------------------------------------------------------\n\nfunction ProfessionalSelect({ value, onChange, professionals }: {\n value: string; onChange: (v: string) => void\n professionals: Array<{ id: string; name: string }>\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = professionals.find((p) => p.id === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left\">\n {current ? (\n <span>{current.name}</span>\n ) : (\n <span className=\"text-muted-foreground\">{t('agenda.appointment.selectProfessional')}</span>\n )}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 right-0 z-50 mt-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100\">\n {professionals.map((p: any) => (\n <button key={p.id} type=\"button\"\n onClick={() => { onChange(p.id); setOpen(false) }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50 transition-colors ${p.id === value ? 'bg-muted/30' : ''}`}>\n <span>{p.name}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Location Select — compact inline dropdown\n// ---------------------------------------------------------------------------\n\nfunction LocationSelect({ value, onChange, locations }: {\n value: string; onChange: (v: string) => void\n locations: Array<{ id: string; name: string }>\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = locations.find((l) => l.id === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left\">\n {current ? (\n <span>{current.name}</span>\n ) : (\n <span className=\"text-muted-foreground\">{t('agenda.appointment.selectLocation')}</span>\n )}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 right-0 z-50 mt-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100 max-h-48 overflow-y-auto\">\n {locations.map((l: any) => (\n <button key={l.id} type=\"button\"\n onClick={() => { onChange(l.id); setOpen(false) }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50 transition-colors ${l.id === value ? 'bg-muted/30' : ''}`}>\n <span>{l.name}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Appointment Modal — Google Calendar-inspired compact layout\n// ---------------------------------------------------------------------------\n\ninterface Props {\n open: boolean\n mode: 'create' | 'edit'\n bookingId?: string\n prefill?: Partial<CreateBookingInput> & { endsAt?: string }\n initialTab?: string\n externalSource?: ExternalBookingSource\n onClose: () => void\n onCreated?: (bookingId: string, source?: ExternalBookingSource) => void\n}\n\nexport function AppointmentModal({ open, mode, bookingId, prefill, initialTab, externalSource, onClose, onCreated }: Props) {\n const t = useTranslation()\n const locale = getCurrentLocale()\n const config = useAgendaConfig()\n const provider = useAgendaProvider()\n const initialSnapshot = useRef<string>('')\n const createBooking = useAgendaStore((s) => s.createBooking)\n const guardBookings = useLimitGuard('bookings_month')\n const updateBooking = useAgendaStore((s) => s.updateBooking)\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const fetchBookings = useAgendaStore((s) => s.fetchBookings)\n const agendaDateRange = useAgendaStore((s) => s.dateRange)\n const professionals = useAgendaStore((s) => s.professionals)\n const storeLocations = useAgendaStore((s) => s.locations)\n\n // --- State ---\n // Default to the first configured booking type (e.g. 'event' in simple mode,\n // 'appointment' otherwise) so single-type agendas resolve their type cleanly.\n const defaultBookingType = (config.bookingTypes[0]?.id ?? 'appointment') as BookingTypeId\n const [loading, setLoading] = useState(mode === 'edit')\n const [bookingType, setBookingType] = useState<BookingTypeId>(prefill?.kind ?? defaultBookingType)\n const [title, setTitle] = useState('')\n const [clientId, setClientId] = useState(prefill?.clientId ?? '')\n const [clientSearch, setClientSearch] = useState('')\n const [clientPhone, setClientPhone] = useState('')\n const [professionalId, setProfessionalId] = useState(prefill?.professionalId ?? '')\n const [locationId, setLocationId] = useState(prefill?.locationId ?? '')\n const [services, setServices] = useState<ServiceItem[]>([])\n const [serviceSearch, setServiceSearch] = useState('')\n const [date, setDate] = useState(() => {\n if (prefill?.startsAt) return prefill.startsAt.slice(0, 10)\n return new Date().toISOString().slice(0, 10)\n })\n const [startTime, setStartTime] = useState(() => {\n if (prefill?.startsAt) {\n const d = new Date(prefill.startsAt)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n }\n return '09:00'\n })\n const [status, setStatus] = useState('scheduled')\n const [notes, setNotes] = useState('')\n const [showNotes, setShowNotes] = useState(false)\n const [saving, setSaving] = useState(false)\n const [conflict, setConflict] = useState(false)\n // Client search/quick-create state now lives inside <ContactPicker>.\n const [serviceOptions, setServiceOptions] = useState<ComboboxOption[]>([])\n const [initialServiceOptions, setInitialServiceOptions] = useState<ComboboxOption[]>([])\n const [editingDate, setEditingDate] = useState(false)\n const [editingTime, setEditingTime] = useState(false)\n const [confirmingDelete, setConfirmingDelete] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [editOrderId, setEditOrderId] = useState<string | null>(null)\n const [editOrderTotal, setEditOrderTotal] = useState(0)\n const [editPaymentStatus, setEditPaymentStatus] = useState<import('../bridges/financial-bridge').BookingPaymentStatus>('none')\n const [paymentStatusLoading, setPaymentStatusLoading] = useState(false)\n const [modalTab, setModalTab] = useState<'appointment' | 'client' | 'financial'>('appointment')\n const [clientData, setClientData] = useState<Record<string, any> | null>(null)\n const [clientDataLoading, setClientDataLoading] = useState(false)\n const [clientEditing, setClientEditing] = useState(false)\n const [cancellationReasons, setCancellationReasons] = useState<CancellationReasonItem[]>([])\n const [cancellationReasonId, setCancellationReasonId] = useState('')\n const [cancellationNotes, setCancellationNotes] = useState('')\n const [cancellationReasonsLoading, setCancellationReasonsLoading] = useState(false)\n\n // Active booking type config\n const activeType = config.bookingTypes.find((bt) => bt.id === bookingType) ?? config.bookingTypes[0]\n\n // What was asked for, not merely whether something is asked for. The dialog\n // covered the calendar, so \"opened\" and \"opened with a new slot\" were the\n // same event; beside the calendar you can pick a second slot while the first\n // is still on screen, and keying the reset on `open` alone would leave the\n // old date and time in a form the new click was supposed to have started.\n const requestKey = [\n mode, bookingId ?? '', initialTab ?? '',\n prefill?.startsAt ?? '', prefill?.endsAt ?? '',\n prefill?.professionalId ?? '', prefill?.locationId ?? '',\n prefill?.clientId ?? '', prefill?.kind ?? '',\n ].join('|')\n\n // Reset form when modal opens\n useEffect(() => {\n if (!open) return\n setClientId(prefill?.clientId ?? ''); setClientSearch(''); setClientPhone('')\n setProfessionalId(prefill?.professionalId ?? ''); setLocationId(prefill?.locationId ?? ''); setServices([])\n setServiceSearch(''); setNotes(''); setStatus('scheduled'); setShowNotes(false)\n setConflict(false); setLoading(mode === 'edit')\n setBookingType(prefill?.kind ?? defaultBookingType); setTitle('')\n setEditingDate(false); setEditingTime(false); setConfirmingDelete(false); setDeleting(false)\n setEditOrderId(null); setEditOrderTotal(0); setEditPaymentStatus('none'); setPaymentStatusLoading(false)\n setClientData(null); setClientDataLoading(false); setClientEditing(false)\n setCancellationReasonId(''); setCancellationNotes(''); setCancellationReasonsLoading(false)\n setModalTab((initialTab as 'appointment' | 'client' | 'financial') || 'appointment')\n if (!prefill?.professionalId && professionals.length === 1) setProfessionalId(professionals[0].id)\n setDate(() => {\n if (prefill?.startsAt) return prefill.startsAt.slice(0, 10)\n return new Date().toISOString().slice(0, 10)\n })\n setStartTime(() => {\n if (prefill?.startsAt) {\n const d = new Date(prefill.startsAt)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n }\n return '09:00'\n })\n }, [open, requestKey])\n\n // Edit: load existing\n useEffect(() => {\n if (!open || mode !== 'edit' || !bookingId) return\n setLoading(true)\n provider.getBookingById(bookingId).then((b) => {\n if (!b) { setLoading(false); return }\n setBookingType((b.kind as BookingTypeId) ?? defaultBookingType)\n setTitle(b.clientName ?? '')\n setClientId(b.clientId ?? ''); setClientSearch(b.clientName ?? '')\n setProfessionalId(b.professionalId ?? ''); setLocationId(b.locationId ?? '')\n setDate(b.startsAt.slice(0, 10))\n const d = new Date(b.startsAt)\n setStartTime(`${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`)\n setStatus(b.status); setNotes(b.notes ?? '')\n if (b.notes) setShowNotes(true)\n if (b.services) setServices(b.services.map((s: any) => ({\n serviceId: s.serviceId ?? '', name: s.name, durationMinutes: s.durationMinutes, price: s.price,\n })))\n setEditOrderId(b.orderId ?? null)\n setEditOrderTotal(b.orderTotal ?? 0)\n setEditPaymentStatus(b.paymentStatus ?? 'none')\n // Save initial snapshot for dirty check\n const svcSnap = b.services ? b.services.map((s: any) => ({ id: s.serviceId ?? '', dur: s.durationMinutes, price: s.price })) : []\n initialSnapshot.current = JSON.stringify({\n title: b.clientName ?? '',\n clientId: b.clientId ?? '', professionalId: b.professionalId ?? '', locationId: b.locationId ?? '',\n date: b.startsAt.slice(0, 10),\n startTime: `${String(new Date(b.startsAt).getHours()).padStart(2, '0')}:${String(new Date(b.startsAt).getMinutes()).padStart(2, '0')}`,\n status: b.status, notes: b.notes ?? '', cancellationReasonId: '', cancellationNotes: '', services: svcSnap,\n })\n setLoading(false)\n // Resolve payment status from bridge if available\n if (b.orderId && config.financialBridge) {\n setPaymentStatusLoading(true)\n config.financialBridge.resolvePaymentStatuses([b.orderId]).then((map) => {\n const summary = map.get(b.orderId!)\n if (summary) {\n setEditPaymentStatus(summary.status)\n setEditOrderTotal(summary.totalAmount)\n }\n }).catch(() => {}).finally(() => setPaymentStatusLoading(false))\n }\n }).catch(() => setLoading(false))\n // Same key as the reset above: whenever that clears the form to `loading`,\n // this has to be the thing that fills it back in.\n }, [open, requestKey])\n\n // Fetch client data when client tab is opened\n useEffect(() => {\n if (modalTab !== 'client' || !clientId || !config.contactLookup || clientData) return\n setClientDataLoading(true)\n config.contactLookup.getById(clientId).then((result) => {\n setClientData(result?.data ?? null)\n setClientDataLoading(false)\n }).catch(() => setClientDataLoading(false))\n }, [modalTab, clientId])\n\n useEffect(() => {\n if (!open || status !== 'cancelled' || !config.cancellationDetails || cancellationReasons.length > 0) return\n setCancellationReasonsLoading(true)\n config.cancellationDetails.listReasons()\n .then((reasons) => setCancellationReasons(reasons))\n .catch(() => setCancellationReasons([]))\n .finally(() => setCancellationReasonsLoading(false))\n }, [open, status, config.cancellationDetails, cancellationReasons.length])\n\n // Fetch initial service list when modal opens\n useEffect(() => {\n if (!open || !config.serviceLookup) return\n const lookup = config.serviceLookup\n const fetch = lookup.list ? () => lookup.list!() : () => lookup.search('')\n fetch().then((results) => {\n const opts = results.map((r: any) => ({ id: r.id, label: r.label, subtitle: r.subtitle, price: r.price, data: r.data }))\n setInitialServiceOptions(opts)\n }).catch(() => setInitialServiceOptions([]))\n }, [open])\n\n // Search effects (client search now lives inside <ContactPicker>)\n useEffect(() => {\n if (!config.serviceLookup || serviceSearch.length < 1) { setServiceOptions([]); return }\n const timer = setTimeout(async () => {\n try {\n const results = await config.serviceLookup!.search(serviceSearch)\n setServiceOptions(results.map((r: any) => ({ id: r.id, label: r.label, subtitle: r.subtitle, price: r.price, data: r.data })))\n } catch { setServiceOptions([]) }\n }, 250)\n return () => clearTimeout(timer)\n }, [serviceSearch])\n\n // Computed\n const serviceDuration = services.reduce((sum, s) => sum + s.durationMinutes, 0)\n const selectionDuration = useMemo(() => {\n if (!prefill?.startsAt || !prefill?.endsAt) return 0\n return Math.round((new Date(prefill.endsAt).getTime() - new Date(prefill.startsAt).getTime()) / 60000)\n }, [prefill?.startsAt, prefill?.endsAt])\n const totalDuration = serviceDuration > 0 ? serviceDuration : selectionDuration\n const totalPrice = services.reduce((sum, s) => sum + s.price, 0)\n const { currency } = config\n\n const endTime = useMemo(() => {\n const [h, m] = startTime.split(':').map(Number)\n const total = h * 60 + m + totalDuration\n return `${String(Math.floor(total / 60) % 24).padStart(2, '0')}:${String(total % 60).padStart(2, '0')}`\n }, [startTime, totalDuration])\n\n // Conflict check\n useEffect(() => {\n if (!professionalId || totalDuration === 0) { setConflict(false); return }\n const timer = setTimeout(() => {\n provider.checkConflict({\n assigneeId: professionalId, startsAt: `${date}T${startTime}:00`, endsAt: `${date}T${endTime}:00`, excludeBookingId: bookingId,\n }).then(setConflict).catch(() => setConflict(false))\n }, 300)\n return () => clearTimeout(timer)\n }, [professionalId, date, startTime, endTime, bookingId])\n\n function addService(opt: ComboboxOption) {\n const duration = (opt.data?.duration_minutes as number) || 60\n setServices((p) => [...p, { serviceId: opt.id, name: opt.label, durationMinutes: duration, price: opt.price ?? 0 }])\n setServiceSearch(''); setServiceOptions([])\n }\n function removeService(idx: number) { setServices((p) => p.filter((_, i) => i !== idx)) }\n\n // A service that does not exist yet. A catalogue is never complete on the day\n // someone calls asking for what is missing from it, and leaving the booking to\n // register one loses the slot being booked. Inline rather than a dialog: this\n // already sits inside a form. Without `create` on the source, search only.\n const serviceCreate = useLookupCreate(\n config.serviceLookup,\n (created) => {\n const duration = (created.data?.duration_minutes as number) || 60\n setServices((p) => [...p, {\n serviceId: created.id,\n name: created.label,\n durationMinutes: duration,\n price: created.price ?? 0,\n }])\n setServiceSearch('')\n setServiceOptions([])\n },\n { variant: 'inline' },\n )\n\n async function handleSubmit(e: React.FormEvent) {\n e.preventDefault()\n if (!canSubmit) return\n // Plan quantity guard (client-side, before the store call): opens the global\n // UpgradeModal and aborts when the monthly booking cap is reached. CREATE only.\n if (mode === 'create' && (await guardBookings()) === 'blocked') return\n setSaving(true)\n try {\n const startsAt = new Date(`${date}T${startTime}:00`).toISOString()\n if (mode === 'create') {\n const newBooking = await createBooking({ kind: bookingType, clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined,\n title: activeType.fields.title ? title.trim() : undefined,\n services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })) })\n invalidateLimit('bookings_month')\n onClose()\n onCreated?.(newBooking.id, externalSource)\n } else if (bookingId) {\n await updateBooking(bookingId, {\n clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined, status: status as any,\n title: activeType.fields.title ? title.trim() : undefined,\n services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })),\n })\n if (status === 'cancelled' && config.cancellationDetails && cancellationReasonId) {\n await config.cancellationDetails.saveCancellationDetails({\n bookingId,\n reasonId: cancellationReasonId,\n notes: cancellationNotes.trim() || undefined,\n cancelledAt: new Date().toISOString(),\n })\n }\n onClose()\n }\n } catch { /* toast */ }\n setSaving(false)\n }\n\n async function handleDelete() {\n if (!bookingId) return\n setDeleting(true)\n try {\n await deleteBooking(bookingId)\n onClose()\n } catch {\n // deleteBooking surfaces its own toast. Return the footer to its normal\n // state (out of the confirm step) so a failure is clear feedback rather\n // than a modal that silently stays stuck on \"Confirm delete\".\n setConfirmingDelete(false)\n } finally {\n setDeleting(false)\n }\n }\n\n const isPaidBooking = editPaymentStatus === 'paid'\n const selectedCancellationReason = cancellationReasons.find((reason) => reason.id === cancellationReasonId)\n const needsCancellationReason = mode === 'edit' && status === 'cancelled' && !!config.cancellationDetails\n const needsCancellationNotes = needsCancellationReason && !!selectedCancellationReason?.requiresNotes\n\n // Dirty check — only enable Update when something changed\n const formSnapshot = useMemo(() =>\n JSON.stringify({ title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services: services.map((s: any) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),\n [title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services]\n )\n const isDirty = mode === 'create' || formSnapshot !== initialSnapshot.current\n\n const canSubmit = (\n (!activeType.fields.title || title.trim()) &&\n (!activeType.requiresClient || clientId) &&\n (!activeType.fields.professional || professionalId) &&\n (!activeType.requiresServices || services.length > 0) &&\n (!needsCancellationReason || !!cancellationReasonId) &&\n (!needsCancellationNotes || !!cancellationNotes.trim()) &&\n !conflict && !saving\n )\n\n const showTabs = config.bookingTypes.length > 1\n\n // The column heads the page, so the form no longer names itself.\n const railTitle = mode === 'create'\n ? t('agenda.appointment.new')\n : (title.trim() || clientSearch || t('agenda.appointment.edit'))\n\n return (\n // A booking is written next to the calendar it belongs to, not on top of\n // it: the dialog used to dim the week you were reading while you filled in\n // a slot from it, and a second panel opening from the same edge as the\n // assistant meant two vocabularies for one side of the screen.\n <RightRailPage title={railTitle} open={open} onClose={onClose} width=\"max-w-lg\">\n\n {/* ═══ TOP — type tabs + date/time ═══ */}\n <div className=\"px-5 pt-3 pb-3 shrink-0 space-y-3\">\n {/* Booking type tabs (create) or section tabs (edit) */}\n {showTabs && mode === 'create' ? (\n <div className=\"flex gap-1 border-b fayz-glass-divider\">\n {config.bookingTypes.map((bt) => {\n const label = t(`agenda.bookingType.${bt.id}`) || bt.label\n const isActive = bookingType === bt.id\n const BtIcon = BOOKING_TYPE_ICONS[bt.icon] ?? Calendar\n return (\n <button key={bt.id} type=\"button\" onClick={() => setBookingType(bt.id)}\n className={`relative flex items-center gap-1.5 pb-2 px-2 text-xs font-medium transition-colors ${\n isActive ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'\n }`}>\n <BtIcon className=\"h-3.5 w-3.5\" />\n {label}\n {isActive && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-foreground\" />\n )}\n </button>\n )\n })}\n </div>\n ) : mode === 'edit' && (\n (config.clientEntityDef && clientId) || (config.modules.financial && editOrderId) ? (\n <div className=\"flex gap-1 border-b fayz-glass-divider\">\n {([\n { id: 'appointment' as const, label: t(`agenda.bookingType.${bookingType}`) || activeType.label, icon: Calendar, show: true },\n { id: 'client' as const, label: t('agenda.appointment.clientTab'), icon: User, show: !!config.clientEntityDef && !!clientId },\n { id: 'financial' as const, label: t('agenda.payment.title'), icon: DollarSign, show: config.modules.financial && !!editOrderId },\n ]).filter((tab) => tab.show).map((tab) => {\n const isActive = modalTab === tab.id\n return (\n <button key={tab.id} type=\"button\" onClick={() => setModalTab(tab.id)}\n className={`relative flex items-center gap-1.5 pb-2 px-2 text-xs font-medium transition-colors ${\n isActive ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'\n }`}>\n <tab.icon className=\"h-3.5 w-3.5\" />\n {tab.label}\n {tab.id === 'financial' && editPaymentStatus === 'paid' && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-success\" />\n )}\n {tab.id === 'financial' && editPaymentStatus !== 'paid' && (\n (editPaymentStatus !== 'none' || (totalPrice > 0 && date <= new Date().toISOString().slice(0, 10)))\n ) && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-warning\" />\n )}\n {isActive && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-foreground\" />\n )}\n </button>\n )\n })}\n </div>\n ) : null\n )}\n\n {/* Date/time + professional row — hidden on financial tab */}\n {modalTab === 'appointment' && (\n <>\n <div className=\"flex items-center gap-3\">\n <Clock className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n {/* Wraps: the column is ~380px, so the assignee drops to its\n own line rather than squeezing the time out of the row. */}\n <div className=\"flex flex-wrap items-center gap-x-1.5 gap-y-1 text-sm flex-1 min-w-0\">\n {editingDate ? (\n <input type=\"date\" value={date} autoFocus\n onChange={(e) => { setDate(e.target.value); setEditingDate(false) }}\n onBlur={() => setEditingDate(false)}\n className=\"bg-transparent text-sm font-medium focus:outline-none border-b border-foreground w-auto shrink-0\" />\n ) : (\n <button type=\"button\" onClick={() => setEditingDate(true)}\n className=\"px-0.5 py-0.5 font-medium border-b border-transparent hover:border-foreground transition-colors shrink-0\">\n {formatCompactDate(date, locale)}\n </button>\n )}\n {editingTime ? (\n <input type=\"time\" value={startTime} autoFocus\n onChange={(e) => { if (e.target.value) { setStartTime(e.target.value); setEditingTime(false) } }}\n onBlur={() => setEditingTime(false)}\n className=\"bg-transparent text-xs text-muted-foreground focus:outline-none border-b border-foreground w-auto shrink-0\" />\n ) : (\n <button type=\"button\" onClick={() => setEditingTime(true)}\n className=\"px-0.5 py-0.5 text-xs text-muted-foreground border-b border-transparent hover:border-foreground transition-colors shrink-0\">\n {startTime}\n </button>\n )}\n <span className=\"text-[11px] text-muted-foreground/60\">—</span>\n <span className=\"text-[11px] text-muted-foreground/60\">{endTime}</span>\n\n {/* Professional — right-aligned on the same row */}\n {activeType.fields.professional && (\n <div className=\"ml-auto shrink-0\">\n <ProfessionalSelect value={professionalId} onChange={setProfessionalId} professionals={professionals} />\n </div>\n )}\n </div>\n </div>\n\n {conflict && (\n <div className=\"flex items-center gap-2 rounded-lg bg-destructive/10 px-3 py-1.5 text-xs text-destructive\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0\" />\n {t('agenda.appointment.conflict')}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* ═══ BODY ═══ */}\n <div className=\"flex flex-col flex-1 min-h-0 overflow-hidden\">\n\n {/* Client tab content — reuses the same CrudDetailPage as /clients/:id */}\n {modalTab === 'client' && clientId && config.clientEntityDef && (\n <div className=\"flex-1 overflow-y-auto px-5 py-4\">\n {clientDataLoading ? (\n <div className=\"space-y-3 py-2\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"h-8 rounded-lg bg-muted animate-pulse\" />\n ))}\n </div>\n ) : clientData ? (\n clientEditing ? (\n <CrudFormPage\n embedded\n entityDef={config.clientEntityDef}\n mode=\"edit\"\n initialData={clientData}\n namePlural=\"\"\n onCancel={() => setClientEditing(false)}\n onSubmit={async (data) => {\n try {\n const { getSupabaseClientOptional } = await import('@fayz-ai/core')\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return\n const dbData: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(data)) {\n dbData[k.replace(/[A-Z]/g, (m) => '_' + m.toLowerCase())] = v\n }\n await supabase.from('people').update(dbData).eq('id', clientId)\n setClientData({ ...clientData, ...data })\n setClientEditing(false)\n } catch { /* toast */ }\n }}\n />\n ) : (\n <CrudDetailPage\n embedded\n entityDef={config.clientEntityDef}\n item={clientData}\n namePlural=\"\"\n basePath=\"\"\n onBack={() => setModalTab('appointment')}\n onEdit={() => setClientEditing(true)}\n />\n )\n ) : (\n <p className=\"text-sm text-muted-foreground py-4 text-center\">{t('agenda.appointment.noClientData')}</p>\n )}\n </div>\n )}\n\n {/* Financial tab content */}\n {modalTab === 'financial' && editOrderId && config.financialBridge && (\n <div className=\"flex-1 overflow-y-auto\">\n <BookingPaymentPanel\n orderId={editOrderId}\n orderTotal={editOrderTotal}\n services={services.map((s: any) => ({ name: s.name, price: s.price, durationMinutes: s.durationMinutes }))}\n formatCurrency={(v) => fmtCurrency(v, currency.locale, currency.code)}\n inline\n onClose={() => setModalTab('appointment')}\n onPaymentChange={() => {\n config.financialBridge!.getPaymentDetail(editOrderId).then((d) => {\n if (d) { setEditPaymentStatus(d.status); setEditOrderTotal(d.totalAmount) }\n }).catch(() => {})\n // Propagate to the calendar card + popover badge (booking.paymentStatus\n // is ledger-derived) so they update without a page refresh.\n if (agendaDateRange.start) fetchBookings(agendaDateRange)\n }}\n />\n </div>\n )}\n\n {/* Appointment tab content */}\n <form onSubmit={handleSubmit} className=\"flex flex-col flex-1 min-h-0 overflow-hidden\" style={{ display: modalTab === 'appointment' ? undefined : 'none' }}>\n <div className=\"border-t fayz-glass-divider px-5 py-3 space-y-1 flex-1 overflow-y-auto\">\n\n {/* Loading skeleton */}\n {loading && (\n <div className=\"space-y-2 py-2\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 py-1.5\">\n <div className=\"h-4 w-4 rounded bg-muted animate-pulse shrink-0\" />\n <div className=\"h-8 flex-1 rounded-lg bg-muted animate-pulse\" />\n </div>\n ))}\n </div>\n )}\n\n {!loading && <>\n\n {/* Title — free-text event name (simple / Google-Calendar-style events) */}\n {activeType.fields.title && (\n <div className=\"flex items-center gap-3 py-1\">\n <Calendar className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <input type=\"text\" value={title} onChange={(e) => setTitle(e.target.value)}\n placeholder={t('agenda.appointment.addTitle')} autoFocus={mode === 'create'} aria-required\n className=\"w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n\n {/* Client */}\n {activeType.fields.client && (\n <div className=\"flex items-center gap-3 py-1\">\n <User className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"flex-1\">\n {/* Shared find-or-create flow (@fayz-ai/admin), same component\n and same behaviour as the conversations composer.\n `variant=\"inline\"` only drops the chrome, to match this\n form's icon rows. Creating opens the app's own client\n form — see `createEntityDef`. */}\n <ContactPicker\n value={clientId || clientSearch ? { id: clientId || undefined, name: clientSearch, phone: clientPhone } : null}\n onChange={(contact) => {\n setClientId(contact?.id ?? '')\n setClientSearch(contact?.name ?? '')\n setClientPhone(contact?.phone ?? '')\n }}\n kind={config.clientKind}\n lookup={config.contactLookup}\n createEntityDef={config.clientEntityDef}\n clearable={!isPaidBooking}\n variant=\"inline\"\n placeholder={t('agenda.appointment.searchClient')}\n createLabel={t('agenda.appointment.newClient')}\n required={activeType.requiresClient}\n />\n </div>\n </div>\n )}\n\n {/* Location */}\n {activeType.fields.location && config.modules.locationSelection && (storeLocations.length > 0 || config.locations.length > 0) && (\n <div className=\"flex items-center gap-3 py-1\">\n <MapPin className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <LocationSelect\n value={locationId}\n onChange={setLocationId}\n locations={storeLocations.length > 0 ? storeLocations : config.locations}\n />\n </div>\n )}\n\n {/* Services */}\n {activeType.fields.services && (\n <div className=\"flex items-start gap-3 py-1\">\n <Briefcase className=\"h-4 w-4 mt-1.5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1\">\n {services.length > 0 && (\n <div className=\"space-y-0.5 mb-1\">\n {services.map((svc, idx) => (\n <div key={idx} className=\"flex items-center rounded-md bg-muted/30 px-2.5 py-1.5 text-sm\">\n <span className=\"flex-1 truncate min-w-0\">{svc.name}</span>\n <div className=\"flex items-center gap-0.5 shrink-0 ml-3\">\n <InlineNumber\n value={svc.durationMinutes}\n onChange={(v) => setServices((p) => p.map((s, i) => i === idx ? { ...s, durationMinutes: Math.round(v) } : s))}\n min={5}\n step={5}\n className=\"w-10 shrink-0\"\n disabled={isPaidBooking}\n tooltip={t('agenda.appointment.duration')}\n />\n <span className=\"text-[11px] text-muted-foreground\">min</span>\n </div>\n <div className=\"flex items-center gap-0.5 shrink-0 ml-3\">\n <span className=\"text-[11px] text-muted-foreground\">{currency.symbol}</span>\n <InlineNumber\n value={svc.price}\n onChange={(v) => setServices((p) => p.map((s, i) => i === idx ? { ...s, price: v } : s))}\n min={0}\n step={0.01}\n className=\"w-14 shrink-0\"\n disabled={isPaidBooking}\n tooltip={t('agenda.appointment.price')}\n />\n </div>\n {!isPaidBooking && (\n <button type=\"button\" onClick={() => removeService(idx)} className=\"p-0.5 ml-2 text-muted-foreground hover:text-destructive shrink-0\">\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n\n {serviceCreate.creating && serviceCreate.form}\n\n {!isPaidBooking && !serviceCreate.creating && <SearchCombobox\n value={serviceSearch}\n onChange={setServiceSearch}\n onSelect={addService}\n options={serviceOptions}\n placeholder={t('agenda.appointment.searchService')}\n onBlurEmpty={() => {}}\n onFocus={() => { if (!serviceSearch && serviceOptions.length === 0) setServiceOptions(initialServiceOptions) }}\n renderRight={(opt) => {\n const dur = (opt.data?.duration_minutes as number) || 0\n const hasPrice = opt.price != null\n if (!hasPrice && !dur) return null\n return (\n <span className=\"text-muted-foreground text-xs whitespace-nowrap\">\n {hasPrice && fmtCurrency(opt.price!, currency.locale, currency.code)}\n {hasPrice && dur > 0 && ' · '}\n {dur > 0 && `${dur}min`}\n </span>\n )\n }}\n minimal\n chevron\n required={activeType.requiresServices && services.length === 0}\n allowCreate={!!serviceCreate.onCreate}\n onCreateNew={serviceCreate.onCreate}\n createLabel={t('agenda.appointment.newService')}\n inlineLabel={services.length > 0 ? t('agenda.appointment.addService') : t('agenda.appointment.addServiceFirst')}\n inlineIcon={services.length > 0 ? 'plus' : 'search'}\n />}\n </div>\n </div>\n )}\n\n {/* Status */}\n {activeType.fields.status && (\n <div className=\"flex items-center gap-3 py-1\">\n <CircleDot className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <StatusSelect value={status} onChange={setStatus} statuses={config.statuses} bookingDate={date} />\n </div>\n )}\n\n {needsCancellationReason && (\n <div className=\"flex items-start gap-3 py-1\">\n <Ban className=\"h-4 w-4 mt-2 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 space-y-2\">\n <select\n value={cancellationReasonId}\n onChange={(event) => setCancellationReasonId(event.target.value)}\n disabled={cancellationReasonsLoading}\n aria-required\n className=\"w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring\"\n >\n <option value=\"\">{cancellationReasonsLoading ? t('agenda.cancellation.loadingReasons') : t('agenda.cancellation.selectReason')}</option>\n {cancellationReasons.map((reason) => (\n <option key={reason.id} value={reason.id}>\n {reason.label}{reason.requiresNotes ? ' *' : ''}\n </option>\n ))}\n </select>\n <textarea\n value={cancellationNotes}\n onChange={(event) => setCancellationNotes(event.target.value)}\n placeholder={needsCancellationNotes ? t('agenda.cancellation.notesRequired') : t('agenda.cancellation.notesOptional')}\n rows={2}\n aria-required={needsCancellationNotes || undefined}\n className=\"w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm resize-none shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n </div>\n )}\n\n {/* Notes — progressive disclosure */}\n {!showNotes ? (\n <div className=\"flex items-center gap-3 py-1\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <button type=\"button\" onClick={() => setShowNotes(true)}\n className=\"text-sm text-muted-foreground hover:text-foreground transition-colors text-left py-1.5 pl-2\">\n {t('agenda.appointment.addNotes')}\n </button>\n </div>\n ) : (\n <div className=\"flex items-start gap-3 py-1\">\n <FileText className=\"h-4 w-4 mt-2 text-muted-foreground shrink-0\" />\n <textarea value={notes} onChange={(e) => setNotes(e.target.value)}\n placeholder={t('agenda.appointment.addDescription')} rows={2} autoFocus\n className=\"w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm resize-none focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n\n </>}\n </div>\n\n {/* Appointment footer — inside form for submit */}\n {modalTab === 'appointment' && !clientEditing && (\n <div className=\"px-5 py-2.5 border-t fayz-glass-divider bg-transparent shrink-0\">\n {confirmingDelete ? (\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-destructive font-medium\">{t('agenda.appointment.deleteConfirm')}</span>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setConfirmingDelete(false)}>\n {t('agenda.appointment.cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" size=\"sm\" onClick={handleDelete} disabled={deleting}>\n {deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {mode === 'edit' && (\n <button type=\"button\" onClick={() => setConfirmingDelete(true)} className=\"text-xs text-destructive font-medium hover:underline\">{t('agenda.appointment.delete')}</button>\n )}\n {services.length > 0 && (\n <span className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {totalDuration}min\n {config.modules.financial && totalPrice > 0 && mode === 'edit' ? (\n paymentStatusLoading ? (\n <span className=\"h-4 w-16 rounded-full bg-muted animate-pulse\" />\n ) : isPaidBooking ? (\n <button type=\"button\" onClick={(e) => { e.stopPropagation(); setModalTab('financial') }}\n className=\"inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-[10px] font-medium text-success hover:bg-success/20 transition-colors\">\n <Check className=\"h-2.5 w-2.5\" />\n {fmtCurrency(totalPrice, currency.locale, currency.code)} · {t('agenda.payment.paid')}\n </button>\n ) : date <= new Date().toISOString().slice(0, 10) ? (\n <button type=\"button\" onClick={(e) => { e.stopPropagation(); setModalTab('financial') }}\n className=\"inline-flex items-center gap-1 rounded-full bg-warning/10 px-2 py-0.5 text-[10px] font-medium text-warning hover:bg-warning/20 transition-colors\">\n <HandCoins className=\"h-3 w-3\" />\n {fmtCurrency(totalPrice, currency.locale, currency.code)} · {t('agenda.payment.collect')}\n </button>\n ) : (\n <span>· {fmtCurrency(totalPrice, currency.locale, currency.code)}</span>\n )\n ) : (\n <span>· {fmtCurrency(totalPrice, currency.locale, currency.code)}</span>\n )}\n </span>\n )}\n </div>\n {/* No Cancel button: the column's header already holds the\n way out, and at this width it crowded Save. */}\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" variant=\"default\" size=\"sm\" disabled={!canSubmit || !isDirty}>\n {saving ? t('agenda.appointment.saving') : mode === 'create' ? t('agenda.appointment.save') : t('agenda.appointment.update')}\n </Button>\n </div>\n </div>\n )}\n </div>\n )}\n </form>\n\n {/* Non-appointment tab footer — outside form */}\n {modalTab !== 'appointment' && !clientEditing && (\n <div className=\"px-5 py-2.5 border-t fayz-glass-divider bg-transparent shrink-0\">\n <div className=\"flex items-center\">\n <button type=\"button\" onClick={() => { setModalTab('appointment'); setClientEditing(false) }}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors\">\n <svg className=\"h-3 w-3\" viewBox=\"0 0 16 16\" fill=\"none\"><path d=\"M10 12L6 8l4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>\n {t('agenda.payment.backToAppointment')}\n </button>\n </div>\n </div>\n )}\n </div>\n </RightRailPage>\n )\n}\n","import React, { useEffect, useRef, useState, useCallback } from 'react'\nimport { createPortal } from 'react-dom'\n\n// ---------------------------------------------------------------------------\n// Inject animations once\n// ---------------------------------------------------------------------------\n\nconst STYLE_ID = 'saas-floating-panel'\nif (typeof document !== 'undefined' && !document.getElementById(STYLE_ID)) {\n const s = document.createElement('style')\n s.id = STYLE_ID\n s.textContent = `\n @keyframes _fp-dismiss { from { opacity:1; transform:scale(1) } to { opacity:0; transform:scale(.96) } }\n @keyframes _fp-expand { from { opacity:1; transform:scale(1) } to { opacity:0; transform:scale(1.08) } }\n .saas-fp-dismissing { animation: _fp-dismiss 150ms ease-in forwards; pointer-events: none }\n .saas-fp-expanding { animation: _fp-expand 200ms ease-in forwards; pointer-events: none }\n `\n document.head.appendChild(s)\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype Phase = 'visible' | 'dismissing' | 'expanding'\n\nexport interface FloatingPanelRef {\n /** Dismiss with fade-out, then call onClose */\n dismiss: () => void\n /** Expand-out animation (e.g. popover → modal), then call callback */\n expandThen: (callback: () => void) => void\n}\n\ninterface FloatingPanelProps {\n position: { x: number; y: number }\n width: number\n height: number\n /** Offset from cursor (default: { x: 0, y: 0 }) */\n offset?: { x: number; y: number }\n onClose: () => void\n className?: string\n children: (ref: FloatingPanelRef) => React.ReactNode\n zIndex?: number\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function FloatingPanel({\n position, width, height, offset, onClose, className, children, zIndex = 100,\n}: FloatingPanelProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [phase, setPhase] = useState<Phase>('visible')\n const phaseRef = useRef<Phase>('visible')\n phaseRef.current = phase\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n const expandCallbackRef = useRef<(() => void) | null>(null)\n\n const dismiss = useCallback(() => {\n if (phaseRef.current !== 'visible') return\n setPhase('dismissing')\n setTimeout(() => onCloseRef.current(), 150)\n }, [])\n\n const expandThen = useCallback((callback: () => void) => {\n if (phaseRef.current !== 'visible') return\n expandCallbackRef.current = callback\n setPhase('expanding')\n setTimeout(() => {\n callback()\n onCloseRef.current()\n }, 220)\n }, [])\n\n // Outside click + Escape\n useEffect(() => {\n function handleClick(e: MouseEvent) {\n if (phaseRef.current !== 'visible') return\n if (ref.current && !ref.current.contains(e.target as Node)) {\n // Don't dismiss if clicking another calendar event — let eventClick handle it\n const target = e.target as HTMLElement\n if (target.closest('.fc-event')) return\n dismiss()\n }\n }\n function handleKey(e: KeyboardEvent) {\n if (e.key === 'Escape') dismiss()\n }\n document.addEventListener('mousedown', handleClick)\n document.addEventListener('keydown', handleKey)\n return () => {\n document.removeEventListener('mousedown', handleClick)\n document.removeEventListener('keydown', handleKey)\n }\n }, [dismiss])\n\n // Clamp position to viewport\n const ox = offset?.x ?? 0\n const oy = offset?.y ?? 0\n let x = position.x + ox\n let y = position.y + oy\n if (x + width > window.innerWidth - 12) x = x - width - ox * 2\n if (y + height > window.innerHeight - 12) y = y - height - oy * 2\n if (x < 12) x = 12\n if (y < 12) y = 12\n\n const panelRef: FloatingPanelRef = { dismiss, expandThen }\n\n return createPortal(\n <div ref={ref}\n style={{ position: 'fixed', left: x, top: y, zIndex, transition: phase === 'visible' ? 'left 200ms ease-out, top 200ms ease-out' : undefined }}\n className={`fayz-glass-surface rounded-modal border bg-popover shadow-lg overflow-hidden ${\n phase === 'expanding' ? 'saas-fp-expanding'\n : phase === 'dismissing' ? 'saas-fp-dismissing'\n : 'animate-in fade-in zoom-in-95 duration-150'\n } ${className ?? ''}`}>\n {children(panelRef)}\n </div>,\n document.body,\n )\n}\n","import React, { useState, useRef, useEffect } from 'react'\nimport { X, Pencil, Trash2, Clock, MapPin, User, FileText, DollarSign, Check, AlertTriangle, HandCoins } from 'lucide-react'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { FloatingPanel, type FloatingPanelRef } from './FloatingPanel'\nimport { useAgendaConfig, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CalendarBooking } from '../types'\n\ninterface Props {\n booking: CalendarBooking\n position: { x: number; y: number }\n onClose: () => void\n onEdit: (id: string) => void\n}\n\nfunction fmtTime(iso: string) {\n return new Date(iso).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n}\nfunction fmtDate(iso: string) {\n return new Date(iso).toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })\n}\nfunction fmtCurrency(amount: number, locale: string, code: string) {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(amount)\n}\n\n// Inline status select for the popover\nfunction PopoverStatusSelect({ value, statuses, bookingStartsAt, onChange }: {\n value: string; statuses: Array<{ value: string; label: string; color: string; availableWhen?: string }>\n bookingStartsAt: string; onChange: (v: string) => void\n}) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = statuses.find((s) => s.value === value)\n\n useEffect(() => {\n if (!open) return\n const h = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', h)\n return () => document.removeEventListener('mousedown', h)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative inline-block\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors hover:opacity-80\"\n style={{ backgroundColor: (current?.color ?? '#6b7280') + '18', color: current?.color ?? '#6b7280' }}>\n <span className=\"h-2 w-2 rounded-full\" style={{ backgroundColor: current?.color }} />\n {current?.label ?? value}\n <svg className=\"h-3 w-3 opacity-50\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute bottom-full left-0 z-50 mb-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100 min-w-[140px]\">\n {statuses.map((s) => {\n const available = isStatusAvailable(s as any, bookingStartsAt)\n return (\n <button key={s.value} type=\"button\" disabled={!available}\n onClick={() => { if (available) { onChange(s.value); setOpen(false) } }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-xs transition-colors ${\n !available ? 'opacity-30 cursor-not-allowed' : s.value === value ? 'bg-muted/30' : 'hover:bg-muted/50'\n }`}>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: s.color }} />\n <span>{s.label}</span>\n </button>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport function AppointmentPopover({ booking, position, onClose, onEdit }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const updateStatus = useAgendaStore((s) => s.updateBookingStatus)\n const openModal = useAgendaStore((s) => s.openAppointmentModal)\n const [confirmingDelete, setConfirmingDelete] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const statusConfig = config.statuses.find((s) => s.value === booking.status)\n const color = statusConfig?.color ?? '#6b7280'\n const timeRange = `${fmtTime(booking.startsAt)}${booking.endsAt ? ' – ' + fmtTime(booking.endsAt) : ''}`\n\n async function handleDelete() {\n setDeleting(true)\n try { await deleteBooking(booking.id); onClose() } catch { setDeleting(false) }\n }\n\n return (\n <>\n <FloatingPanel position={position} width={320} height={340} onClose={onClose}>\n {(panel) => (\n <>\n {/* Action bar */}\n <div className=\"flex items-center justify-end gap-0.5 px-3 pt-3 pb-1\">\n {confirmingDelete ? (\n <>\n <span className=\"text-xs text-destructive font-medium mr-auto pl-1\">{t('agenda.appointment.deleteConfirm')}</span>\n <button onClick={() => setConfirmingDelete(false)}\n className=\"rounded px-2 py-0.5 text-[11px] font-medium hover:bg-muted/50 transition-colors\">{t('agenda.appointment.cancel')}</button>\n <button onClick={handleDelete} disabled={deleting}\n className=\"rounded bg-destructive border border-destructive px-2 py-0.5 text-[11px] font-medium text-destructive-foreground hover:bg-destructive/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\">{deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}</button>\n </>\n ) : (\n <>\n <button onClick={() => panel.expandThen(() => onEdit(booking.id))}\n className=\"p-1.5 rounded-full hover:bg-muted transition-colors\" title={t('common.edit')}>\n <Pencil className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n <button onClick={() => setConfirmingDelete(true)}\n className=\"p-1.5 rounded-full hover:bg-destructive/10 transition-colors\" title={t('common.delete')}>\n <Trash2 className=\"h-4 w-4 text-muted-foreground hover:text-destructive\" />\n </button>\n <button onClick={panel.dismiss} className=\"p-1.5 rounded-full hover:bg-muted transition-colors\">\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </>\n )}\n </div>\n\n {/* Content */}\n <div className=\"px-5 pb-5 space-y-3\">\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-1.5 h-3 w-3 rounded shrink-0\" style={{ backgroundColor: color }} />\n <div className=\"min-w-0\">\n {/* Client agendas link to the person; simple events (no client\n capability) render the free-text title as a plain heading —\n booking.clientName carries the event title in that model. */}\n {config.capabilities.client ? (\n <PersonLink personId={booking.clientId} name={booking.clientName ?? 'Unknown'} className=\"text-base\" />\n ) : (\n <p className=\"text-base font-medium truncate\">{booking.clientName || t('agenda.appointment.untitled')}</p>\n )}\n <p className=\"text-sm text-muted-foreground mt-0.5\">{fmtDate(booking.startsAt)} · {timeRange}</p>\n </div>\n </div>\n\n {booking.services && booking.services.length > 0 && (\n <div className=\"flex items-start gap-3\">\n <Clock className=\"h-4 w-4 mt-0.5 text-muted-foreground shrink-0\" />\n <div className=\"text-sm space-y-0.5\">\n {booking.services.map((svc) => (\n <p key={svc.id}>{svc.name} <span className=\"text-muted-foreground\">({svc.durationMinutes}min)</span></p>\n ))}\n </div>\n </div>\n )}\n\n {config.capabilities.professional && booking.professionalName && (\n <div className=\"flex items-center gap-3\">\n <User className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-sm\">{booking.professionalName}</span>\n </div>\n )}\n\n {booking.locationName && (\n <div className=\"flex items-center gap-3\">\n <MapPin className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-sm\">{booking.locationName}</span>\n </div>\n )}\n\n {booking.notes && (\n <div className=\"flex items-start gap-3\">\n <FileText className=\"h-4 w-4 mt-0.5 text-muted-foreground shrink-0\" />\n <p className=\"text-sm text-muted-foreground\">{booking.notes}</p>\n </div>\n )}\n\n {booking.orderTotal != null && booking.orderTotal > 0 && (() => {\n const total = fmtCurrency(booking.orderTotal, config.currency.locale, config.currency.code)\n const ps = booking.paymentStatus ?? 'none'\n const hasFinancial = config.modules.financial && booking.orderId\n\n // No financial module — just show total\n if (!hasFinancial) {\n return (\n <div className=\"pt-2 border-t fayz-glass-divider flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">{t('agenda.appointment.total')}</span>\n <span className=\"font-medium\">{total}</span>\n </div>\n )\n }\n\n const badgeConfig: Record<string, { icon: React.ElementType; bg: string; text: string; label: string }> = {\n none: { icon: HandCoins, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.collect')}` },\n pending: { icon: Clock, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.pending')}` },\n partial: { icon: DollarSign, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.partial')}` },\n paid: { icon: Check, bg: 'bg-success/10 hover:bg-success/15', text: 'text-success', label: `${total} · ${t('agenda.payment.paid')}` },\n overdue: { icon: AlertTriangle, bg: 'bg-destructive/10 hover:bg-destructive/15', text: 'text-destructive', label: `${total} · ${t('agenda.payment.overdue')}` },\n cancelled: { icon: X, bg: 'bg-muted hover:bg-muted/80', text: 'text-muted-foreground', label: `${total} · ${t('agenda.payment.cancelled')}` },\n }\n const cfg = badgeConfig[ps] ?? badgeConfig.none\n const StatusIcon = cfg.icon\n\n return (\n <div className=\"pt-2 border-t fayz-glass-divider flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">{t('agenda.appointment.total')}</span>\n <button\n type=\"button\"\n onClick={() => { onClose(); openModal('edit', { bookingId: booking.id, initialTab: 'financial' }) }}\n className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium transition-colors ${cfg.bg} ${cfg.text}`}\n >\n <StatusIcon className=\"h-3 w-3\" />\n {cfg.label}\n </button>\n </div>\n )\n })()}\n\n {/* Status workflow — hidden for simple events (no status capability). */}\n {config.capabilities.status && (\n <div className=\"pt-2 border-t fayz-glass-divider\">\n <PopoverStatusSelect\n value={booking.status}\n statuses={config.statuses}\n bookingStartsAt={booking.startsAt}\n onChange={(v) => { updateStatus(booking.id, v); onClose() }}\n />\n </div>\n )}\n </div>\n </>\n )}\n </FloatingPanel>\n </>\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Pencil, Trash2, Check } from 'lucide-react'\nimport { FloatingPanel } from './FloatingPanel'\nimport { useAgendaConfig, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Tooltip — portaled to body\n// ---------------------------------------------------------------------------\n\nfunction Tooltip({ anchor, label }: { anchor: DOMRect; label: string }) {\n return createPortal(\n <div style={{ position: 'fixed', left: anchor.left + anchor.width / 2, top: anchor.bottom + 6, transform: 'translateX(-50%)', zIndex: 120 }}\n className=\"pointer-events-none\">\n <div className=\"rounded-md bg-foreground text-background px-2 py-0.5 text-[11px] font-medium whitespace-nowrap shadow-lg\">\n {label}\n </div>\n </div>,\n document.body,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Status dot with portaled tooltip\n// ---------------------------------------------------------------------------\n\nfunction StatusDot({ color, label, isActive, disabled, onClick }: {\n color: string; label: string; isActive: boolean; disabled?: boolean; onClick: () => void\n}) {\n const [hover, setHover] = useState(false)\n const btnRef = useRef<HTMLButtonElement>(null)\n const [rect, setRect] = useState<DOMRect | null>(null)\n\n return (\n <>\n <button ref={btnRef} type=\"button\" onClick={disabled ? undefined : onClick} disabled={disabled}\n onMouseEnter={() => { setHover(true); if (btnRef.current) setRect(btnRef.current.getBoundingClientRect()) }}\n onMouseLeave={() => setHover(false)}\n className={`flex h-7 w-7 items-center justify-center rounded-full transition-all ${\n disabled ? 'opacity-25 cursor-not-allowed' : isActive ? 'ring-2 ring-offset-2 ring-offset-popover' : 'hover:scale-110'\n }`}\n style={{ backgroundColor: color, ['--tw-ring-color' as any]: isActive ? color : undefined }}>\n {isActive && <Check className=\"h-3.5 w-3.5 text-white\" strokeWidth={2.5} />}\n </button>\n {hover && rect && <Tooltip anchor={rect} label={label} />}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Context Menu\n// ---------------------------------------------------------------------------\n\ninterface Props {\n booking: CalendarBooking\n position: { x: number; y: number }\n onClose: () => void\n onEdit: (id: string) => void\n}\n\nexport function EventContextMenu({ booking, position, onClose, onEdit }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const updateStatus = useAgendaStore((s) => s.updateBookingStatus)\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const [confirming, setConfirming] = useState(false)\n const [deleting, setDeleting] = useState(false)\n\n async function handleDelete() {\n setDeleting(true)\n try { await deleteBooking(booking.id); onClose() } catch { setDeleting(false) }\n }\n\n return (\n <FloatingPanel position={position} width={230} height={180} offset={{ x: 4, y: 4 }} onClose={onClose} zIndex={110}>\n {(panel) => (\n <>\n <div className=\"py-1\">\n <button onClick={() => panel.expandThen(() => onEdit(booking.id))}\n className=\"flex w-full items-center gap-3 px-4 py-2 text-sm hover:bg-muted/50 transition-colors\">\n <Pencil className=\"h-4 w-4 text-muted-foreground\" /> {t('agenda.contextMenu.edit')}\n </button>\n {confirming ? (\n <div className=\"flex items-center justify-between px-4 py-2\">\n <span className=\"text-xs text-destructive font-medium\">{t('agenda.appointment.deleteConfirm')}</span>\n <div className=\"flex items-center gap-1.5\">\n <button onClick={() => setConfirming(false)}\n className=\"rounded px-2 py-0.5 text-[11px] font-medium hover:bg-muted/50 transition-colors\">{t('agenda.appointment.cancel')}</button>\n <button onClick={handleDelete} disabled={deleting}\n className=\"rounded bg-destructive border border-destructive px-2 py-0.5 text-[11px] font-medium text-destructive-foreground hover:bg-destructive/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\">{deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}</button>\n </div>\n </div>\n ) : (\n <button onClick={() => setConfirming(true)}\n className=\"flex w-full items-center gap-3 px-4 py-2 text-sm hover:bg-muted/50 transition-colors text-destructive\">\n <Trash2 className=\"h-4 w-4\" /> {t('agenda.contextMenu.delete')}\n </button>\n )}\n </div>\n\n {/* Status workflow — hidden for simple events (no status capability). */}\n {config.capabilities.status && (\n <div className=\"border-t px-4 py-3\">\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.contextMenu.changeStatus')}</p>\n <div className=\"flex items-center gap-1.5\">\n {config.statuses.map((s) => {\n const available = isStatusAvailable(s, booking.startsAt)\n return (\n <StatusDot key={s.value} color={s.color} label={available ? s.label : `${s.label} ${t('agenda.contextMenu.notAvailable')}`}\n isActive={booking.status === s.value}\n disabled={!available}\n onClick={() => { if (available) { updateStatus(booking.id, s.value); panel.dismiss() } }} />\n )\n })}\n </div>\n </div>\n )}\n </>\n )}\n </FloatingPanel>\n )\n}\n","import React, { useMemo } from 'react'\nimport { formatCurrency, useTranslation, getCurrentLocale } from '@fayz-ai/core'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Mobile agenda list — a thumb-friendly, date-grouped list of upcoming items.\n// Rendered on <md viewports instead of the FullCalendar grid. Each row shows a\n// category/status dot, the title, the time, and (for finance-style events) the\n// amount. Fed straight from the store bookings so it works for any seeded app.\n// ---------------------------------------------------------------------------\n\nfunction startOfDay(d: Date): Date {\n const x = new Date(d)\n x.setHours(0, 0, 0, 0)\n return x\n}\n\nfunction timeLabel(iso: string): string {\n const d = new Date(iso)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n}\n\nexport interface AgendaMobileListProps {\n bookings: CalendarBooking[]\n statusColors: Record<string, string>\n currencyCode: string\n onSelect: (booking: CalendarBooking) => void\n /** Lets the empty state offer the one thing the screen is for. */\n onCreate?: () => void\n}\n\n/**\n * Loading state for the mobile list. Shaped like the list it replaces — a day\n * heading and a couple of rows — so the screen does not jump when real data\n * lands. A blank pane while the query runs reads as \"nothing scheduled\", which\n * is the one answer this screen must never give wrongly.\n */\nexport function AgendaMobileListSkeleton() {\n return (\n <div className=\"flex-1 space-y-5 overflow-hidden px-3 py-3\" aria-busy=\"true\" aria-live=\"polite\">\n {[0, 1].map((g) => (\n <div key={g} className=\"animate-pulse\">\n <div className=\"mb-2 ml-1 h-3 w-20 rounded bg-muted\" />\n <div className=\"space-y-1.5\">\n {[0, 1].map((r) => (\n <div key={r} className=\"flex items-center gap-3 rounded-card border border-border bg-card px-3 py-3\">\n <div className=\"h-2 w-2 shrink-0 rounded-full bg-muted\" />\n <div className=\"min-w-0 flex-1 space-y-1.5\">\n <div className=\"h-3.5 w-2/3 rounded bg-muted\" />\n <div className=\"h-3 w-12 rounded bg-muted\" />\n </div>\n <div className=\"h-3.5 w-14 shrink-0 rounded bg-muted\" />\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n\nexport function AgendaMobileList({ bookings, statusColors, currencyCode, onSelect, onCreate }: AgendaMobileListProps) {\n const t = useTranslation()\n const locale = getCurrentLocale() === 'pt-BR' ? 'pt-BR' : 'en'\n\n const groups = useMemo(() => {\n const todayStart = startOfDay(new Date()).getTime()\n const sorted = bookings\n .filter((b) => !!b.startsAt)\n .slice()\n .sort((a, b) => (a.startsAt < b.startsAt ? -1 : a.startsAt > b.startsAt ? 1 : 0))\n const map = new Map<string, CalendarBooking[]>()\n for (const b of sorted) {\n const day = startOfDay(new Date(b.startsAt))\n if (day.getTime() < todayStart) continue // upcoming only\n const key = day.toISOString().slice(0, 10)\n const list = map.get(key) ?? []\n list.push(b)\n map.set(key, list)\n }\n return Array.from(map.entries()).map(([key, items]) => ({ key, date: new Date(key + 'T00:00:00'), items }))\n }, [bookings])\n\n function dayLabel(date: Date): string {\n const today = startOfDay(new Date())\n const diff = Math.round((startOfDay(date).getTime() - today.getTime()) / 86400000)\n if (diff === 0) return t('agenda.list.today')\n if (diff === 1) return t('agenda.list.tomorrow')\n return date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long' })\n }\n\n if (groups.length === 0) {\n return (\n <div className=\"flex flex-1 flex-col items-center justify-center gap-4 px-6 py-16 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('agenda.list.empty')}</p>\n {onCreate && (\n <button\n type=\"button\"\n onClick={onCreate}\n className=\"fz-tap inline-flex items-center rounded-full bg-primary px-5 text-sm font-medium text-primary-foreground active:scale-[0.98]\"\n >\n {t('agenda.calendar.newAppointment')}\n </button>\n )}\n </div>\n )\n }\n\n return (\n <div className=\"flex-1 overflow-y-auto px-3 py-3 space-y-5\">\n {groups.map((g) => (\n <div key={g.key}>\n <h3 className=\"px-1 pb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {dayLabel(g.date)}\n </h3>\n <div className=\"space-y-1.5\">\n {g.items.map((b) => {\n const color = statusColors[b.status] ?? '#6b7280'\n const hasAmount = typeof b.orderTotal === 'number' && b.orderTotal > 0\n return (\n <button\n key={b.id}\n onClick={() => onSelect(b)}\n className=\"flex w-full items-center gap-3 rounded-card border bg-card px-3 py-2.5 text-left shadow-sm transition-colors active:bg-muted/50\"\n >\n <span className=\"h-2.5 w-2.5 shrink-0 rounded-full\" style={{ backgroundColor: color }} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-foreground\">{b.clientName ?? '—'}</p>\n <p className=\"text-xs text-muted-foreground\">{timeLabel(b.startsAt)}</p>\n </div>\n {hasAmount && (\n <span className=\"shrink-0 text-sm font-semibold tabular-nums text-foreground\">\n {formatCurrency(b.orderTotal, currencyCode)}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n ))}\n </div>\n )\n}\n","import type { EventInput } from '@fullcalendar/core'\nimport type { CalendarBooking } from '../types'\n\n/**\n * Booking → FullCalendar event. Extracted from CalendarView so the resource-lane\n * rule below is testable without mounting the grid.\n */\nexport function bookingToEvent(\n booking: CalendarBooking,\n statusColors: Record<string, string>,\n visibleResourceIds: string[] = [],\n): EventInput {\n const color = statusColors[booking.status] ?? '#6b7280'\n const serviceNames = booking.services?.map((service) => service.name).join(', ') ?? ''\n return {\n id: booking.id,\n // A tenant-wide block (an imported whole-agenda Google event, for example)\n // has no assignee. Availability treats it as busy for every professional, so\n // resource views must render it in every visible lane instead of dropping it.\n ...(booking.professionalId\n ? { resourceId: booking.professionalId }\n : visibleResourceIds.length > 0\n ? { resourceIds: visibleResourceIds }\n : {}),\n title: booking.clientName ?? 'Unknown',\n start: booking.startsAt,\n end: booking.endsAt ?? undefined,\n backgroundColor: color + '30',\n borderColor: color,\n textColor: color,\n extendedProps: { booking, serviceNames },\n }\n}\n","import React, { useRef, useEffect, useCallback, useMemo, useState } from 'react'\nimport { injectCalendarStyles } from '../styles/calendar-styles'\nimport FullCalendar from '@fullcalendar/react'\nimport dayGridPlugin from '@fullcalendar/daygrid'\nimport timeGridPlugin from '@fullcalendar/timegrid'\nimport resourceTimeGridPlugin from '@fullcalendar/resource-timegrid'\nimport interactionPlugin from '@fullcalendar/interaction'\nimport listPlugin from '@fullcalendar/list'\nimport ptBrLocale from '@fullcalendar/core/locales/pt-br'\nimport type { EventInput, EventClickArg, DateSelectArg, EventDropArg } from '@fullcalendar/core'\nimport { ChevronLeft, ChevronRight, Plus, ChevronDown, Settings } from 'lucide-react'\nimport { usePluginPrefs, PageActions } from '@fayz-ai/admin'\nimport { getCurrentLocale } from '@fayz-ai/core'\nimport { useTranslation, useDataChanged } from '@fayz-ai/core'\nimport { useAgendaConfig, useAgendaProvider, useAgendaStore } from '../context'\nimport { useAgendaSettings } from '../hooks/useAgendaSettings'\nimport { MiniCalendar } from '../components/MiniCalendar'\nimport { AppointmentModal } from '../components/AppointmentModal'\nimport { AppointmentPopover } from '../components/AppointmentPopover'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { EventContextMenu } from '../components/EventContextMenu'\nimport { AgendaMobileList, AgendaMobileListSkeleton } from '../components/AgendaMobileList'\nimport { ConfirmDialog } from '@fayz-ai/ui'\nimport { Button, PageHeaderActions } from '@fayz-ai/ui'\nimport type { CalendarBooking, Schedule } from '../types'\nimport { bookingToEvent } from '../lib/calendar-events'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Generate FullCalendar background events showing unavailable time.\n * For each day, creates background blocks for the gaps OUTSIDE working hours\n * within the visible business hours window. This grays out non-working time.\n */\nfunction generateAvailabilityEvents(\n schedules: Schedule[],\n professionals: { id: string }[],\n dateRange: { start: string; end: string } | null,\n businessHours?: { startTime: string; endTime: string },\n locationMap?: Map<string, string>,\n): EventInput[] {\n if (!dateRange || schedules.length === 0) return []\n\n const bgEvents: EventInput[] = []\n const startDate = new Date(dateRange.start)\n const endDate = new Date(dateRange.end)\n const bizStart = businessHours?.startTime ?? '08:00'\n const bizEnd = businessHours?.endTime ?? '20:00'\n\n // Group schedules by assignee\n const byAssignee = new Map<string, Schedule[]>()\n for (const s of schedules) {\n const aid = s.assigneeId\n if (!aid) continue\n const list = byAssignee.get(aid) ?? []\n list.push(s)\n byAssignee.set(aid, list)\n }\n\n function timeToMinutes(t: string): number {\n const [h, m] = t.split(':').map(Number)\n return h * 60 + m\n }\n\n function minutesToTime(m: number): string {\n return `${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`\n }\n\n const bizStartMin = timeToMinutes(bizStart)\n const bizEndMin = timeToMinutes(bizEnd)\n\n for (const prof of professionals) {\n const profSchedules = byAssignee.get(prof.id) ?? []\n\n // Separate weekly and date-specific schedules\n const weekly = profSchedules.filter((s) => s.dayOfWeek != null && !s.specificDate)\n const exceptions = profSchedules.filter((s) => s.specificDate != null)\n const exceptionDates = new Set(exceptions.map((s) => s.specificDate!))\n\n const current = new Date(startDate)\n while (current < endDate) {\n const dateStr = current.toISOString().slice(0, 10)\n const dayOfWeek = current.getDay()\n\n // Get working periods for this day\n let daySchedules: Schedule[]\n if (exceptionDates.has(dateStr)) {\n daySchedules = exceptions.filter((s) => s.specificDate === dateStr && s.isActive)\n } else {\n daySchedules = weekly.filter((s) => s.dayOfWeek === dayOfWeek && s.isActive)\n }\n\n // Convert working periods to sorted minute ranges, preserving locationId\n const workRanges = daySchedules\n .map((s) => {\n const locId = s.locationId ?? (s.metadata?.locationId as string | undefined)\n return {\n start: timeToMinutes(s.startsAt),\n end: timeToMinutes(s.endsAt),\n locationName: locId && locationMap ? locationMap.get(locId) : undefined,\n }\n })\n .sort((a, b) => a.start - b.start)\n\n // Compute unavailable gaps within business hours\n let cursor = bizStartMin\n for (const range of workRanges) {\n const availStart = Math.max(range.start, bizStartMin)\n const availEnd = Math.min(range.end, bizEndMin)\n\n // Gap before this working range = unavailable\n if (cursor < availStart) {\n bgEvents.push({\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(cursor) + ':00',\n end: dateStr + 'T' + minutesToTime(availStart) + ':00',\n display: 'background',\n classNames: ['fc-unavailable-bg'],\n })\n }\n\n // Location label on available range\n if (availStart < availEnd && range.locationName) {\n bgEvents.push({\n id: `loc-${prof.id}-${dateStr}-${minutesToTime(availStart)}`,\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(availStart) + ':00',\n end: dateStr + 'T' + minutesToTime(availStart + 20) + ':00',\n title: range.locationName,\n display: 'auto',\n editable: false,\n backgroundColor: 'transparent',\n borderColor: 'transparent',\n textColor: '#a3a3a3',\n classNames: ['fc-location-label'],\n extendedProps: { isLocationLabel: true },\n })\n }\n\n cursor = Math.max(cursor, availEnd)\n }\n\n // Gap after last working range = unavailable\n if (cursor < bizEndMin) {\n bgEvents.push({\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(cursor) + ':00',\n end: dateStr + 'T' + minutesToTime(bizEndMin) + ':00',\n display: 'background',\n classNames: ['fc-unavailable-bg'],\n })\n }\n\n\n current.setDate(current.getDate() + 1)\n }\n }\n\n return bgEvents\n}\n\n// ---------------------------------------------------------------------------\n// Loading skeleton — mimics the resource-timegrid-week layout\n// ---------------------------------------------------------------------------\n\nfunction CalendarSkeleton({ profCount = 2 }: { profCount?: number }) {\n const days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']\n const hours = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00']\n\n return (\n <div className=\"flex-1 overflow-hidden animate-pulse\">\n <div className=\"flex border-b\" style={{ paddingLeft: 56 }}>\n {Array.from({ length: profCount }).map((_, pi) => (\n <div key={pi} className=\"flex-1 border-r last:border-r-0 py-2 px-3\">\n <div className=\"flex items-center justify-center gap-2\">\n <div className=\"h-6 w-6 rounded-full bg-muted\" />\n <div className=\"h-3 w-20 rounded bg-muted\" />\n </div>\n </div>\n ))}\n </div>\n <div className=\"flex border-b\" style={{ paddingLeft: 56 }}>\n {Array.from({ length: profCount }).map((_, pi) => (\n <div key={pi} className=\"flex-1 flex border-r last:border-r-0\">\n {days.map((d) => (\n <div key={d} className=\"flex-1 py-1.5 text-center\">\n <span className=\"text-[10px] text-muted-foreground/40\">{d}</span>\n </div>\n ))}\n </div>\n ))}\n </div>\n <div className=\"relative\">\n {hours.map((h) => (\n <div key={h} className=\"flex border-b border-border/30\" style={{ height: 50 }}>\n <div className=\"w-14 shrink-0 pr-2 text-right\">\n <span className=\"text-[10px] text-muted-foreground/30\">{h}</span>\n </div>\n <div className=\"flex-1 flex\">\n {Array.from({ length: profCount * 7 }).map((_, ci) => (\n <div key={ci} className={`flex-1 border-r border-border/20 ${Math.floor(ci / 7) % 2 === 1 ? 'bg-muted/20' : ''}`} />\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\n// Resource views — one column per professional. Used when the app has staff.\nconst RESOURCE_VIEW_OPTIONS = [\n { key: 'resourceTimeGridDay', labelKey: 'agenda.calendar.viewDay' },\n { key: 'resourceTimeGridWeek', labelKey: 'agenda.calendar.viewWeek' },\n { key: 'dayGridMonth', labelKey: 'agenda.calendar.viewMonth' },\n] as const\n\n// Non-resource variants — used when there are no professionals/resources (e.g. a\n// personal-finance agenda). A resource timegrid renders an EMPTY grid with zero\n// resource columns and drops events that have no resourceId, so those apps fall\n// back to a plain month/day/week calendar.\nconst PLAIN_VIEW_OPTIONS = [\n { key: 'timeGridDay', labelKey: 'agenda.calendar.viewDay' },\n { key: 'timeGridWeek', labelKey: 'agenda.calendar.viewWeek' },\n { key: 'dayGridMonth', labelKey: 'agenda.calendar.viewMonth' },\n { key: 'listMonth', labelKey: 'agenda.calendar.viewList' },\n] as const\n\n// Sentinel view key for the thumb-friendly mobile agenda list (AgendaMobileList),\n// which is NOT a FullCalendar view. Selected by default on <md so B2C opens on the\n// list; picking any grid option (Dia/Semana/Mês) mounts the real calendar instead.\nconst MOBILE_LIST_VIEW = '__mobileList__'\nconst AGENDA_POLL_INTERVAL_MS = 30_000\nconst AGENDA_REALTIME_DEBOUNCE_MS = 300\n\n/** Collapse a resource view to a plain month calendar when there are no resources. */\nfunction viewForNoResources(view: string): string {\n return view.startsWith('resource') ? 'dayGridMonth' : view\n}\n\n/** Promote a plain timegrid to its resource variant when the app has resources. */\nfunction viewForResources(view: string): string {\n if (view === 'timeGridWeek') return 'resourceTimeGridWeek'\n if (view === 'timeGridDay') return 'resourceTimeGridDay'\n return view\n}\n\n/** Small viewport (<md) → render the thumb-friendly agenda list instead of the grid. */\nfunction useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState(() =>\n typeof window !== 'undefined' && window.matchMedia('(max-width: 767px)').matches)\n useEffect(() => {\n if (typeof window === 'undefined') return\n const mq = window.matchMedia('(max-width: 767px)')\n const onChange = () => setIsMobile(mq.matches)\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [])\n return isMobile\n}\n\n// ---------------------------------------------------------------------------\n// Calendar View\n// ---------------------------------------------------------------------------\n\nexport function CalendarView() {\n injectCalendarStyles()\n const config = useAgendaConfig()\n const provider = useAgendaProvider()\n const t = useTranslation()\n const currentLocale = getCurrentLocale()\n const fcLocale = currentLocale === 'pt-BR' ? ptBrLocale : undefined\n const calendarRef = useRef<FullCalendar>(null)\n const prefs = usePluginPrefs('agenda', { calendarView: config.defaultCalendarView ?? 'resourceTimeGridWeek' })\n const agendaSettings = useAgendaSettings()\n const effectiveBusinessHours = {\n startTime: agendaSettings.startTime,\n endTime: agendaSettings.endTime,\n }\n\n const bookings = useAgendaStore((s) => s.bookings)\n const bookingsLoading = useAgendaStore((s) => s.bookingsLoading)\n const professionals = useAgendaStore((s) => s.professionals)\n const professionalsLoading = useAgendaStore((s) => s.professionalsLoading)\n const currentView = useAgendaStore((s) => s.currentView)\n const selectedProfIds = useAgendaStore((s) => s.selectedProfessionalIds)\n const selectedStatuses = useAgendaStore((s) => s.selectedStatuses)\n const schedules = useAgendaStore((s) => s.schedules)\n const fetchBookings = useAgendaStore((s) => s.fetchBookings)\n const fetchProfessionals = useAgendaStore((s) => s.fetchProfessionals)\n const fetchLocations = useAgendaStore((s) => s.fetchLocations)\n const storeLocations = useAgendaStore((s) => s.locations)\n const fetchSchedules = useAgendaStore((s) => s.fetchSchedules)\n const rescheduleBooking = useAgendaStore((s) => s.rescheduleBooking)\n const setView = useAgendaStore((s) => s.setView)\n const setFilters = useAgendaStore((s) => s.setFilters)\n const _openModal = useAgendaStore((s) => s.openAppointmentModal)\n const closeModal = useAgendaStore((s) => s.closeAppointmentModal)\n const modalState = useAgendaStore((s) => s.appointmentModal)\n\n // Resource-capable = the app has professionals/staff. When it doesn't (e.g. a\n // personal-finance agenda), resource views render empty, so we force plain\n // (non-resource) views and default to a month calendar.\n const isMobile = useIsMobile()\n const resourceCapable = professionals.length > 0\n const viewOptions = resourceCapable ? RESOURCE_VIEW_OPTIONS : PLAIN_VIEW_OPTIONS\n\n // Mobile (<md) has its own view selection, independent of the desktop pref: it\n // defaults to the thumb-friendly list and lets the user switch to any grid view\n // (Dia/Semana/Mês) without changing the desktop's stored calendarView. The list\n // sentinel replaces FullCalendar's own listMonth so mobile always gets the rich\n // AgendaMobileList, and a list option is offered even for resource apps.\n const [mobileView, setMobileView] = useState<string>(MOBILE_LIST_VIEW)\n const mobileViewOptions = useMemo(\n () => [\n ...viewOptions.filter((o) => o.key !== 'listMonth'),\n { key: MOBILE_LIST_VIEW, labelKey: 'agenda.calendar.viewList' },\n ],\n [viewOptions],\n )\n const mobileGridActive = isMobile && mobileView !== MOBILE_LIST_VIEW\n\n const [selectedBooking, setSelectedBooking] = useState<CalendarBooking | null>(null)\n const [popoverAnchor, setPopoverAnchor] = useState<{ x: number; y: number } | null>(null)\n const [popoverVisible, _setPopoverVisible] = useState(false)\n const popoverVisibleRef = useRef(false)\n const setPopoverVisible = useCallback((v: boolean) => { popoverVisibleRef.current = v; _setPopoverVisible(v) }, [])\n const [contextMenu, setContextMenu] = useState<{ booking: CalendarBooking; x: number; y: number } | null>(null)\n const [contextMenuVisible, _setContextMenuVisible] = useState(false)\n const contextMenuVisibleRef = useRef(false)\n const setContextMenuVisible = useCallback((v: boolean) => { contextMenuVisibleRef.current = v; _setContextMenuVisible(v) }, [])\n const [scheduleConfirm, setScheduleConfirm] = useState<{ onConfirm: () => void } | null>(null)\n const [calendarTitle, setCalendarTitle] = useState('')\n const [selectedDate, setSelectedDate] = useState(new Date())\n const [profSectionOpen, setProfSectionOpen] = useState(true)\n const [statusSectionOpen, setStatusSectionOpen] = useState(false)\n const [visibleRange, setVisibleRange] = useState<{ start: string; end: string } | null>(null)\n\n // Leaving the calendar ends the booking form with it. The open flag lives in\n // the store, which outlives this screen — without this, navigating away with\n // a half-filled form and coming back reopened it, days later, still holding\n // the slot you abandoned.\n useEffect(() => () => closeModal(), [closeModal])\n\n // Wrap openModal to always dismiss popover/context menu first\n const openModal: typeof _openModal = useCallback((...args) => {\n setPopoverVisible(false); setSelectedBooking(null); setPopoverAnchor(null)\n setContextMenuVisible(false); setContextMenu(null)\n _openModal(...args)\n }, [_openModal])\n\n const statusColors = useMemo(() => {\n const map: Record<string, string> = {}\n for (const s of config.statuses) map[s.value] = s.color\n return map\n }, [config.statuses])\n\n useEffect(() => {\n fetchProfessionals(); fetchSchedules()\n if (config.modules.locationSelection) fetchLocations()\n }, [])\n\n // Keep the view consistent with resource-capability, in case a stale/shared\n // pref selected the wrong variant. No resources → a resource view is an empty\n // grid that drops the seeded events; resources → a plain timegrid loses the\n // per-professional columns.\n useEffect(() => {\n const api = calendarRef.current?.getApi()\n if (!api) return\n if (!resourceCapable && currentView.startsWith('resource')) {\n api.changeView('dayGridMonth')\n } else if (resourceCapable && (currentView === 'timeGridWeek' || currentView === 'timeGridDay')) {\n api.changeView(viewForResources(currentView))\n }\n }, [resourceCapable, currentView])\n\n // Mobile renders the agenda list (no FullCalendar), so the grid's datesSet —\n // which normally drives fetchBookings — never fires. Fetch a wide upcoming\n // window directly so the list has data.\n useEffect(() => {\n if (!isMobile) return\n const start = new Date(); start.setHours(0, 0, 0, 0); start.setDate(start.getDate() - 1)\n const end = new Date(start); end.setDate(end.getDate() + 91)\n fetchBookings({ start: start.toISOString(), end: end.toISOString() })\n }, [isMobile, fetchBookings])\n\n // A booking created outside the grid — the assistant, the public page,\n // another device — repaints the calendar it belongs to. Without this the\n // manager who just said \"agenda a Maria amanhã às 10\" still sees yesterday's\n // grid and reloads the tab by hand.\n const refreshVisibleBookings = useCallback(() => {\n if (visibleRange) {\n void fetchBookings(visibleRange)\n return\n }\n const start = new Date(); start.setHours(0, 0, 0, 0); start.setDate(start.getDate() - 1)\n const end = new Date(start); end.setDate(end.getDate() + 91)\n void fetchBookings({ start: start.toISOString(), end: end.toISOString() })\n }, [visibleRange, fetchBookings])\n\n useDataChanged({}, refreshVisibleBookings, [refreshVisibleBookings])\n\n // Writes this tab never saw — a Google webhook, another device, the public\n // booking page — arrive through the provider's realtime subscription. The\n // 30s visibility-aware poll is the net for a sleeping/disconnected socket;\n // a hidden tab does no database work, and returning to it refreshes at once.\n useEffect(() => {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n\n let refreshTimer: ReturnType<typeof setTimeout> | undefined\n let unsubscribe: (() => void) | undefined\n\n const scheduleRefresh = (delay = 0) => {\n if (document.visibilityState === 'hidden') return\n if (refreshTimer) clearTimeout(refreshTimer)\n refreshTimer = setTimeout(refreshVisibleBookings, delay)\n }\n\n try {\n unsubscribe = provider.subscribeToBookingChanges?.(() => scheduleRefresh(AGENDA_REALTIME_DEBOUNCE_MS))\n } catch (error) {\n console.warn('[agenda] Realtime unavailable; using the polling fallback.', error)\n }\n\n const pollTimer = window.setInterval(() => scheduleRefresh(), AGENDA_POLL_INTERVAL_MS)\n const onVisibilityChange = () => { if (document.visibilityState === 'visible') scheduleRefresh() }\n const onFocus = () => scheduleRefresh()\n\n document.addEventListener('visibilitychange', onVisibilityChange)\n window.addEventListener('focus', onFocus)\n\n return () => {\n if (refreshTimer) clearTimeout(refreshTimer)\n window.clearInterval(pollTimer)\n document.removeEventListener('visibilitychange', onVisibilityChange)\n window.removeEventListener('focus', onFocus)\n unsubscribe?.()\n }\n }, [provider, refreshVisibleBookings])\n\n const resources = useMemo(() => {\n const filtered = selectedProfIds.length > 0\n ? professionals.filter((p) => selectedProfIds.includes(p.id))\n : professionals\n return filtered.map((p) => ({\n id: p.id, title: p.name,\n extendedProps: { avatarUrl: p.avatarUrl, locationName: p.locationName },\n }))\n }, [professionals, selectedProfIds])\n\n const visibleResourceIds = useMemo(() => resources.map((resource) => resource.id), [resources])\n\n const bookingEvents = useMemo(() =>\n bookings.map((b) => bookingToEvent(b, statusColors, visibleResourceIds)),\n [bookings, statusColors, visibleResourceIds])\n\n // Merge static config locations with dynamically fetched locations\n const allLocations = useMemo(() => {\n const map = new Map<string, string>()\n for (const loc of config.locations) map.set(loc.id, loc.name)\n for (const loc of storeLocations) map.set(loc.id, loc.name)\n return map\n }, [config.locations, storeLocations])\n\n const locationMap = useMemo(() => {\n if (!config.modules.locationSelection || allLocations.size === 0) return undefined\n return allLocations\n }, [config.modules.locationSelection, allLocations])\n\n const availabilityEvents = useMemo(() =>\n generateAvailabilityEvents(schedules, professionals, visibleRange, effectiveBusinessHours, locationMap),\n [schedules, professionals, visibleRange, effectiveBusinessHours, locationMap])\n\n const events = useMemo(() =>\n [...bookingEvents, ...availabilityEvents], [bookingEvents, availabilityEvents])\n\n const storedView = prefs.get('calendarView')\n const effectiveInitialView = resourceCapable ? viewForResources(storedView) : viewForNoResources(storedView)\n\n // ── Calendar handlers ──\n const handleDatesSet = useCallback((arg: { startStr: string; endStr: string; view: { title: string; type: string } }) => {\n setCalendarTitle(arg.view.title)\n setView(arg.view.type)\n setVisibleRange({ start: arg.startStr, end: arg.endStr })\n fetchBookings({ start: arg.startStr, end: arg.endStr })\n }, [fetchBookings, setView])\n\n // Double-click → open edit directly\n // Right-click → context menu\n const handleEventDidMount = useCallback((arg: { event: any; el: HTMLElement }) => {\n const booking = arg.event.extendedProps?.booking as CalendarBooking | undefined\n if (booking) arg.el.setAttribute('data-booking-id', booking.id)\n arg.el.addEventListener('dblclick', (e) => {\n e.preventDefault()\n e.stopPropagation()\n skipClickRef.current = true\n const booking = arg.event.extendedProps.booking as CalendarBooking\n setSelectedBooking(null)\n setPopoverAnchor(null)\n setContextMenu(null)\n openModal('edit', { bookingId: booking.id })\n })\n arg.el.addEventListener('contextmenu', (e) => {\n e.preventDefault()\n const booking = arg.event.extendedProps.booking as CalendarBooking\n const menuW = 210, menuH = 200\n let x = e.clientX + 4\n let y = e.clientY + 4\n if (x + menuW > window.innerWidth - 12) x = x - menuW\n if (y + menuH > window.innerHeight - 12) y = y - menuH\n setContextMenu({ booking, x, y })\n setContextMenuVisible(true)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n })\n }, [])\n\n // Flag to suppress single-click after a double-click\n const skipClickRef = useRef(false)\n\n // Hover timer — show popover after 4s hover on a booking event\n const hoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const handleEventMouseEnter = useCallback((arg: { event: any; el: HTMLElement }) => {\n if (arg.event.display === 'background') return\n if (arg.event.extendedProps?.isLocationLabel) return\n const booking = arg.event.extendedProps.booking as CalendarBooking\n if (!booking) return\n\n hoverTimerRef.current = setTimeout(() => {\n const rect = arg.el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (x < 16) x = Math.max(16, rect.left + rect.width / 2 - popW / 2)\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }, 3000)\n }, [])\n\n const handleEventMouseLeave = useCallback(() => {\n if (hoverTimerRef.current) {\n clearTimeout(hoverTimerRef.current)\n hoverTimerRef.current = null\n }\n }, [])\n\n // Single click — open popover instantly, or slide to new position if already open\n const handleEventClick = useCallback((arg: EventClickArg) => {\n if (skipClickRef.current) { skipClickRef.current = false; return }\n // Ignore clicks on background availability events and location labels\n if (arg.event.display === 'background') return\n if (arg.event.extendedProps?.isLocationLabel) return\n setContextMenu(null); setContextMenuVisible(false)\n const booking = arg.event.extendedProps.booking as CalendarBooking\n if (!booking) return\n const rect = arg.el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (x < 16) x = Math.max(16, rect.left + rect.width / 2 - popW / 2)\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n // Always update — if popover is already open it slides to the new position\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }, [])\n\n // Find the schedule block covering a given time slot for a professional\n const findScheduleForSlot = useCallback((professionalId: string | undefined, dateTimeStr: string): Schedule | null => {\n if (!professionalId) return null\n const dt = new Date(dateTimeStr)\n const dateStr = dt.toISOString().slice(0, 10)\n const dayOfWeek = dt.getDay()\n const timeMin = dt.getHours() * 60 + dt.getMinutes()\n\n const profSchedules = schedules.filter((s) => s.assigneeId === professionalId)\n const exceptions = profSchedules.filter((s) => s.specificDate === dateStr && s.isActive)\n const weekly = profSchedules.filter((s) => s.dayOfWeek === dayOfWeek && s.isActive && !s.specificDate)\n const daySchedules = exceptions.length > 0 ? exceptions : weekly\n\n for (const s of daySchedules) {\n const [sh, sm] = s.startsAt.split(':').map(Number)\n const [eh, em] = s.endsAt.split(':').map(Number)\n if (timeMin >= sh * 60 + sm && timeMin < eh * 60 + em) return s\n }\n return null\n }, [schedules])\n\n const handleSelect = useCallback((arg: DateSelectArg) => {\n calendarRef.current?.getApi().unselect()\n\n // Don't open create if popover/context menu is showing — dismiss them instead\n if (popoverVisibleRef.current || contextMenuVisibleRef.current) {\n setPopoverVisible(false); setSelectedBooking(null); setPopoverAnchor(null)\n setContextMenuVisible(false); setContextMenu(null)\n return\n }\n\n const professionalId = arg.resource?.id\n const schedule = findScheduleForSlot(professionalId, arg.startStr)\n\n const proceed = () => {\n const locId = schedule?.locationId ?? (schedule?.metadata?.locationId as string | undefined)\n openModal('create', { prefill: { startsAt: arg.startStr, endsAt: arg.endStr, professionalId, locationId: locId || undefined } })\n }\n\n // Warn if no schedule covers this slot — only when the working-hours module\n // is on (off by default in eventMode:'simple', so simple/Google-Calendar\n // events never surface the \"no open schedule for this professional\" dialog).\n if (config.modules.workingHours && !schedule) {\n setScheduleConfirm({ onConfirm: proceed })\n return\n }\n\n proceed()\n }, [openModal, findScheduleForSlot, config.modules.workingHours])\n\n const handleEventDrop = useCallback(async (arg: EventDropArg) => {\n const booking = arg.event.extendedProps.booking as CalendarBooking\n try { await rescheduleBooking(booking.id, arg.event.startStr, arg.event.endStr, arg.newResource?.id ?? undefined) }\n catch { arg.revert() }\n }, [rescheduleBooking])\n\n const handleViewChange = useCallback((v: string) => {\n calendarRef.current?.getApi().changeView(v)\n prefs.set('calendarView', v)\n }, [prefs])\n // Mobile switcher: swap between the list sentinel and a real grid view. When a\n // grid is picked we also sync the store's currentView so the resource-collapse\n // effect doesn't fight the freshly-mounted mobile calendar; if it's already\n // mounted (grid → grid), changeView animates in place.\n const handleMobileViewChange = useCallback((v: string) => {\n setMobileView(v)\n if (v === MOBILE_LIST_VIEW) return\n setView(v)\n calendarRef.current?.getApi()?.changeView(v)\n }, [setView])\n const handlePrev = useCallback(() => calendarRef.current?.getApi().prev(), [])\n const handleNext = useCallback(() => calendarRef.current?.getApi().next(), [])\n const handleToday = useCallback(() => { calendarRef.current?.getApi().today(); setSelectedDate(new Date()) }, [])\n\n function handleMiniDateSelect(date: Date) {\n setSelectedDate(date)\n calendarRef.current?.getApi().gotoDate(date)\n }\n\n function toggleProfessional(id: string) {\n const next = selectedProfIds.includes(id)\n ? selectedProfIds.filter((p) => p !== id)\n : [...selectedProfIds, id]\n setFilters({ professionalIds: next })\n }\n\n function toggleStatus(value: string) {\n const next = selectedStatuses.includes(value)\n ? selectedStatuses.filter((s) => s !== value)\n : [...selectedStatuses, value]\n setFilters({ statuses: next })\n }\n\n // Alternating resource backgrounds — apply via DOM after render\n const wrapperRef = useRef<HTMLDivElement>(null)\n\n // FullCalendar measures its columns once and only re-measures on a WINDOW\n // resize. Opening/closing the assistant rail (or the sidebar) resizes the\n // container without one, so the grid stayed locked at the narrow width until\n // a real window resize came along. Watch the container and hand FC the new box.\n useEffect(() => {\n const container = wrapperRef.current\n if (!container) return\n let frame = 0\n let lastWidth = container.clientWidth\n let lastHeight = container.clientHeight\n const ro = new ResizeObserver(() => {\n const width = container.clientWidth\n const height = container.clientHeight\n if (width === lastWidth && height === lastHeight) return\n lastWidth = width\n lastHeight = height\n // Next frame, not inline: measuring inside the observer callback reads a\n // mid-layout box (and trips the RO loop warning). The rail animates, so\n // this fires on each frame and the last one settles on the final width.\n cancelAnimationFrame(frame)\n frame = requestAnimationFrame(() => calendarRef.current?.getApi()?.updateSize())\n })\n ro.observe(container)\n return () => { cancelAnimationFrame(frame); ro.disconnect() }\n // Re-attach whenever the calendar branch remounts (skeleton → grid, mobile\n // list → grid), since the observed node is gone on the other branches.\n }, [isMobile, mobileGridActive, professionalsLoading, professionals.length])\n\n // Responsive day headers — collapse weekday names to a single initial (S M T\n // W T F S, Google-Calendar style) when day columns get too narrow. Measured\n // from the actual rendered column width so it adapts to resource count + view.\n const [dayHeaderCompact, setDayHeaderCompact] = useState(false)\n useEffect(() => {\n const container = wrapperRef.current\n if (!container) return\n let frame = 0\n const measure = () => {\n // Measure an actual DAY column ([data-date]) — in resource views the first\n // .fc-col-header-cell is the wide resource header, not a day column.\n const cell = container.querySelector('.fc-col-header-cell[data-date]') as HTMLElement | null\n if (!cell) return\n const colWidth = cell.getBoundingClientRect().width\n // Collapse to single-letter ONLY when the full weekday label can't fit.\n // Measure the widest full line (\"WED\" / \"12/14\") in the header's font so\n // the breakpoint adapts to font + locale instead of a magic number.\n const cushion = (cell.querySelector('.fc-col-header-cell-cushion') as HTMLElement | null) ?? cell\n const cs = getComputedStyle(cushion)\n const probe = document.createElement('span')\n probe.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;top:-9999px'\n probe.style.fontSize = cs.fontSize\n probe.style.fontWeight = cs.fontWeight\n probe.style.fontFamily = cs.fontFamily\n probe.style.letterSpacing = cs.letterSpacing\n probe.style.textTransform = cs.textTransform\n document.body.appendChild(probe)\n probe.textContent = 'Wed'\n const weekdayWidth = probe.getBoundingClientRect().width\n probe.textContent = '12/14'\n const dateWidth = probe.getBoundingClientRect().width\n probe.remove()\n const needed = Math.max(weekdayWidth, dateWidth) + 12 // text + cushion padding\n setDayHeaderCompact(colWidth < needed)\n }\n // FullCalendar reflows its inner day columns on a later tick than the\n // container resize, so re-measure across a few frames to read settled widths.\n const timers: ReturnType<typeof setTimeout>[] = []\n const schedule = () => {\n cancelAnimationFrame(frame)\n frame = requestAnimationFrame(measure)\n timers.forEach(clearTimeout)\n timers.length = 0\n timers.push(setTimeout(measure, 130), setTimeout(measure, 330))\n }\n schedule()\n const ro = new ResizeObserver(schedule)\n ro.observe(container)\n return () => { cancelAnimationFrame(frame); timers.forEach(clearTimeout); ro.disconnect() }\n }, [resources, currentView, visibleRange])\n\n const applyResourceStriping = useCallback(() => {\n const container = wrapperRef.current\n if (!container) return\n const resourceIds = resources.map((r: { id: string }) => r.id)\n if (resourceIds.length < 2) return\n container.querySelectorAll('[data-resource-id]').forEach((el: Element) => {\n const rid = el.getAttribute('data-resource-id')\n const idx = rid ? resourceIds.indexOf(rid) : -1\n el.classList.toggle('fc-resource-alt', idx % 2 === 1)\n })\n }, [resources])\n\n useEffect(() => {\n applyResourceStriping()\n const t1 = setTimeout(applyResourceStriping, 100)\n const t2 = setTimeout(applyResourceStriping, 300)\n return () => { clearTimeout(t1); clearTimeout(t2) }\n }, [applyResourceStriping, currentView, visibleRange, bookings])\n\n // Listen for cross-plugin booking open requests (e.g., from financial invoice detail)\n useEffect(() => {\n function handleOpenBooking(e: Event) {\n const detail = (e as CustomEvent).detail ?? {}\n const externalSource = detail.source\n ? { type: String(detail.source), id: detail.waitlistId, waitlistId: detail.waitlistId }\n : undefined\n if (detail.bookingId) {\n openModal('edit', { bookingId: detail.bookingId, externalSource })\n return\n }\n openModal('create', {\n prefill: detail.prefill ?? {\n clientId: detail.clientId,\n professionalId: detail.professionalId,\n locationId: detail.locationId,\n startsAt: detail.startsAt,\n },\n externalSource,\n })\n }\n window.addEventListener('agenda:open-booking', handleOpenBooking)\n return () => window.removeEventListener('agenda:open-booking', handleOpenBooking)\n }, [openModal])\n\n // Custom day header: weekday + date stacked. When columns get narrow it\n // collapses the weekday to a single initial (S / 16, Google-Calendar style).\n // Always returns explicit content — returning undefined renders an EMPTY\n // header in the React adapter rather than falling back to the default.\n const dayHeaderContent = useCallback((arg: any) => {\n const date: Date = arg.date\n const dateLocale = currentLocale === 'pt-BR' ? 'pt-BR' : 'en'\n // Inline styles (not CSS classes) so stacking is guaranteed regardless of\n // the runtime style-injection state.\n const wrapStyle: React.CSSProperties = { display: 'flex', flexDirection: 'column', alignItems: 'center', lineHeight: 1.15 }\n const dateStyle: React.CSSProperties = { fontSize: '0.65rem', opacity: 0.75 }\n if (dayHeaderCompact) {\n const letter = date.toLocaleDateString(dateLocale, { weekday: 'narrow' })\n return (\n <div style={wrapStyle}>\n <span style={{ fontWeight: 600 }}>{letter}</span>\n <span style={dateStyle}>{date.getDate()}</span>\n </div>\n )\n }\n const weekday = date.toLocaleDateString(dateLocale, { weekday: 'short' })\n return (\n <div style={wrapStyle}>\n <span>{weekday}</span>\n <span style={dateStyle}>{`${date.getMonth() + 1}/${date.getDate()}`}</span>\n </div>\n )\n }, [dayHeaderCompact, currentLocale])\n\n const resourceLabelContent = useCallback((arg: any) => {\n const { id, title, extendedProps } = arg.resource\n const initials = title.split(' ').map((n: string) => n[0]).join('').slice(0, 2)\n return (\n <div className=\"flex items-center gap-2 px-2 py-1.5\">\n <div className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary/10 text-[10px] font-bold text-primary\">{initials}</div>\n <div className=\"min-w-0\">\n <PersonLink\n personId={id}\n name={title}\n size=\"sm\"\n tab=\"schedule\"\n profileHref={`#/registry/staff/${id}/schedule`}\n />\n {extendedProps?.locationName && <p className=\"text-[10px] text-muted-foreground truncate\">{extendedProps.locationName}</p>}\n </div>\n </div>\n )\n }, [])\n\n const eventContent = useCallback((arg: any) => {\n // Location label events — render as a small tag\n if (arg.event.extendedProps?.isLocationLabel) {\n return (\n <div className=\"px-1.5 py-0.5 overflow-hidden\">\n <p className=\"text-[10px] font-medium truncate\">{arg.event.title}</p>\n </div>\n )\n }\n const serviceNames = arg.event.extendedProps?.serviceNames\n const start = arg.event.start\n const end = arg.event.end\n const fmt = (d: Date) => `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n const timeRange = start && end ? `${fmt(start)} – ${fmt(end)}` : start ? fmt(start) : ''\n return (\n <div className=\"px-1.5 py-0.5 overflow-hidden leading-tight h-full\">\n <div className=\"flex items-start justify-between gap-1\">\n <p className=\"text-[11px] font-semibold truncate\">{arg.event.title}</p>\n {serviceNames && <p className=\"text-[10px] opacity-60 truncate shrink-0 max-w-[45%] text-right\">{serviceNames}</p>}\n </div>\n {timeRange && <p className=\"text-[9px] opacity-50\">{timeRange}</p>}\n </div>\n )\n }, [])\n\n return (\n <div className=\"flex h-[calc(100vh-7.5rem)]\">\n {/* ═══ LEFT SIDEBAR — hidden on mobile ═══ */}\n <div className=\"hidden md:flex w-[220px] shrink-0 flex-col overflow-y-auto py-4 px-3 mr-4\">\n {/* + Create button */}\n <button\n onClick={() => openModal('create')}\n className=\"flex items-center gap-2 rounded-button bg-primary text-primary-foreground border border-primary pl-3 pr-4 py-1.5 text-sm font-semibold hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-all mb-6 w-fit\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('agenda.sidebar.create')}\n </button>\n\n {/* Mini month calendar */}\n <MiniCalendar selectedDate={selectedDate} onDateSelect={handleMiniDateSelect} />\n\n {/* Agendas (professional filter) — hidden when no booking type uses a\n professional (e.g. eventMode:'simple'). */}\n {config.capabilities.professional && (<>\n <div className=\"h-px bg-border my-4\" />\n\n <button onClick={() => setProfSectionOpen((p) => !p)}\n className=\"flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors\">\n <span>Agendas</span>\n <ChevronDown className={`h-3.5 w-3.5 transition-transform ${profSectionOpen ? '' : '-rotate-90'}`} />\n </button>\n {profSectionOpen && (\n <div className=\"mt-1.5 space-y-0.5\">\n {professionals.map((prof) => {\n const active = selectedProfIds.length === 0 || selectedProfIds.includes(prof.id)\n return (\n <label key={prof.id} className=\"flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors\">\n <span className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors ${\n active ? 'border-primary bg-primary' : 'border-muted-foreground/30'\n }`}>\n {active && <svg className=\"h-2.5 w-2.5 text-primary-foreground\" viewBox=\"0 0 12 12\" fill=\"none\"><path d=\"M2 6l3 3 5-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>}\n </span>\n <span className={`text-xs truncate ${active ? 'text-foreground' : 'text-muted-foreground'}`}>{prof.name}</span>\n <input type=\"checkbox\" className=\"sr-only\" checked={active} onChange={() => toggleProfessional(prof.id)} />\n </label>\n )\n })}\n </div>\n )}\n </>)}\n\n {/* Status filter — hidden when no booking type uses a status workflow\n (e.g. eventMode:'simple'). */}\n {config.capabilities.status && (<>\n <div className=\"h-px bg-border my-4\" />\n\n <button onClick={() => setStatusSectionOpen((p) => !p)}\n className=\"flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors\">\n <span>Status</span>\n <ChevronDown className={`h-3.5 w-3.5 transition-transform ${statusSectionOpen ? '' : '-rotate-90'}`} />\n </button>\n {statusSectionOpen && (\n <div className=\"mt-1.5 space-y-0.5\">\n {config.statuses.map((st) => {\n const active = selectedStatuses.length === 0 || selectedStatuses.includes(st.value)\n return (\n <label key={st.value} className=\"flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors\">\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors\"\n style={{ borderColor: active ? st.color : st.color + '40', backgroundColor: active ? st.color : 'transparent' }}>\n {active && <svg className=\"h-2.5 w-2.5 text-white\" viewBox=\"0 0 12 12\" fill=\"none\"><path d=\"M2 6l3 3 5-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>}\n </span>\n <span className={`text-xs ${active ? 'text-foreground' : 'text-muted-foreground'}`}>{st.label}</span>\n <input type=\"checkbox\" className=\"sr-only\" checked={active} onChange={() => toggleStatus(st.value)} />\n </label>\n )\n })}\n </div>\n )}\n </>)}\n </div>\n\n {/* On a phone these two lived in a toolbar row of their own, which left a\n near-empty 48px band under a bar that was already naming the screen.\n The shell's page header has the room and is where every other screen\n puts its actions. */}\n {/* Declared, so the shell decides where they go: a caret on desktop, the\n FAB on a phone. As raw buttons they were a row of their own under a bar\n that already named the screen. */}\n {isMobile && (\n <PageHeaderActions>\n <PageActions\n actions={[\n {\n id: 'new-booking',\n label: t('agenda.calendar.newAppointment'),\n icon: Plus,\n intent: 'primary',\n creates: true,\n onSelect: () => openModal('create'),\n },\n {\n id: 'agenda-settings',\n label: t('agenda.settings.title'),\n icon: Settings,\n // Utility, not an alternative way to book: the shell gives it\n // its own quiet circle above the \"+\" instead of hiding it in a\n // create menu.\n intent: 'utility',\n onSelect: () => { window.location.hash = '/settings/agenda' },\n },\n ]}\n />\n </PageHeaderActions>\n )}\n\n {/* ═══ MAIN AREA ═══ */}\n <div className=\"flex-1 flex flex-col min-w-0 overflow-hidden\">\n {/* Toolbar */}\n <div className=\"shrink-0 border-b\">\n {/* Row 1 — create + date nav + title (left), desktop switcher + settings\n (right). Extra right padding on mobile clears the transparent header's\n floating profile avatar, which otherwise overlaps the settings gear. */}\n <div className={`${mobileGridActive ? 'flex' : 'hidden'} md:flex h-12 items-center justify-between pl-4 pr-4`}>\n <div className=\"flex items-center gap-3 min-w-0\">\n {/* Date navigation drives the FullCalendar api — shown on desktop and,\n on mobile, only when a grid view is active (the list paginates\n itself, so it has no grid to page through). */}\n <div className={`${mobileGridActive ? 'flex' : 'hidden'} md:flex items-center gap-3`}>\n <button onClick={handleToday}\n className=\"rounded-md border px-3 py-1 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">\n {t('agenda.toolbar.today')}\n </button>\n <div className=\"flex items-center gap-0.5\">\n <button onClick={handlePrev} className=\"flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <button onClick={handleNext} className=\"flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {/* On a phone the shell's page bar already says \"Agenda\"; repeating\n it here cost a line and said nothing. The date range is the one\n thing that bar cannot know, so a grid view still shows it. */}\n {!(isMobile && !mobileGridActive) && (\n <h2 className=\"truncate text-base font-normal sm:text-lg\">{calendarTitle}</h2>\n )}\n </div>\n\n <div className=\"flex items-center gap-1 shrink-0\">\n <div className=\"hidden md:flex items-center gap-1\">\n {viewOptions.map((opt) => (\n <button key={opt.key} onClick={() => handleViewChange(opt.key)}\n className={`rounded-md px-3 py-1 text-sm transition-colors ${\n currentView === opt.key\n ? 'bg-primary/10 text-primary font-medium'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}>\n {t(opt.labelKey)}\n </button>\n ))}\n </div>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => window.location.hash = '/settings/agenda'}\n aria-label={t('agenda.settings.title')}\n title={t('agenda.settings.title')}\n className=\"ml-1 hidden md:inline-flex\"\n >\n <Settings className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Row 2 (mobile only) — compact segmented view switcher on its own row so\n it never collides with the floating avatar. Dia/Semana/Mês mount the\n calendar; Lista returns to the thumb-friendly agenda list. */}\n <div className=\"flex md:hidden items-center gap-1 overflow-x-auto px-3 pb-2\">\n {mobileViewOptions.map((opt) => (\n <button key={opt.key} onClick={() => handleMobileViewChange(opt.key)}\n aria-pressed={mobileView === opt.key}\n className={`flex min-h-[2.75rem] shrink-0 items-center rounded-full px-4 text-sm transition-colors active:scale-[0.98] ${\n mobileView === opt.key\n ? 'bg-primary/10 font-medium text-primary'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}>\n {t(opt.labelKey)}\n </button>\n ))}\n </div>\n </div>\n\n {/* Mobile list view → thumb-friendly agenda list; otherwise (desktop, or a\n mobile grid view the user switched to) → FullCalendar grid. */}\n {isMobile && !mobileGridActive ? (\n // The mobile branch used to sit in front of the loading check, so the\n // list rendered empty while the query ran — which on this screen reads\n // as \"nothing scheduled\", the one wrong answer it must not give.\n bookingsLoading && bookings.length === 0 ? (\n <AgendaMobileListSkeleton />\n ) : (\n <AgendaMobileList\n bookings={bookings}\n statusColors={statusColors}\n currencyCode={config.currency.code}\n onSelect={(b) => openModal('edit', { bookingId: b.id })}\n onCreate={() => openModal('create')}\n />\n )\n ) : professionalsLoading && professionals.length === 0 ? (\n <CalendarSkeleton profCount={2} />\n ) : (\n <div ref={wrapperRef} className=\"flex-1 overflow-hidden agenda-calendar\">\n <FullCalendar\n ref={calendarRef}\n plugins={[dayGridPlugin, timeGridPlugin, resourceTimeGridPlugin, interactionPlugin, listPlugin]}\n initialView={mobileGridActive ? mobileView : effectiveInitialView}\n schedulerLicenseKey=\"CC-Attribution-NonCommercial-NoDerivatives\"\n resources={resourceCapable ? resources : undefined}\n events={events}\n headerToolbar={false}\n locale={fcLocale}\n height=\"100%\"\n slotMinTime={effectiveBusinessHours.startTime + ':00'}\n slotMaxTime={effectiveBusinessHours.endTime + ':00'}\n slotDuration={{ minutes: config.slotDuration }}\n allDaySlot={false}\n nowIndicator={true}\n editable={config.modules.dragAndDrop}\n selectable={true}\n selectMirror={true}\n eventOverlap={false}\n datesSet={handleDatesSet}\n eventDidMount={handleEventDidMount}\n eventClick={handleEventClick}\n eventMouseEnter={handleEventMouseEnter}\n eventMouseLeave={handleEventMouseLeave}\n select={handleSelect}\n eventDrop={handleEventDrop}\n resourceLabelContent={resourceLabelContent}\n dayHeaderContent={dayHeaderContent}\n eventContent={eventContent}\n resourceOrder=\"title\"\n stickyHeaderDates={true}\n expandRows={false}\n eventTimeFormat={{ hour: '2-digit', minute: '2-digit', hour12: false }}\n slotLabelFormat={{ hour: '2-digit', minute: '2-digit', hour12: false }}\n />\n </div>\n )}\n </div>\n\n {/* Popover — stays mounted until animation finishes */}\n {selectedBooking && popoverAnchor && popoverVisible && (\n <AppointmentPopover booking={selectedBooking} position={popoverAnchor}\n onClose={() => {\n // Called AFTER the popover's exit animation finishes\n setPopoverVisible(false)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n }}\n onEdit={(id) => {\n setPopoverVisible(false)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n openModal('edit', { bookingId: id })\n }} />\n )}\n\n {/* Context Menu */}\n {contextMenu && (\n <EventContextMenu\n booking={contextMenu.booking}\n position={{ x: contextMenu.x, y: contextMenu.y }}\n onClose={() => { setContextMenuVisible(false); setContextMenu(null) }}\n onEdit={(id) => { setContextMenuVisible(false); setContextMenu(null); openModal('edit', { bookingId: id }) }}\n />\n )}\n\n {/* No-schedule confirm */}\n <ConfirmDialog\n open={!!scheduleConfirm}\n variant=\"warning\"\n title={t('agenda.calendar.noScheduleConfirm')}\n confirmLabel={t('common.confirm')}\n cancelLabel={t('common.cancel')}\n onConfirm={() => { const cb = scheduleConfirm?.onConfirm; setScheduleConfirm(null); cb?.() }}\n onCancel={() => setScheduleConfirm(null)}\n />\n\n {/* Booking form — always mounted; it shows itself in the shell's right\n column (or a sheet, where there is no column) */}\n <AppointmentModal\n open={modalState.open}\n mode={modalState.mode}\n bookingId={modalState.bookingId}\n prefill={modalState.prefill}\n initialTab={modalState.initialTab}\n externalSource={modalState.externalSource}\n onClose={closeModal}\n onCreated={(newId, source) => {\n if (config.onBookingCreated) {\n void Promise.resolve(config.onBookingCreated({ bookingId: newId, source })).catch((error: unknown) => {\n console.error('Failed to run agenda booking-created bridge', error)\n })\n }\n // After a short delay (let calendar re-render), find the event and show popover\n setTimeout(() => {\n const booking = bookings.find((b: CalendarBooking) => b.id === newId)\n if (!booking) return\n const el = document.querySelector(`[data-booking-id=\"${newId}\"]`) as HTMLElement | null\n if (el) {\n const rect = el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }\n }, 400)\n }} />\n </div>\n )\n}\n","let t: string | undefined\nexport function setAgendaTenantId(id: string | undefined){ t = id }\nexport function getAgendaTenantId(): string | undefined { return t }\n","import React from 'react'\nimport { usePluginRuntimeOptional } from '@fayz-ai/core'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { AgendaContextProvider } from '../context'\nimport type { ResolvedAgendaConfig } from '../config'\nimport type { AgendaDataProvider } from '../data/types'\nimport type { AgendaUIState } from '../store'\nimport { CalendarView } from './CalendarView'\nimport { setAgendaTenantId } from '../lib/tenant'\n\n// ---------------------------------------------------------------------------\n// Main page — clean single-page calendar, no module nav wrapper\n// ---------------------------------------------------------------------------\n\nexport function AgendaPage({ config, provider, store }: {\n config: ResolvedAgendaConfig\n provider: AgendaDataProvider\n store: StoreApi<AgendaUIState>\n}) {\n const runtime = usePluginRuntimeOptional()\n const tenantId = runtime?.context.tenant?.id\n\n React.useEffect(() => {\n setAgendaTenantId(tenantId)\n return () => setAgendaTenantId(undefined)\n }, [tenantId])\n\n return (\n <AgendaContextProvider config={config} provider={provider} store={store}>\n <CalendarView />\n </AgendaContextProvider>\n )\n}\n","import type { AgendaDataProvider } from './types'\nimport type {\n CalendarBooking, Professional, Schedule, TimeSlot,\n CreateBookingInput, UpdateBookingInput, SaveScheduleInput,\n BookingQuery, ConflictCheckParams, AvailableSlotsParams, BookingStatus,\n} from '../types'\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { getAgendaTenantId } from '../lib/tenant'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getTenantId(): string | undefined {\n // Plugin-local override wins; else fall back to the app's active tenant so\n // writes stamp the right tenant_id and pass orders/bookings RLS.\n return getAgendaTenantId() ?? getActiveTenantId()\n}\n\nfunction snakeToCamel(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n result[key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = value\n }\n return result\n}\n\nfunction getClients() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n // Core v1 lives in PUBLIC — a single client serves both core and view reads.\n return { core: supabase, pub: supabase }\n}\n\nfunction mapBooking(row: Record<string, unknown>): CalendarBooking {\n return snakeToCamel(row) as unknown as CalendarBooking\n}\n\nfunction mapSchedule(row: Record<string, unknown>): Schedule {\n return snakeToCamel(row) as unknown as Schedule\n}\n\nfunction addMinutes(iso: string, minutes: number): string {\n const d = new Date(iso)\n d.setMinutes(d.getMinutes() + minutes)\n return d.toISOString()\n}\n\nfunction unique(values: Array<string | null | undefined>): string[] {\n return Array.from(new Set(values.filter((value): value is string => !!value)))\n}\n\nfunction indexById(rows: any[] | null | undefined): Map<string, any> {\n return new Map((rows ?? []).filter((row) => row?.id).map((row) => [row.id, row]))\n}\n\nfunction groupBy<T>(rows: T[], getKey: (row: T) => string | null | undefined): Map<string, T[]> {\n const grouped = new Map<string, T[]>()\n for (const row of rows) {\n const key = getKey(row)\n if (!key) continue\n grouped.set(key, [...(grouped.get(key) ?? []), row])\n }\n return grouped\n}\n\nfunction getDurationMinutes(startsAt: string, endsAt: string | null | undefined): number | null {\n if (!endsAt) return null\n return Math.round((new Date(endsAt).getTime() - new Date(startsAt).getTime()) / 60000)\n}\n\nfunction mergeBookings(viewBookings: CalendarBooking[], canonicalBookings: CalendarBooking[]): CalendarBooking[] {\n const canonicalIds = new Set(canonicalBookings.map((booking) => booking.id))\n const canonicalOrderIds = new Set(canonicalBookings.map((booking) => booking.orderId).filter(Boolean))\n const merged = [\n ...canonicalBookings,\n ...viewBookings.filter((booking) => {\n if (canonicalIds.has(booking.id)) return false\n if (booking.orderId && canonicalOrderIds.has(booking.orderId)) return false\n if (canonicalOrderIds.has(booking.id)) return false\n return true\n }),\n ]\n\n return merged.sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n}\n\nasync function hydrateCanonicalBookings(core: any, bookings: any[]): Promise<CalendarBooking[]> {\n const personIds = unique(bookings.flatMap((booking) => [booking.party_id, booking.assignee_id]))\n const locationIds = unique(bookings.map((booking) => booking.location_id))\n const orderIds = unique(bookings.map((booking) => booking.order_id))\n const bookingIds = unique(bookings.map((booking) => booking.id))\n\n const [\n { data: persons, error: personsError },\n { data: locations, error: locationsError },\n { data: orders, error: ordersError },\n { data: items, error: itemsError },\n ] = await Promise.all([\n personIds.length\n ? core.from('people').select('id, name, phone, email, avatar_url').in('id', personIds)\n : Promise.resolve({ data: [], error: null }),\n locationIds.length\n ? core.from('locations').select('id, name').in('id', locationIds)\n : Promise.resolve({ data: [], error: null }),\n orderIds.length\n ? core.from('orders').select('id, total, status').in('id', orderIds)\n : Promise.resolve({ data: [], error: null }),\n orderIds.length\n ? core.from('order_items').select('id, order_id, service_id, name, duration_minutes, unit_price, assignee_id, sort_order').in('order_id', orderIds)\n : Promise.resolve({ data: [], error: null }),\n ])\n\n if (personsError) throw personsError\n if (locationsError) throw locationsError\n if (ordersError) throw ordersError\n if (itemsError) throw itemsError\n\n const personsById = indexById(persons)\n const locationsById = indexById(locations)\n const ordersById = indexById(orders)\n // S4: line items come from order_items (single source), keyed by order_id.\n const itemsByOrderId = groupBy(items ?? [], (item: any) => item.order_id)\n\n return bookings.map((booking) => {\n const client = booking.party_id ? personsById.get(booking.party_id) : null\n const professional = booking.assignee_id ? personsById.get(booking.assignee_id) : null\n const location = booking.location_id ? locationsById.get(booking.location_id) : null\n const order = booking.order_id ? ordersById.get(booking.order_id) : null\n const bookingItems = ((booking.order_id ? itemsByOrderId.get(booking.order_id) : null) ?? [])\n .sort((a: any, b: any) => (a.sort_order ?? 0) - (b.sort_order ?? 0))\n .map((item: any) => ({\n id: item.id,\n serviceId: item.service_id,\n name: item.name,\n durationMinutes: item.duration_minutes,\n price: item.unit_price,\n assigneeId: item.assignee_id,\n }))\n const itemDuration = bookingItems.reduce((sum: number, item: any) => sum + (item.durationMinutes ?? 0), 0)\n\n return {\n id: booking.id,\n tenantId: booking.tenant_id,\n kind: booking.kind,\n startsAt: booking.starts_at,\n endsAt: booking.ends_at,\n status: booking.status,\n notes: booking.notes,\n orderId: booking.order_id,\n locationId: booking.location_id,\n metadata: booking.metadata ?? {},\n clientId: booking.party_id,\n // Simple events (no party) fall back to the title stored in metadata;\n // partyless blocks/tasks (e.g. imported Google events) get their notes or\n // a kind label so the calendar never renders an unnamed chip.\n clientName: client?.name\n ?? (booking.metadata?.title as string | undefined)\n ?? (booking.kind === 'appointment'\n ? null\n : booking.notes || (booking.kind === 'task' ? 'Tarefa' : 'Bloqueio')),\n clientPhone: client?.phone ?? null,\n clientEmail: client?.email ?? null,\n clientAvatarUrl: client?.avatar_url ?? null,\n professionalId: booking.assignee_id,\n professionalName: professional?.name ?? null,\n professionalAvatarUrl: professional?.avatar_url ?? null,\n locationName: location?.name ?? null,\n orderTotal: order?.total ?? null,\n orderStatus: order?.status ?? null,\n services: bookingItems.length ? bookingItems : null,\n totalDurationMinutes: itemDuration || getDurationMinutes(booking.starts_at, booking.ends_at),\n createdAt: booking.created_at,\n updatedAt: booking.updated_at,\n } satisfies CalendarBooking\n })\n}\n\nasync function getCanonicalBookings(core: any, query: BookingQuery): Promise<CalendarBooking[]> {\n let q = core.from('appointments')\n .select('id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at')\n .gte('starts_at', query.dateRange.start)\n .lte('starts_at', query.dateRange.end)\n\n if (query.kind) q = q.eq('kind', query.kind)\n if (query.statuses?.length) q = q.in('status', query.statuses)\n if (query.professionalIds?.length) q = q.in('assignee_id', query.professionalIds)\n if (query.locationId) q = q.eq('location_id', query.locationId)\n\n const { data, error } = await q.order('starts_at', { ascending: true })\n if (error) throw error\n return hydrateCanonicalBookings(core, data ?? [])\n}\n\nasync function getCanonicalBookingById(core: any, id: string): Promise<CalendarBooking | null> {\n const columns = 'id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, created_at, updated_at'\n let { data, error } = await core.from('appointments').select(columns).eq('id', id).maybeSingle()\n if (error) throw error\n\n if (!data) {\n const fallback = await core.from('appointments').select(columns).eq('order_id', id).maybeSingle()\n if (fallback.error) throw fallback.error\n data = fallback.data\n }\n\n if (!data) return null\n const [booking] = await hydrateCanonicalBookings(core, [data])\n return booking ?? null\n}\n\n// ---------------------------------------------------------------------------\n// Supabase Agenda Provider\n// ---------------------------------------------------------------------------\n\nexport interface SupabaseAgendaProviderOptions {\n /** people.kind used for calendar resources/professionals (default 'staff' — schools use 'teacher'). */\n professionalKind?: string\n}\n\nlet bookingChangesChannelSequence = 0\n\nexport function createSupabaseAgendaProvider(providerOptions?: SupabaseAgendaProviderOptions): AgendaDataProvider {\n const professionalKind = providerOptions?.professionalKind ?? 'staff'\n return {\n subscribeToBookingChanges(onChange) {\n const { core } = getClients()\n const tenantId = getTenantId() ?? 'active'\n const channelName = `agenda:appointments:${tenantId}:${++bookingChangesChannelSequence}`\n const channel = core\n .channel(channelName)\n .on('postgres_changes', { event: '*', schema: 'public', table: 'appointments' }, onChange)\n .subscribe()\n\n // No tenant_id filter on purpose: RLS already scopes Postgres Changes to\n // the caller's tenants, and Supabase cannot filter DELETE events. The\n // callback only refetches — it never trusts the payload.\n return () => { void core.removeChannel(channel) }\n },\n\n // v_appointments is in public schema (PostgREST default)\n async getBookings(query: BookingQuery): Promise<CalendarBooking[]> {\n const { core, pub } = getClients()\n let q = pub.from('v_appointments').select('*')\n .gte('starts_at', query.dateRange.start)\n .lte('starts_at', query.dateRange.end)\n\n if (query.kind) q = q.eq('kind', query.kind)\n if (query.statuses?.length) q = q.in('status', query.statuses)\n if (query.professionalIds?.length) q = q.in('professional_id', query.professionalIds)\n if (query.locationId) q = q.eq('location_id', query.locationId)\n\n q = q.order('starts_at', { ascending: true })\n\n const { data, error } = await q\n if (error) throw error\n const viewBookings = (data ?? []).map(mapBooking)\n const canonicalBookings = await getCanonicalBookings(core, query)\n return mergeBookings(viewBookings, canonicalBookings)\n },\n\n async getBookingById(id: string): Promise<CalendarBooking | null> {\n const { core, pub } = getClients()\n const { data, error } = await pub.from('v_appointments').select('*').eq('id', id).maybeSingle()\n if (error) throw error\n if (data) {\n const booking = mapBooking(data as Record<string, unknown>)\n // v_appointments is a FLAT read model — it exposes no line items. The\n // calendar list path merges in the canonical hydration (which carries\n // `services` from order_items), but this single-record lookup used by the\n // edit modal previously returned the bare view row. That dropped\n // `services`, so a booking whose type has `requiresServices` reopened with\n // an empty service list and kept the \"Update\" button permanently disabled\n // (canSubmit stayed false). Hydrate the line items here to stay consistent\n // with getBookings.\n if (booking.orderId) {\n const { data: items } = await core.from('order_items')\n .select('id, service_id, name, duration_minutes, unit_price, assignee_id, sort_order')\n .eq('order_id', booking.orderId)\n .order('sort_order', { ascending: true })\n if (items && items.length) {\n const services = items.map((item: any) => ({\n id: item.id,\n serviceId: item.service_id,\n name: item.name,\n durationMinutes: item.duration_minutes,\n price: item.unit_price,\n assigneeId: item.assignee_id,\n }))\n booking.services = services\n const itemDuration = services.reduce((sum: number, s: any) => sum + (s.durationMinutes ?? 0), 0)\n if (itemDuration) booking.totalDurationMinutes = itemDuration\n }\n }\n return booking\n }\n return getCanonicalBookingById(core, id)\n },\n\n async createBooking(input: CreateBookingInput): Promise<CalendarBooking> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('No active tenant')\n\n const hasServices = input.services.length > 0\n const totalDuration = input.services.reduce((sum, s) => sum + s.durationMinutes, 0)\n const totalPrice = input.services.reduce((sum, s) => sum + s.price, 0)\n const endsAt = addMinutes(input.startsAt, totalDuration || 30)\n const serviceNames = input.services.map((s: any) => s.name).join(', ')\n\n // Resolve client name for metadata (used by financial detail view)\n let contactName: string | undefined\n if (input.clientId) {\n const { data: person } = await core.from('people').select('name').eq('id', input.clientId).single()\n contactName = person?.name as string | undefined\n }\n\n // Simple / Google-Calendar-style events have no client party — persist the\n // free-text title in metadata so the read model can surface it as the name.\n const eventTitle = input.title?.trim() || undefined\n\n const { data: order, error: orderErr } = await core.from('orders').insert({\n tenant_id: tenantId,\n kind: input.kind ?? 'appointment',\n status: 'scheduled',\n party_id: input.clientId || null,\n assignee_id: input.professionalId || null,\n location_id: input.locationId ?? null,\n subtotal: totalPrice,\n total: totalPrice,\n notes: input.notes ?? null,\n metadata: {\n source: 'agenda',\n ...(serviceNames ? { serviceNames, itemsSummary: serviceNames } : {}),\n ...(contactName ? { contactName } : {}),\n ...(eventTitle ? { title: eventTitle } : {}),\n },\n }).select('id').single()\n if (orderErr) throw orderErr\n\n const { data: booking, error: bookingErr } = await core.from('appointments').insert({\n tenant_id: tenantId,\n kind: input.kind ?? 'appointment',\n party_id: input.clientId || null,\n assignee_id: input.professionalId || null,\n location_id: input.locationId ?? null,\n order_id: order.id,\n starts_at: input.startsAt,\n ends_at: endsAt,\n status: 'scheduled',\n notes: input.notes ?? null,\n metadata: {\n source: 'agenda',\n ...(serviceNames ? { serviceNames, itemsSummary: serviceNames } : {}),\n ...(contactName ? { contactName } : {}),\n ...(eventTitle ? { title: eventTitle } : {}),\n },\n }).select('id').single()\n if (bookingErr) throw bookingErr\n\n if (hasServices) {\n // S4: line items live ONLY in order_items now (booking_items deprecated).\n const orderItems = input.services.map((s, i) => ({\n order_id: order.id,\n service_id: s.serviceId,\n name: s.name,\n quantity: 1,\n unit_price: s.price,\n total: s.price,\n sort_order: i,\n duration_minutes: s.durationMinutes,\n assignee_id: s.assigneeId || input.professionalId || null,\n }))\n const { error: oiErr } = await core.from('order_items').insert(orderItems)\n if (oiErr) throw oiErr\n }\n\n const createdBooking = await this.getBookingById(booking.id)\n if (!createdBooking) throw new Error('Created booking did not resolve from agenda read model')\n return createdBooking\n },\n\n async updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking> {\n const { core } = getClients()\n const { data: existing, error: existingErr } = await core.from('appointments')\n .select('id, order_id, starts_at, assignee_id, metadata')\n .eq('id', id)\n .single()\n if (existingErr) throw existingErr\n\n const updates: Record<string, unknown> = {}\n if (data.startsAt) updates.starts_at = data.startsAt\n if (data.endsAt) updates.ends_at = data.endsAt\n // Simple-event title lives in metadata (no client party) — merge, don't clobber.\n if (data.title !== undefined) {\n updates.metadata = { ...(existing?.metadata as Record<string, unknown> ?? {}), title: data.title }\n }\n if (data.status) {\n // Only update the agenda status — never touch the financial stage\n updates.status = data.status\n }\n if (data.notes !== undefined) updates.notes = data.notes\n if (data.professionalId) updates.assignee_id = data.professionalId\n if (data.clientId) updates.party_id = data.clientId\n if (data.locationId) updates.location_id = data.locationId\n\n // Recalculate totals when services are updated\n if (data.services) {\n const totalDuration = data.services.reduce((s, svc) => s + svc.durationMinutes, 0)\n const totalPrice = data.services.reduce((s, svc) => s + svc.price, 0)\n // Recalculate ends_at from startsAt + total duration\n const startsAt = data.startsAt ?? (existing?.starts_at as string | undefined)\n if (startsAt) {\n const ends = new Date(new Date(startsAt).getTime() + totalDuration * 60000)\n updates.ends_at = ends.toISOString()\n }\n }\n\n const effectiveAssigneeId = data.professionalId ?? (existing?.assignee_id as string | null | undefined) ?? null\n\n const { error } = await core.from('appointments').update(updates).eq('id', id)\n if (error) throw error\n\n // S4: services are updated only in order_items below (booking_items deprecated).\n const orderId = existing?.order_id as string | null | undefined\n if (orderId) {\n const orderUpdates: Record<string, unknown> = {}\n if (data.notes !== undefined) orderUpdates.notes = data.notes\n if (data.professionalId) orderUpdates.assignee_id = data.professionalId\n if (data.clientId) orderUpdates.party_id = data.clientId\n if (data.locationId) orderUpdates.location_id = data.locationId\n\n if (data.services) {\n const totalPrice = data.services.reduce((s, svc) => s + svc.price, 0)\n orderUpdates.subtotal = totalPrice\n orderUpdates.total = totalPrice\n }\n\n if (Object.keys(orderUpdates).length > 0) {\n const { error: orderErr } = await core.from('orders').update(orderUpdates).eq('id', orderId)\n if (orderErr) throw orderErr\n }\n\n if (data.services) {\n await core.from('order_items').delete().eq('order_id', orderId)\n if (data.services.length > 0) {\n const items = data.services.map((svc, idx) => ({\n order_id: orderId,\n service_id: svc.serviceId || null,\n name: svc.name,\n quantity: 1,\n unit_price: svc.price,\n total: svc.price,\n sort_order: idx,\n duration_minutes: svc.durationMinutes,\n assignee_id: svc.assigneeId ?? effectiveAssigneeId,\n }))\n const { error: itemErr } = await core.from('order_items').insert(items)\n if (itemErr) throw itemErr\n }\n }\n }\n\n return (await this.getBookingById(id))!\n },\n\n async deleteBooking(id: string): Promise<void> {\n const { core, pub } = getClients()\n const { data: booking, error: bookingErr } = await core.from('appointments')\n .select('order_id')\n .eq('id', id)\n .single()\n if (bookingErr) throw bookingErr\n\n const orderId = booking?.order_id as string | null | undefined\n // Financial movements live in the financial plugin's tables. Pools that\n // don't provision that plugin (e.g. school/event agendas) have no\n // plg_financial_movements table, and the probe below returns a PostgREST\n // \"relation does not exist\" error. Previously that error was rethrown,\n // which aborted the ENTIRE delete — the modal caught it and left the\n // booking in place, so \"Delete\" looked like a silent no-op (works in\n // beauty, which has the table; fails in school, which doesn't). Treat any\n // probe failure as \"no linked movements\" and fall through to a plain delete.\n let movementCount = 0\n if (orderId) {\n const { count, error: movementErr } = await pub\n .from('plg_financial_movements')\n .select('id', { count: 'exact', head: true })\n .eq('invoice_id', orderId)\n if (!movementErr) movementCount = count ?? 0\n }\n\n if (orderId && movementCount > 0) {\n // Cancel movements + order (don't delete financial records)\n await pub.from('plg_financial_movements').update({ status: 'cancelled' }).eq('invoice_id', orderId)\n await core.from('orders').update({ status: 'cancelled' }).eq('id', orderId)\n const { error } = await core.from('appointments').update({ status: 'cancelled' }).eq('id', id)\n if (error) throw error\n } else {\n // Safe to delete — remove any movements first (FK constraint)\n if (orderId) {\n await pub.from('plg_financial_movements').delete().eq('invoice_id', orderId)\n }\n const { error } = await core.from('appointments').delete().eq('id', id)\n if (error) throw error\n if (orderId) {\n const { error: orderErr } = await core.from('orders').delete().eq('id', orderId)\n if (orderErr) throw orderErr\n }\n }\n },\n\n async updateBookingStatus(id: string, status: string): Promise<CalendarBooking> {\n return this.updateBooking(id, { status: status as BookingStatus })\n },\n\n async checkConflict(params: ConflictCheckParams): Promise<boolean> {\n const { core } = getClients()\n let q = core.from('appointments').select('id', { count: 'exact', head: true })\n .eq('assignee_id', params.assigneeId)\n .eq('kind', 'appointment')\n .not('status', 'in', '(\"cancelled\",\"no_show\")')\n .not('starts_at', 'is', null)\n .lt('starts_at', params.endsAt)\n .gt('ends_at', params.startsAt)\n\n if (params.excludeBookingId) {\n q = q.neq('id', params.excludeBookingId)\n }\n\n const { count, error } = await q\n if (error) throw error\n return (count ?? 0) > 0\n },\n\n async getAvailableSlots(params: AvailableSlotsParams): Promise<TimeSlot[]> {\n const { pub } = getClients()\n const { data, error } = await pub.rpc('get_available_slots', {\n p_tenant_id: getTenantId(),\n p_assignee_id: params.assigneeId,\n p_date: params.date,\n p_duration_minutes: params.durationMinutes,\n p_slot_interval: params.slotInterval ?? 30,\n })\n if (error) throw error\n return (data ?? []).map((row: any) => ({ start: row.slot_start, end: row.slot_end }))\n },\n\n async getSchedules(professionalId?: string): Promise<Schedule[]> {\n const { core } = getClients()\n let q = core.from('schedules').select('*').eq('kind', 'working_hours')\n if (professionalId) q = q.eq('assignee_id', professionalId)\n q = q.order('day_of_week').order('starts_at')\n\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(mapSchedule)\n },\n\n async saveSchedule(input: SaveScheduleInput): Promise<Schedule> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('No active tenant')\n\n const { data, error } = await core.from('schedules').insert({\n tenant_id: tenantId,\n kind: 'working_hours',\n assignee_id: input.assigneeId,\n location_id: input.locationId ?? null,\n day_of_week: input.dayOfWeek ?? null,\n specific_date: input.specificDate ?? null,\n starts_at: input.startsAt,\n ends_at: input.endsAt,\n is_active: input.isActive !== false,\n metadata: input.metadata ?? {},\n }).select('*').single()\n if (error) throw error\n return mapSchedule(data as Record<string, unknown>)\n },\n\n async deleteSchedule(id: string): Promise<void> {\n const { core } = getClients()\n const { error } = await core.from('schedules').delete().eq('id', id)\n if (error) throw error\n },\n\n async getProfessionals(): Promise<Professional[]> {\n const { core } = getClients()\n const base = () => core.from('people')\n .select('id, name, avatar_url, is_active')\n .eq('kind', professionalKind)\n .eq('is_active', true)\n\n // Trabalhar aqui não é atender cliente. Desde que todo login ganha ficha,\n // o contador e o administrador entram em `people` com o mesmo kind de\n // quem atende — e sem este filtro viram coluna na grade semanal, com\n // horário livre para alguém marcar em cima.\n let { data, error } = await base().eq('is_bookable', true).order('name')\n\n // Pool que ainda não recebeu a coluna responde 42703. Voltar sem o filtro\n // é a resposta certa: lá o problema não existe (ninguém tem ficha de\n // login), e derrubar a agenda inteira por causa de uma coluna que falta\n // seria trocar um incômodo por uma tela quebrada.\n if (error && (error as any).code === '42703') {\n ;({ data, error } = await base().order('name'))\n }\n if (error) throw error\n return (data ?? []).map((p: any) => ({\n id: p.id, name: p.name, avatarUrl: p.avatar_url,\n locationId: null, locationName: null, isActive: p.is_active,\n }))\n },\n\n async getLocations(): Promise<Array<{ id: string; name: string }>> {\n const { core } = getClients()\n const { data, error } = await core.from('locations')\n .select('id, name')\n .eq('is_active', true)\n .order('name')\n if (error) throw error\n return (data ?? []).map((l: any) => ({ id: l.id, name: l.name }))\n },\n\n async getConfirmationsPending(daysAhead = 2): Promise<CalendarBooking[]> {\n const { pub } = getClients()\n const now = new Date().toISOString()\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() + daysAhead)\n\n const { data, error } = await pub.from('v_appointments').select('*')\n .eq('status', 'scheduled')\n .gte('starts_at', now)\n .lte('starts_at', cutoff.toISOString())\n .order('starts_at')\n if (error) throw error\n return (data ?? []).map(mapBooking)\n },\n\n async sendConfirmation(bookingId: string, channel: string): Promise<void> {\n const { core } = getClients()\n const { data: booking } = await core.from('appointments').select('metadata').eq('id', bookingId).single()\n const metadata = (booking?.metadata ?? {}) as Record<string, unknown>\n const confirmations = (metadata.confirmations as any[] ?? [])\n confirmations.push({ channel, sentAt: new Date().toISOString(), status: 'sent' })\n await core.from('appointments').update({ metadata: { ...metadata, confirmations } }).eq('id', bookingId)\n },\n\n async completeBooking(bookingId: string): Promise<{ booking: CalendarBooking; orderId: string }> {\n const { core } = getClients()\n const { data: existing, error: existingErr } = await core.from('appointments')\n .select('order_id')\n .eq('id', bookingId)\n .single()\n if (existingErr) throw existingErr\n\n const { error } = await core.from('appointments')\n .update({ status: 'completed' })\n .eq('id', bookingId)\n if (error) throw error\n\n const orderId = existing?.order_id as string | null | undefined\n const booking = await this.getBookingById(bookingId)\n if (!booking) throw new Error('Booking not found')\n return { booking, orderId: orderId ?? bookingId }\n },\n }\n}\n","import { emitDomainEvent, getActiveTenantId } from '@fayz-ai/core'\nimport { getAgendaTenantId } from './tenant'\nimport type { CalendarBooking } from '../types'\n\n// Emissores dos fatos declarados em message-events.ts. `agenda.booking_reminder`\n// não tem emissor de propósito: a véspera é disparada por agendador no servidor.\n\nconst STATUS_EVENT: Record<string, string> = {\n cancelled: 'agenda.booking_cancelled',\n completed: 'agenda.booking_completed',\n no_show: 'agenda.booking_no_show',\n}\n\n/** O evento específico de uma transição de status, se ela tiver um. */\nexport function bookingStatusEventKey(status: string): string | undefined {\n return STATUS_EVENT[status]\n}\n\n// Data e hora no formato dos exemplos do catálogo: '12/08/2026', '14:30'.\nfunction bookingPayload(booking: CalendarBooking): Record<string, unknown> {\n const starts = new Date(booking.startsAt)\n return {\n customer_name: booking.clientName ?? '',\n // O destino do WhatsApp, exatamente como está na ficha do cliente — máscara,\n // DDD solto, o que houver. Normalizar é trabalho de quem envia\n // (normalizeBrPhoneToE164), e adivinhar aqui só criaria uma quinta versão da\n // mesma regra. Vazio quando a ficha não tem telefone: a automação pula, e um\n // envio pulado é melhor que um envio para o número de outra pessoa.\n customer_phone: booking.clientPhone ?? '',\n service_name: (booking.services ?? []).map((s) => s.name).join(' + '),\n professional_name: booking.professionalName ?? '',\n booking_date: starts.toLocaleDateString('pt-BR'),\n booking_time: starts.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }),\n location_name: booking.locationName ?? '',\n }\n}\n\nexport function emitBookingEvent(key: string, booking: CalendarBooking): void {\n emitDomainEvent(key, bookingPayload(booking), {\n tenantId: booking.tenantId || getAgendaTenantId() || getActiveTenantId() || null,\n subject: { type: 'booking', id: booking.id },\n })\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { emitDataChanged } from '@fayz-ai/core'\nimport { dedup } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport { getScheduleBlockConfig, setScheduleBlockConfig } from '@fayz-ai/admin'\nimport type { AgendaDataProvider } from './data/types'\nimport { bookingStatusEventKey, emitBookingEvent } from './lib/booking-events'\nimport type { AgendaFinancialBridge } from './bridges/financial-bridge'\nimport type { ExternalBookingSource } from './config'\nimport type {\n CalendarBooking, Professional, Schedule,\n CreateBookingInput, UpdateBookingInput, BookingQuery,\n} from './types'\n\n// ---------------------------------------------------------------------------\n// Store state\n// ---------------------------------------------------------------------------\n\nexport interface AgendaUIState {\n // Calendar data\n bookings: CalendarBooking[]\n bookingsLoading: boolean\n dateRange: { start: string; end: string }\n currentView: string\n selectedDate: string\n\n // Resources\n professionals: Professional[]\n professionalsLoading: boolean\n\n // Filters\n selectedProfessionalIds: string[]\n selectedLocationId: string | null\n selectedStatuses: string[]\n\n // Locations\n locations: Array<{ id: string; name: string }>\n\n // Schedules\n schedules: Schedule[]\n schedulesLoading: boolean\n\n // Confirmations\n pendingConfirmations: CalendarBooking[]\n confirmationsLoading: boolean\n\n // Modal state\n appointmentModal: {\n open: boolean\n mode: 'create' | 'edit'\n bookingId?: string\n prefill?: Partial<CreateBookingInput> & { endsAt?: string }\n initialTab?: string\n externalSource?: ExternalBookingSource\n }\n\n // Actions\n fetchBookings(range: { start: string; end: string }): Promise<void>\n fetchProfessionals(): Promise<void>\n fetchLocations(): Promise<void>\n fetchSchedules(professionalId?: string): Promise<void>\n fetchConfirmations(): Promise<void>\n createBooking(input: CreateBookingInput): Promise<CalendarBooking>\n updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking>\n deleteBooking(id: string): Promise<void>\n updateBookingStatus(id: string, status: string): Promise<void>\n rescheduleBooking(id: string, newStart: string, newEnd: string, newProfessionalId?: string): Promise<void>\n setFilters(filters: Partial<{ professionalIds: string[]; locationId: string | null; statuses: string[] }>): void\n setView(view: string): void\n setSelectedDate(date: string): void\n openAppointmentModal(mode: 'create' | 'edit', options?: { bookingId?: string; prefill?: Partial<CreateBookingInput> & { endsAt?: string }; initialTab?: string; externalSource?: ExternalBookingSource }): void\n closeAppointmentModal(): void\n}\n\n// ---------------------------------------------------------------------------\n// Store factory\n// ---------------------------------------------------------------------------\n\nfunction getCurrentBookingQuery(state: AgendaUIState, dateRange = state.dateRange): BookingQuery {\n return {\n dateRange,\n professionalIds: state.selectedProfessionalIds.length ? state.selectedProfessionalIds : undefined,\n locationId: state.selectedLocationId ?? undefined,\n statuses: state.selectedStatuses.length ? state.selectedStatuses : undefined,\n }\n}\n\nexport function createAgendaStore(provider: AgendaDataProvider, financialBridge?: AgendaFinancialBridge): StoreApi<AgendaUIState> {\n return createStore<AgendaUIState>((set, get) => ({\n bookings: [],\n bookingsLoading: false,\n dateRange: { start: '', end: '' },\n currentView: 'resourceTimeGridDay',\n selectedDate: new Date().toISOString().slice(0, 10),\n\n professionals: [],\n professionalsLoading: false,\n\n selectedProfessionalIds: [],\n selectedLocationId: null,\n selectedStatuses: ['scheduled', 'confirmed', 'in_progress', 'completed'],\n\n locations: [],\n\n schedules: [],\n schedulesLoading: false,\n\n pendingConfirmations: [],\n confirmationsLoading: false,\n\n appointmentModal: { open: false, mode: 'create' },\n\n async fetchBookings(range) {\n const key = `agenda:bookings:${range.start}:${range.end}`\n return dedup(key, async () => {\n set({ bookingsLoading: true, dateRange: range })\n const state = get()\n const query = getCurrentBookingQuery(state, range)\n let bookings = await provider.getBookings(query)\n\n // Enrich with payment status if financial bridge is available\n if (financialBridge) {\n const orderIds = bookings.map((b) => b.orderId).filter((id): id is string => !!id)\n if (orderIds.length > 0) {\n try {\n const statuses = await financialBridge.resolvePaymentStatuses(orderIds)\n bookings = bookings.map((b) => {\n if (!b.orderId) return b\n const summary = statuses.get(b.orderId)\n return summary ? { ...b, paymentStatus: summary.status } : b\n })\n } catch { /* non-blocking */ }\n }\n }\n\n set({ bookings, bookingsLoading: false })\n })\n },\n\n async fetchProfessionals() {\n return dedup('agenda:professionals', async () => {\n set({ professionalsLoading: true })\n const professionals = await provider.getProfessionals()\n set({ professionals, professionalsLoading: false })\n })\n },\n\n async fetchLocations() {\n return dedup('agenda:locations', async () => {\n if (!provider.getLocations) return\n const locations = await provider.getLocations()\n set({ locations })\n // Update global schedule block config so ScheduleEditor picks up locations\n const current = getScheduleBlockConfig()\n if (current) {\n setScheduleBlockConfig({ ...current, locations })\n }\n })\n },\n\n async fetchSchedules(professionalId) {\n return dedup('agenda:schedules:' + (professionalId ?? 'all'), async () => {\n set({ schedulesLoading: true })\n const schedules = await provider.getSchedules(professionalId)\n set({ schedules, schedulesLoading: false })\n })\n },\n\n async fetchConfirmations() {\n return dedup('agenda:confirmations', async () => {\n set({ confirmationsLoading: true })\n const pendingConfirmations = await provider.getConfirmationsPending()\n set({ pendingConfirmations, confirmationsLoading: false })\n })\n },\n\n async createBooking(input) {\n try {\n const booking = await provider.createBooking(input)\n emitBookingEvent('agenda.booking_created', booking)\n // Refresh bookings for current range\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'create', id: booking.id, source: 'ui' })\n toast.success('Appointment created')\n return booking\n } catch (err: any) {\n toast.error('Failed to create appointment', { description: err?.message })\n throw err\n }\n },\n\n async updateBooking(id, data) {\n try {\n const prev = get().bookings.find((b) => b.id === id)\n const booking = await provider.updateBooking(id, data)\n // Um fato por salvamento: transição de status ganha o evento específico;\n // senão, mudança de horário é remarcação.\n const statusKey = prev && booking.status !== prev.status ? bookingStatusEventKey(booking.status) : undefined\n if (statusKey) {\n emitBookingEvent(statusKey, booking)\n } else if (prev && new Date(booking.startsAt).getTime() !== new Date(prev.startsAt).getTime()) {\n emitBookingEvent('agenda.booking_rescheduled', booking)\n }\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })\n toast.success('Appointment updated')\n return booking\n } catch (err: any) {\n toast.error('Failed to update appointment', { description: err?.message })\n throw err\n }\n },\n\n async deleteBooking(id) {\n try {\n await provider.deleteBooking(id)\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'delete', id, source: 'ui' })\n toast.success('Appointment deleted')\n } catch (err: any) {\n toast.error('Failed to delete appointment', { description: err?.message })\n throw err\n }\n },\n\n async updateBookingStatus(id, status) {\n // Optimistic update — change color immediately\n const prev = get().bookings\n const prevStatus = prev.find((b) => b.id === id)?.status\n set({ bookings: prev.map((b) => b.id === id ? { ...b, status: status as any } : b) })\n try {\n const updated = await provider.updateBookingStatus(id, status)\n // Só na transição real — reaplicar o mesmo status não é um fato novo.\n const key = prevStatus !== status ? bookingStatusEventKey(status) : undefined\n if (key) emitBookingEvent(key, updated)\n // Refresh from server to get full data\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })\n toast.success('Status updated')\n } catch (err: any) {\n // Rollback on failure\n set({ bookings: prev })\n toast.error('Failed to update status', { description: err?.message })\n throw err\n }\n },\n\n async rescheduleBooking(id, newStart, newEnd, newProfessionalId) {\n try {\n // Check for conflicts\n const existing = get().bookings.find((b) => b.id === id)\n const assigneeId = newProfessionalId ?? existing?.professionalId\n if (assigneeId) {\n const hasConflict = await provider.checkConflict({\n assigneeId,\n startsAt: newStart,\n endsAt: newEnd,\n excludeBookingId: id,\n })\n if (hasConflict) {\n toast.error('Time conflict detected', { description: 'This professional already has an appointment at this time.' })\n throw new Error('Time conflict')\n }\n }\n const updated = await provider.updateBooking(id, {\n startsAt: newStart,\n endsAt: newEnd,\n ...(newProfessionalId && { professionalId: newProfessionalId }),\n })\n emitBookingEvent('agenda.booking_rescheduled', updated)\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n toast.success('Appointment rescheduled')\n } catch (err: any) {\n if (err?.message !== 'Time conflict') {\n toast.error('Failed to reschedule', { description: err?.message })\n }\n throw err\n }\n },\n\n setFilters(filters) {\n set({\n ...(filters.professionalIds !== undefined && { selectedProfessionalIds: filters.professionalIds }),\n ...(filters.locationId !== undefined && { selectedLocationId: filters.locationId }),\n ...(filters.statuses !== undefined && { selectedStatuses: filters.statuses }),\n })\n // Re-fetch with new filters\n const { dateRange } = get()\n if (dateRange.start && dateRange.end) {\n get().fetchBookings(dateRange)\n }\n },\n\n setView(view) { set({ currentView: view }) },\n setSelectedDate(date) { set({ selectedDate: date }) },\n\n openAppointmentModal(mode, options) {\n set({ appointmentModal: { open: true, mode, bookingId: options?.bookingId, prefill: options?.prefill, initialTab: options?.initialTab, externalSource: options?.externalSource } })\n },\n\n closeAppointmentModal() {\n // Only toggle open — keep mode/bookingId/prefill intact so layout\n // doesn't shift during the close animation\n set((state) => ({ appointmentModal: { ...state.appointmentModal, open: false } }))\n },\n }))\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Holidays (public.holidays — tenant-scoped)\n// ---------------------------------------------------------------------------\n\nconst holidayEntity: EntityDef = {\n name: 'Holiday',\n namePlural: 'Holidays',\n icon: 'TreePalm',\n displayField: 'name',\n defaultSort: 'date',\n defaultSortDir: 'asc',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'date', label: 'Date', type: 'date', required: true, showInTable: true, sortable: true },\n { key: 'recurring', label: 'Recurring Annually', type: 'boolean', showInTable: true, defaultValue: false },\n { key: 'description', label: 'Description', type: 'text', showInTable: false },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: {\n table: 'holidays',\n tenantScoped: true,\n },\n}\n\nexport const agendaRegistries: PluginRegistryDef[] = [\n {\n id: 'holidays',\n entity: holidayEntity,\n icon: 'TreePalm',\n description: 'Non-working days and recurring holidays',\n },\n]\n","import React from 'react'\nimport { SettingsGroup, ToggleRow, SelectRow, useTenantPluginSettings } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useAgendaSettings } from '../hooks/useAgendaSettings'\n\nconst HOUR_OPTIONS = Array.from({ length: 18 }, (_, i) => {\n const h = (5 + i).toString().padStart(2, '0')\n return { value: `${h}:00`, label: `${h}:00` }\n})\n\n// Per-tenant toggle defaults = the values that used to be hardcoded here.\n// NOTE: these are persisted + re-hydrated per tenant; actually consuming them to\n// change agenda behaviour is a follow-up (see useTenantPluginSettings docs).\nconst AGENDA_TOGGLE_DEFAULTS = {\n conflictDetection: true,\n dragDrop: true,\n autoCreateOrder: true,\n enableLocation: false,\n enableWorkingHours: true,\n blockOutside: false,\n enableConfirmations: true,\n autoConfirm: false,\n reminder: true,\n showCancelled: false,\n showNoShow: true,\n compact: false,\n newBookingNotif: true,\n cancelAlerts: true,\n noShowTracking: false,\n}\n\nexport function AgendaGeneralSettings() {\n const t = useTranslation()\n const { startTime, endTime, setStartTime, setEndTime } = useAgendaSettings()\n const s = useTenantPluginSettings('agenda', AGENDA_TOGGLE_DEFAULTS)\n return (\n <div className=\"space-y-4\">\n <SettingsGroup title={t('agenda.settings.scheduling')} description={t('agenda.settings.schedulingDesc')}>\n <ToggleRow label={t('agenda.settings.conflictDetection')} description={t('agenda.settings.conflictDetectionDesc')} checked={s.get('conflictDetection')} onChange={(v) => s.set('conflictDetection', v)} />\n <ToggleRow label={t('agenda.settings.dragDrop')} description={t('agenda.settings.dragDropDesc')} checked={s.get('dragDrop')} onChange={(v) => s.set('dragDrop', v)} />\n <ToggleRow label={t('agenda.settings.autoCreateOrder')} description={t('agenda.settings.autoCreateOrderDesc')} checked={s.get('autoCreateOrder')} onChange={(v) => s.set('autoCreateOrder', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.locations')} description={t('agenda.settings.locationsDesc')}>\n <ToggleRow label={t('agenda.settings.enableLocation')} description={t('agenda.settings.enableLocationDesc')} checked={s.get('enableLocation')} onChange={(v) => s.set('enableLocation', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.workingHours')} description={t('agenda.settings.workingHoursDesc')}>\n <ToggleRow label={t('agenda.settings.enableWorkingHours')} description={t('agenda.settings.enableWorkingHoursDesc')} checked={s.get('enableWorkingHours')} onChange={(v) => s.set('enableWorkingHours', v)} />\n <ToggleRow label={t('agenda.settings.blockOutside')} description={t('agenda.settings.blockOutsideDesc')} checked={s.get('blockOutside')} onChange={(v) => s.set('blockOutside', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.confirmations')} description={t('agenda.settings.confirmationsDesc')}>\n <ToggleRow label={t('agenda.settings.enableConfirmations')} description={t('agenda.settings.enableConfirmationsDesc')} checked={s.get('enableConfirmations')} onChange={(v) => s.set('enableConfirmations', v)} />\n <ToggleRow label={t('agenda.settings.autoConfirm')} description={t('agenda.settings.autoConfirmDesc')} checked={s.get('autoConfirm')} onChange={(v) => s.set('autoConfirm', v)} />\n <ToggleRow label={t('agenda.settings.reminder')} description={t('agenda.settings.reminderDesc')} checked={s.get('reminder')} onChange={(v) => s.set('reminder', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.calendarDisplay')} description={t('agenda.settings.calendarDisplayDesc')}>\n <SelectRow\n label={t('agenda.settings.dayStartTime')}\n description={t('agenda.settings.dayStartTimeDesc')}\n value={startTime}\n options={HOUR_OPTIONS}\n onChange={setStartTime}\n />\n <SelectRow\n label={t('agenda.settings.dayEndTime')}\n description={t('agenda.settings.dayEndTimeDesc')}\n value={endTime}\n options={HOUR_OPTIONS}\n onChange={setEndTime}\n />\n <ToggleRow label={t('agenda.settings.showCancelled')} description={t('agenda.settings.showCancelledDesc')} checked={s.get('showCancelled')} onChange={(v) => s.set('showCancelled', v)} />\n <ToggleRow label={t('agenda.settings.showNoShow')} description={t('agenda.settings.showNoShowDesc')} checked={s.get('showNoShow')} onChange={(v) => s.set('showNoShow', v)} />\n <ToggleRow label={t('agenda.settings.compact')} description={t('agenda.settings.compactDesc')} checked={s.get('compact')} onChange={(v) => s.set('compact', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.notifications')} description={t('agenda.settings.notificationsDesc')}>\n <ToggleRow label={t('agenda.settings.newBookingNotif')} description={t('agenda.settings.newBookingNotifDesc')} checked={s.get('newBookingNotif')} onChange={(v) => s.set('newBookingNotif', v)} />\n <ToggleRow label={t('agenda.settings.cancelAlerts')} description={t('agenda.settings.cancelAlertsDesc')} checked={s.get('cancelAlerts')} onChange={(v) => s.set('cancelAlerts', v)} />\n <ToggleRow label={t('agenda.settings.noShowTracking')} description={t('agenda.settings.noShowTrackingDesc')} checked={s.get('noShowTracking')} onChange={(v) => s.set('noShowTracking', v)} />\n </SettingsGroup>\n </div>\n )\n}\n","// agenda.* — merged plugin-own + saas-core central i18n\nexport const en: Record<string, string> = {\n \"agenda.appointment.addDescription\": \"Add description...\",\n \"agenda.appointment.addService\": \"Add service\",\n \"agenda.appointment.cancel\": \"Cancel\",\n \"agenda.appointment.clientTab\": \"Client\",\n \"agenda.appointment.noClientData\": \"No client data available\",\n \"agenda.appointment.client\": \"Client\",\n \"agenda.appointment.conflict\": \"Time conflict — this professional is already booked at this time.\",\n \"agenda.appointment.create\": \"Create\",\n \"agenda.appointment.createClientFailed\": \"Failed to create client\",\n \"agenda.appointment.creating\": \"Creating...\",\n \"agenda.appointment.delete\": \"Delete\",\n \"agenda.appointment.deleteConfirm\": \"Delete this appointment?\",\n \"agenda.appointment.confirmDelete\": \"Delete\",\n \"agenda.appointment.deleting\": \"Deleting…\",\n \"agenda.appointment.edit\": \"Edit Appointment\",\n \"agenda.appointment.emailOptional\": \"Email (optional)\",\n \"agenda.appointment.location\": \"Location\",\n \"agenda.appointment.name\": \"Name\",\n \"agenda.appointment.new\": \"New Appointment\",\n \"agenda.appointment.newClient\": \"New client\",\n \"agenda.appointment.required\": \"Required\",\n \"agenda.appointment.newService\": \"New service\",\n \"agenda.appointment.notes\": \"Notes\",\n \"agenda.appointment.phone\": \"Phone\",\n \"agenda.appointment.professional\": \"Professional\",\n \"agenda.appointment.save\": \"Save\",\n \"agenda.appointment.saving\": \"Saving...\",\n \"agenda.appointment.searchClient\": \"Search client...\",\n \"agenda.appointment.searchService\": \"Search service to add...\",\n \"agenda.appointment.selectLocation\": \"Select location...\",\n \"agenda.appointment.selectProfessional\": \"Select professional...\",\n \"agenda.appointment.services\": \"Services\",\n \"agenda.appointment.status\": \"Status\",\n \"agenda.appointment.to\": \"to\",\n \"agenda.appointment.total\": \"Total\",\n \"agenda.appointment.update\": \"Update\",\n \"agenda.payment.title\": \"Payment\",\n \"agenda.payment.generateInvoice\": \"Generate invoice\",\n \"agenda.payment.generating\": \"Generating…\",\n \"agenda.payment.pending\": \"Pending\",\n \"agenda.payment.partial\": \"Partial\",\n \"agenda.payment.paid\": \"Paid\",\n \"agenda.payment.collect\": \"Collect\",\n \"agenda.payment.overdue\": \"Overdue\",\n \"agenda.payment.cancelled\": \"Cancelled\",\n \"agenda.payment.none\": \"Payment\",\n \"agenda.payment.pay\": \"Pay\",\n \"agenda.payment.paying\": \"Paying…\",\n \"agenda.payment.remaining\": \"Remaining\",\n \"agenda.payment.installment\": \"Installment\",\n \"agenda.payment.total\": \"Total\",\n \"agenda.payment.noInvoice\": \"No invoice generated\",\n \"agenda.payment.selectAccount\": \"Select account\",\n \"agenda.payment.registerPayment\": \"Register payment\",\n \"agenda.payment.registerPaymentHint\": \"Record a payment for this appointment\",\n \"agenda.payment.pendingHint\": \"Invoice generated, awaiting payment\",\n \"agenda.payment.partialHint\": \"Partially paid, tap to complete\",\n \"agenda.payment.paidHint\": \"Payment completed\",\n \"agenda.payment.overdueHint\": \"Payment overdue\",\n \"agenda.payment.backToAppointment\": \"Back to appointment\",\n \"agenda.payment.checkout\": \"Confirm\",\n \"agenda.payment.checkingOut\": \"Processing…\",\n \"agenda.payment.serviceSummary\": \"Service summary\",\n \"agenda.payment.paymentMethod\": \"Payment method\",\n \"agenda.payment.noMethods\": \"No payment methods configured.\",\n \"agenda.payment.configureMethods\": \"Set up payment methods\",\n \"agenda.payment.checkoutComplete\": \"Payment confirmed\",\n \"agenda.payment.card\": \"Card\",\n \"agenda.payment.method\": \"Method\",\n \"agenda.payment.select\": \"Select…\",\n \"agenda.payment.cardBrand\": \"Brand\",\n \"agenda.payment.selectBrand\": \"Select brand…\",\n \"agenda.payment.cardInstallments\": \"Installments\",\n \"agenda.payment.bankAccount\": \"Account\",\n \"agenda.payment.viewInvoice\": \"View invoice details\",\n \"agenda.calendar.agendas\": \"Agendas\",\n \"agenda.calendar.create\": \"Create\",\n \"agenda.calendar.next\": \"Next\",\n \"agenda.calendar.previous\": \"Previous\",\n \"agenda.calendar.status\": \"Status\",\n \"agenda.calendar.today\": \"Today\",\n \"agenda.calendar.viewAgenda\": \"Agenda\",\n \"agenda.calendar.viewDay\": \"Day\",\n \"agenda.calendar.viewList\": \"List\",\n \"agenda.calendar.viewMonth\": \"Month\",\n \"agenda.calendar.viewWeek\": \"Week\",\n \"agenda.list.today\": \"Today\",\n \"agenda.list.tomorrow\": \"Tomorrow\",\n \"agenda.list.empty\": \"No upcoming items\",\n \"agenda.confirmations.confirmed\": \"Confirmed:\",\n \"agenda.confirmations.empty\": \"No pending confirmations\",\n \"agenda.confirmations.emptySubtitle\": \"All upcoming appointments have been confirmed\",\n \"agenda.confirmations.loading\": \"Loading...\",\n \"agenda.confirmations.subtitle\": \"Upcoming appointments pending confirmation\",\n \"agenda.confirmations.unknownClient\": \"Unknown client\",\n \"agenda.confirmations.sendWhatsApp\": \"Send WhatsApp\",\n \"agenda.confirmations.call\": \"Call\",\n \"agenda.confirmations.markConfirmed\": \"Mark Confirmed\",\n \"agenda.confirmations.markCancelled\": \"Mark Cancelled\",\n \"agenda.cancellation.loadingReasons\": \"Loading reasons...\",\n \"agenda.cancellation.notesOptional\": \"Cancellation notes (optional)\",\n \"agenda.cancellation.notesRequired\": \"Cancellation notes required\",\n \"agenda.cancellation.selectReason\": \"Select cancellation reason\",\n \"agenda.contextMenu.changeStatus\": \"Change status\",\n \"agenda.contextMenu.delete\": \"Delete\",\n \"agenda.contextMenu.edit\": \"Edit\",\n \"agenda.contextMenu.notAvailable\": \"(not available)\",\n \"agenda.index.settingsSubtitle\": \"Working hours, scheduling preferences, and confirmations\",\n \"agenda.index.settingsTitle\": \"Agenda Settings\",\n \"settings.plugin.agenda-working-hours\": \"Working Hours\",\n \"agenda.popover.unknown\": \"Unknown\",\n \"agenda.settings.autoConfirm\": \"Auto-confirm\",\n \"agenda.settings.autoConfirmDesc\": \"Automatically confirm new bookings\",\n \"agenda.settings.autoCreateOrder\": \"Auto-create Order\",\n \"agenda.settings.autoCreateOrderDesc\": \"Automatically create a financial order for new bookings\",\n \"agenda.settings.blockOutside\": \"Block Outside Hours\",\n \"agenda.settings.blockOutsideDesc\": \"Prevent bookings outside working hours\",\n \"agenda.settings.calendarDisplay\": \"Calendar Display\",\n \"agenda.settings.calendarDisplayDesc\": \"Visual settings for the calendar\",\n \"agenda.settings.cancelAlerts\": \"Cancellation Alerts\",\n \"agenda.settings.cancelAlertsDesc\": \"Notify when a booking is cancelled\",\n \"agenda.settings.compact\": \"Compact Mode\",\n \"agenda.settings.compactDesc\": \"Use smaller event blocks\",\n \"agenda.settings.confirmations\": \"Confirmations\",\n \"agenda.settings.confirmationsDesc\": \"Booking confirmation settings\",\n \"agenda.settings.conflictDetection\": \"Conflict Detection\",\n \"agenda.settings.conflictDetectionDesc\": \"Warn when bookings overlap\",\n \"agenda.settings.dragDrop\": \"Drag & Drop\",\n \"agenda.settings.dragDropDesc\": \"Allow rescheduling by dragging events\",\n \"agenda.settings.enableConfirmations\": \"Enable Confirmations\",\n \"agenda.settings.enableConfirmationsDesc\": \"Require confirmation for new bookings\",\n \"agenda.settings.enableLocation\": \"Enable Location Selection\",\n \"agenda.settings.enableLocationDesc\": \"Show location picker in booking modal\",\n \"agenda.settings.enableWorkingHours\": \"Enable Working Hours\",\n \"agenda.settings.enableWorkingHoursDesc\": \"Show working hours overlay on calendar\",\n \"agenda.settings.locations\": \"Locations\",\n \"agenda.settings.locationsDesc\": \"Multi-location settings\",\n \"agenda.settings.newBookingNotif\": \"New Booking Alerts\",\n \"agenda.settings.newBookingNotifDesc\": \"Notify when a new booking is created\",\n \"agenda.settings.noShowTracking\": \"No-show Tracking\",\n \"agenda.settings.noShowTrackingDesc\": \"Track and alert on no-shows\",\n \"agenda.settings.notifications\": \"Notifications\",\n \"agenda.settings.notificationsDesc\": \"Notification preferences\",\n \"agenda.settings.reminder\": \"Reminders\",\n \"agenda.settings.reminderDesc\": \"Send reminders before appointments\",\n \"agenda.settings.scheduling\": \"Scheduling\",\n \"agenda.settings.schedulingDesc\": \"Configure scheduling behavior\",\n \"agenda.settings.showCancelled\": \"Show Cancelled\",\n \"agenda.settings.showCancelledDesc\": \"Display cancelled bookings on calendar\",\n \"agenda.settings.showNoShow\": \"Show No-shows\",\n \"agenda.settings.showNoShowDesc\": \"Display no-show bookings on calendar\",\n \"agenda.settings.workingHours\": \"Working Hours\",\n \"agenda.settings.workingHoursDesc\": \"Working hours and availability\",\n \"agenda.sidebar.agendas\": \"Agendas\",\n \"agenda.sidebar.allLocations\": \"All locations\",\n \"agenda.sidebar.create\": \"Create\",\n \"agenda.sidebar.location\": \"Location\",\n \"agenda.sidebar.status\": \"Status\",\n \"agenda.toolbar.next\": \"Next\",\n \"agenda.toolbar.previous\": \"Previous\",\n \"agenda.toolbar.today\": \"Today\",\n \"agenda.workingHours.addBreak\": \"Add break\",\n \"agenda.workingHours.copyToAll\": \"Copy to all\",\n \"agenda.workingHours.dayOff\": \"Day off\",\n \"agenda.workingHours.removePeriod\": \"Remove period\",\n \"agenda.workingHours.professional\": \"Professional\",\n \"agenda.workingHours.save\": \"Save\",\n \"agenda.workingHours.saveFailed\": \"Failed to save\",\n \"agenda.workingHours.saved\": \"Working hours saved\",\n \"agenda.workingHours.saving\": \"Saving...\",\n \"agenda.workingHours.subtitle\": \"Manage working hours per professional\",\n \"agenda.workingHours.to\": \"to\",\n \"agenda.title\": \"Agenda\",\n \"agenda.calendar.title\": \"Calendar\",\n \"agenda.calendar.noScheduleConfirm\": \"This time slot has no open schedule for this professional. Do you want to book anyway?\",\n \"agenda.calendar.newAppointment\": \"New Appointment\",\n \"agenda.booking.create\": \"New Appointment\",\n \"agenda.booking.edit\": \"Edit Appointment\",\n \"agenda.booking.delete\": \"Delete Appointment\",\n \"agenda.booking.deleteConfirm\": \"Are you sure you want to delete this appointment?\",\n \"agenda.booking.client\": \"Client\",\n \"agenda.booking.professional\": \"Professional\",\n \"agenda.booking.services\": \"Services\",\n \"agenda.booking.date\": \"Date\",\n \"agenda.booking.time\": \"Time\",\n \"agenda.booking.duration\": \"Duration\",\n \"agenda.booking.notes\": \"Notes\",\n \"agenda.booking.status\": \"Status\",\n \"agenda.booking.save\": \"Save Appointment\",\n \"agenda.booking.saving\": \"Saving...\",\n \"agenda.confirmations.title\": \"Confirmations\",\n \"agenda.confirmations.pending\": \"Pending Confirmations\",\n \"agenda.confirmations.emptyDescription\": \"All upcoming appointments have been confirmed\",\n \"agenda.confirmations.confirm\": \"Confirm\",\n \"agenda.confirmations.cancel\": \"Cancel\",\n \"agenda.workingHours.title\": \"Working Hours\",\n \"agenda.workingHours.addPeriod\": \"Add period\",\n \"agenda.workingHours.loading\": \"Loading...\",\n \"agenda.appointment.addClient\": \"Add client\",\n \"agenda.appointment.addServiceFirst\": \"Add service\",\n \"agenda.appointment.addNotes\": \"Add notes\",\n \"agenda.appointment.duration\": \"Duration (minutes)\",\n \"agenda.appointment.price\": \"Price\",\n \"agenda.appointment.title\": \"Title\",\n \"agenda.appointment.addTitle\": \"Add a title\",\n \"agenda.appointment.untitled\": \"(no title)\",\n \"agenda.bookingType.appointment\": \"Appointment\",\n \"agenda.bookingType.event\": \"Event\",\n \"agenda.bookingType.task\": \"Task\",\n \"agenda.bookingType.out_of_office\": \"Out of Office\",\n \"agenda.bookingType.block\": \"Block\",\n \"agenda.settings.title\": \"Agenda Settings\",\n \"agenda.settings.slotDuration\": \"Slot Duration\",\n \"agenda.settings.bookingKind\": \"Booking Kind\",\n \"agenda.settings.dayStartTime\": \"Day Start Time\",\n \"agenda.settings.dayStartTimeDesc\": \"First hour shown on the calendar\",\n \"agenda.settings.dayEndTime\": \"Day End Time\",\n \"agenda.settings.dayEndTimeDesc\": \"Last hour shown on the calendar\",\n}\n","// agenda.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"agenda.appointment.addDescription\": \"Adicionar descrição...\",\n \"agenda.appointment.addService\": \"Adicionar serviço\",\n \"agenda.appointment.cancel\": \"Cancelar\",\n \"agenda.appointment.clientTab\": \"Cliente\",\n \"agenda.appointment.noClientData\": \"Dados do cliente não disponíveis\",\n \"agenda.appointment.client\": \"Cliente\",\n \"agenda.appointment.conflict\": \"Conflito de horário — este profissional já está reservado neste horário.\",\n \"agenda.appointment.create\": \"Criar\",\n \"agenda.appointment.createClientFailed\": \"Falha ao criar cliente\",\n \"agenda.appointment.creating\": \"Criando...\",\n \"agenda.appointment.delete\": \"Excluir\",\n \"agenda.appointment.deleteConfirm\": \"Excluir este agendamento?\",\n \"agenda.appointment.confirmDelete\": \"Excluir\",\n \"agenda.appointment.deleting\": \"Excluindo…\",\n \"agenda.appointment.edit\": \"Editar Agendamento\",\n \"agenda.appointment.emailOptional\": \"E-mail (opcional)\",\n \"agenda.appointment.location\": \"Local\",\n \"agenda.appointment.name\": \"Nome\",\n \"agenda.appointment.new\": \"Novo Agendamento\",\n \"agenda.appointment.newClient\": \"Novo cliente\",\n \"agenda.appointment.required\": \"Obrigatório\",\n \"agenda.appointment.newService\": \"Novo serviço\",\n \"agenda.appointment.notes\": \"Observações\",\n \"agenda.appointment.phone\": \"Telefone\",\n \"agenda.appointment.professional\": \"Profissional\",\n \"agenda.appointment.save\": \"Salvar\",\n \"agenda.appointment.saving\": \"Salvando...\",\n \"agenda.appointment.searchClient\": \"Buscar cliente...\",\n \"agenda.appointment.searchService\": \"Buscar serviço para adicionar...\",\n \"agenda.appointment.selectLocation\": \"Selecionar local...\",\n \"agenda.appointment.selectProfessional\": \"Selecionar profissional...\",\n \"agenda.appointment.services\": \"Serviços\",\n \"agenda.appointment.status\": \"Status\",\n \"agenda.appointment.to\": \"até\",\n \"agenda.appointment.total\": \"Total\",\n \"agenda.appointment.update\": \"Atualizar\",\n \"agenda.payment.title\": \"Recebimento\",\n \"agenda.payment.generateInvoice\": \"Gerar recebimento\",\n \"agenda.payment.generating\": \"Gerando…\",\n \"agenda.payment.pending\": \"Pendente\",\n \"agenda.payment.partial\": \"Parcial\",\n \"agenda.payment.paid\": \"Pago\",\n \"agenda.payment.collect\": \"Receber\",\n \"agenda.payment.overdue\": \"Vencido\",\n \"agenda.payment.cancelled\": \"Cancelado\",\n \"agenda.payment.none\": \"Recebimento\",\n \"agenda.payment.pay\": \"Pagar\",\n \"agenda.payment.paying\": \"Pagando…\",\n \"agenda.payment.remaining\": \"Restante\",\n \"agenda.payment.installment\": \"Parcela\",\n \"agenda.payment.total\": \"Total\",\n \"agenda.payment.noInvoice\": \"Sem recebimento gerado\",\n \"agenda.payment.selectAccount\": \"Selecionar conta\",\n \"agenda.payment.registerPayment\": \"Registrar recebimento\",\n \"agenda.payment.registerPaymentHint\": \"Registrar pagamento deste agendamento\",\n \"agenda.payment.pendingHint\": \"Fatura gerada, aguardando pagamento\",\n \"agenda.payment.partialHint\": \"Parcialmente pago, toque para completar\",\n \"agenda.payment.paidHint\": \"Pagamento realizado\",\n \"agenda.payment.overdueHint\": \"Pagamento vencido\",\n \"agenda.payment.backToAppointment\": \"Voltar ao agendamento\",\n \"agenda.payment.checkout\": \"Confirmar\",\n \"agenda.payment.checkingOut\": \"Processando…\",\n \"agenda.payment.serviceSummary\": \"Resumo do atendimento\",\n \"agenda.payment.paymentMethod\": \"Forma de pagamento\",\n \"agenda.payment.noMethods\": \"Nenhuma forma de pagamento configurada.\",\n \"agenda.payment.configureMethods\": \"Configurar formas de pagamento\",\n \"agenda.payment.checkoutComplete\": \"Pagamento confirmado\",\n \"agenda.payment.card\": \"Cartão\",\n \"agenda.payment.method\": \"Método\",\n \"agenda.payment.select\": \"Selecionar…\",\n \"agenda.payment.cardBrand\": \"Bandeira\",\n \"agenda.payment.selectBrand\": \"Selecionar bandeira…\",\n \"agenda.payment.cardInstallments\": \"Parcelas\",\n \"agenda.payment.bankAccount\": \"Conta\",\n \"agenda.payment.viewInvoice\": \"Ver detalhes da fatura\",\n \"agenda.calendar.agendas\": \"Agendas\",\n \"agenda.calendar.create\": \"Criar\",\n \"agenda.calendar.next\": \"Próximo\",\n \"agenda.calendar.previous\": \"Anterior\",\n \"agenda.calendar.status\": \"Status\",\n \"agenda.calendar.today\": \"Hoje\",\n \"agenda.calendar.viewAgenda\": \"Agenda\",\n \"agenda.calendar.viewDay\": \"Dia\",\n \"agenda.calendar.viewList\": \"Lista\",\n \"agenda.calendar.viewMonth\": \"Mês\",\n \"agenda.calendar.viewWeek\": \"Semana\",\n \"agenda.list.today\": \"Hoje\",\n \"agenda.list.tomorrow\": \"Amanhã\",\n \"agenda.list.empty\": \"Nenhum item próximo\",\n \"agenda.confirmations.confirmed\": \"Confirmado:\",\n \"agenda.confirmations.empty\": \"Nenhuma confirmação pendente\",\n \"agenda.confirmations.emptySubtitle\": \"Todos os agendamentos futuros foram confirmados\",\n \"agenda.confirmations.loading\": \"Carregando...\",\n \"agenda.confirmations.subtitle\": \"Agendamentos futuros pendentes de confirmação\",\n \"agenda.confirmations.unknownClient\": \"Cliente desconhecido\",\n \"agenda.confirmations.sendWhatsApp\": \"Enviar WhatsApp\",\n \"agenda.confirmations.call\": \"Ligar\",\n \"agenda.confirmations.markConfirmed\": \"Marcar Confirmado\",\n \"agenda.confirmations.markCancelled\": \"Marcar Cancelado\",\n \"agenda.cancellation.loadingReasons\": \"Carregando motivos...\",\n \"agenda.cancellation.notesOptional\": \"Observações do cancelamento (opcional)\",\n \"agenda.cancellation.notesRequired\": \"Observações do cancelamento obrigatórias\",\n \"agenda.cancellation.selectReason\": \"Selecionar motivo do cancelamento\",\n \"agenda.contextMenu.changeStatus\": \"Alterar status\",\n \"agenda.contextMenu.delete\": \"Excluir\",\n \"agenda.contextMenu.edit\": \"Editar\",\n \"agenda.contextMenu.notAvailable\": \"(indisponível)\",\n \"agenda.index.settingsSubtitle\": \"Horários de funcionamento, preferências de agendamento e confirmações\",\n \"agenda.index.settingsTitle\": \"Configurações da Agenda\",\n \"settings.plugin.agenda-working-hours\": \"Horário de Funcionamento\",\n \"agenda.popover.unknown\": \"Desconhecido\",\n \"agenda.settings.autoConfirm\": \"Confirmar Automaticamente\",\n \"agenda.settings.autoConfirmDesc\": \"Confirmar automaticamente novos agendamentos\",\n \"agenda.settings.autoCreateOrder\": \"Criar Pedido Automaticamente\",\n \"agenda.settings.autoCreateOrderDesc\": \"Criar automaticamente um pedido financeiro para novos agendamentos\",\n \"agenda.settings.blockOutside\": \"Bloquear Fora do Horário\",\n \"agenda.settings.blockOutsideDesc\": \"Impedir agendamentos fora do horário de funcionamento\",\n \"agenda.settings.calendarDisplay\": \"Exibição do Calendário\",\n \"agenda.settings.calendarDisplayDesc\": \"Configurações visuais do calendário\",\n \"agenda.settings.cancelAlerts\": \"Alertas de Cancelamento\",\n \"agenda.settings.cancelAlertsDesc\": \"Notificar quando um agendamento é cancelado\",\n \"agenda.settings.compact\": \"Modo Compacto\",\n \"agenda.settings.compactDesc\": \"Usar blocos de eventos menores\",\n \"agenda.settings.confirmations\": \"Confirmações\",\n \"agenda.settings.confirmationsDesc\": \"Configurações de confirmação de agendamento\",\n \"agenda.settings.conflictDetection\": \"Detecção de Conflitos\",\n \"agenda.settings.conflictDetectionDesc\": \"Alertar quando agendamentos se sobrepõem\",\n \"agenda.settings.dragDrop\": \"Arrastar e Soltar\",\n \"agenda.settings.dragDropDesc\": \"Permitir reagendamento arrastando eventos\",\n \"agenda.settings.enableConfirmations\": \"Habilitar Confirmações\",\n \"agenda.settings.enableConfirmationsDesc\": \"Exigir confirmação para novos agendamentos\",\n \"agenda.settings.enableLocation\": \"Habilitar Seleção de Local\",\n \"agenda.settings.enableLocationDesc\": \"Mostrar seletor de local no modal de agendamento\",\n \"agenda.settings.enableWorkingHours\": \"Habilitar Horário de Funcionamento\",\n \"agenda.settings.enableWorkingHoursDesc\": \"Mostrar sobreposição de horário de funcionamento no calendário\",\n \"agenda.settings.locations\": \"Locais\",\n \"agenda.settings.locationsDesc\": \"Configurações de múltiplos locais\",\n \"agenda.settings.newBookingNotif\": \"Alertas de Novo Agendamento\",\n \"agenda.settings.newBookingNotifDesc\": \"Notificar quando um novo agendamento é criado\",\n \"agenda.settings.noShowTracking\": \"Rastreamento de Ausências\",\n \"agenda.settings.noShowTrackingDesc\": \"Rastrear e alertar sobre ausências\",\n \"agenda.settings.notifications\": \"Notificações\",\n \"agenda.settings.notificationsDesc\": \"Preferências de notificação\",\n \"agenda.settings.reminder\": \"Lembretes\",\n \"agenda.settings.reminderDesc\": \"Enviar lembretes antes dos compromissos\",\n \"agenda.settings.scheduling\": \"Agendamento\",\n \"agenda.settings.schedulingDesc\": \"Configurar comportamento do agendamento\",\n \"agenda.settings.showCancelled\": \"Mostrar Cancelados\",\n \"agenda.settings.showCancelledDesc\": \"Exibir agendamentos cancelados no calendário\",\n \"agenda.settings.showNoShow\": \"Mostrar Ausências\",\n \"agenda.settings.showNoShowDesc\": \"Exibir ausências no calendário\",\n \"agenda.settings.workingHours\": \"Horário de Funcionamento\",\n \"agenda.settings.workingHoursDesc\": \"Horários e disponibilidade\",\n \"agenda.sidebar.agendas\": \"Agendas\",\n \"agenda.sidebar.allLocations\": \"Todos os locais\",\n \"agenda.sidebar.create\": \"Criar\",\n \"agenda.sidebar.location\": \"Local\",\n \"agenda.sidebar.status\": \"Status\",\n \"agenda.toolbar.next\": \"Próximo\",\n \"agenda.toolbar.previous\": \"Anterior\",\n \"agenda.toolbar.today\": \"Hoje\",\n \"agenda.workingHours.addBreak\": \"Adicionar intervalo\",\n \"agenda.workingHours.copyToAll\": \"Copiar para todos\",\n \"agenda.workingHours.dayOff\": \"Folga\",\n \"agenda.workingHours.removePeriod\": \"Remover período\",\n \"agenda.workingHours.professional\": \"Profissional\",\n \"agenda.workingHours.save\": \"Salvar\",\n \"agenda.workingHours.saveFailed\": \"Falha ao salvar\",\n \"agenda.workingHours.saved\": \"Horários de trabalho salvos\",\n \"agenda.workingHours.saving\": \"Salvando...\",\n \"agenda.workingHours.subtitle\": \"Gerenciar horários de trabalho por profissional\",\n \"agenda.workingHours.to\": \"até\",\n \"agenda.title\": \"Agenda\",\n \"agenda.calendar.title\": \"Calendário\",\n \"agenda.calendar.noScheduleConfirm\": \"Este horário não possui agenda aberta para este profissional. Deseja agendar mesmo assim?\",\n \"agenda.calendar.newAppointment\": \"Novo Agendamento\",\n \"agenda.booking.create\": \"Novo Agendamento\",\n \"agenda.booking.edit\": \"Editar Agendamento\",\n \"agenda.booking.delete\": \"Excluir Agendamento\",\n \"agenda.booking.deleteConfirm\": \"Tem certeza que deseja excluir este agendamento?\",\n \"agenda.booking.client\": \"Cliente\",\n \"agenda.booking.professional\": \"Profissional\",\n \"agenda.booking.services\": \"Serviços\",\n \"agenda.booking.date\": \"Data\",\n \"agenda.booking.time\": \"Horário\",\n \"agenda.booking.duration\": \"Duração\",\n \"agenda.booking.notes\": \"Observações\",\n \"agenda.booking.status\": \"Status\",\n \"agenda.booking.save\": \"Salvar Agendamento\",\n \"agenda.booking.saving\": \"Salvando...\",\n \"agenda.confirmations.title\": \"Confirmações\",\n \"agenda.confirmations.pending\": \"Confirmações Pendentes\",\n \"agenda.confirmations.emptyDescription\": \"Todos os agendamentos futuros foram confirmados\",\n \"agenda.confirmations.confirm\": \"Confirmar\",\n \"agenda.confirmations.cancel\": \"Cancelar\",\n \"agenda.workingHours.title\": \"Horário de Trabalho\",\n \"agenda.workingHours.addPeriod\": \"Adicionar período\",\n \"agenda.workingHours.loading\": \"Carregando...\",\n \"agenda.appointment.addClient\": \"Adicionar cliente\",\n \"agenda.appointment.addServiceFirst\": \"Adicionar serviço\",\n \"agenda.appointment.addNotes\": \"Adicionar observações\",\n \"agenda.appointment.duration\": \"Duração (minutos)\",\n \"agenda.appointment.price\": \"Preço\",\n \"agenda.appointment.title\": \"Título\",\n \"agenda.appointment.addTitle\": \"Adicionar um título\",\n \"agenda.appointment.untitled\": \"(sem título)\",\n \"agenda.bookingType.appointment\": \"Agendamento\",\n \"agenda.bookingType.event\": \"Evento\",\n \"agenda.bookingType.task\": \"Tarefa\",\n \"agenda.bookingType.out_of_office\": \"Ausência\",\n \"agenda.bookingType.block\": \"Bloqueio\",\n \"agenda.settings.title\": \"Configurações da Agenda\",\n \"agenda.settings.slotDuration\": \"Duração do Intervalo\",\n \"agenda.settings.bookingKind\": \"Tipo de Agendamento\",\n \"agenda.settings.dayStartTime\": \"Horário de Início\",\n \"agenda.settings.dayStartTimeDesc\": \"Primeiro horário exibido no calendário\",\n \"agenda.settings.dayEndTime\": \"Horário de Término\",\n \"agenda.settings.dayEndTimeDesc\": \"Último horário exibido no calendário\",\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const agendaLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","// AUTO-GENERATED from 000b_v_bookings_rename.sql, 000c_dedupe_customer_phones.sql, 001_public_booking.sql, 002_v_bookings_compat.sql, 003_public_client_kind.sql, 004_public_booking_assignee.sql, 005_agent_rpcs.sql, 006_agent_rpc_localtime.sql, 007_schedule_exception_precedence.sql, 008_agent_rpc_exception_precedence.sql, 009_public_booking_location.sql, 010_public_service_curation.sql, 011_default_assignee.sql, 012_drop_legacy_booking_overload.sql, 013_normalize_v_appointments.sql, 014_agent_rpc_update_appointment.sql, 015_analytics_read_models.sql, 016_public_services_release.sql, 017_booking_channel_reply.sql, 018_the_agenda_declares_its_species.sql, 019_the_definer_functions_stop_trusting_the_path.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000B_V_BOOKINGS_RENAME = `-- Salon-only unblock: the pre-pools beauty deployment built rep_* report\n-- views on top of its (wider) v_bookings view, so 001's cleanup DROP cannot\n-- run there. Renaming keeps the dependents attached (they track the OID) and\n-- frees the name for 001; 002_v_bookings_compat re-creates v_bookings as a\n-- thin alias for live pre-M5 clients. No-op on fresh pools and on pools whose\n-- v_bookings has no dependents (001's DROP handles those).\n\nDO $rename$\nBEGIN\n IF to_regclass('public.v_bookings') IS NOT NULL\n AND to_regclass('public.v_bookings_legacy_beauty') IS NULL\n AND EXISTS (\n SELECT 1 FROM pg_depend d\n JOIN pg_rewrite rw ON rw.oid = d.objid\n JOIN pg_class dep ON dep.oid = rw.ev_class\n JOIN pg_class ref ON ref.oid = d.refobjid\n WHERE ref.relname = 'v_bookings' AND dep.relname <> 'v_bookings'\n ) THEN\n EXECUTE 'ALTER VIEW public.v_bookings RENAME TO v_bookings_legacy_beauty';\n END IF;\nEND $rename$;\n`\n\nexport const MIGRATION_000C_DEDUPE_CUSTOMER_PHONES = `-- 001 needs the customer-phone upsert key UNIQUE(tenant_id, phone). Converted\n-- pools can carry duplicates (found live on salon: 9 dogfood test records all\n-- sharing the founder's phone). Non-destructive dedupe: per (tenant_id, phone)\n-- customer group keep the row with most appointments (tie: oldest), NULL the\n-- phone on the rest and stash the original in metadata->'dedupedPhone'.\n-- Idempotent: reruns find no groups > 1.\n\nDO $dedupe$\nDECLARE\n r record;\nBEGIN\n IF to_regclass('public.people') IS NULL THEN\n RETURN;\n END IF;\n\n FOR r IN\n SELECT p.id, p.phone\n FROM public.people p\n JOIN LATERAL (\n SELECT count(*) AS appts\n FROM public.appointments a WHERE a.party_id = p.id\n ) ac ON true\n WHERE p.kind = 'customer' AND p.phone IS NOT NULL\n AND p.id NOT IN (\n SELECT DISTINCT ON (p2.tenant_id, p2.phone) p2.id\n FROM public.people p2\n WHERE p2.kind = 'customer' AND p2.phone IS NOT NULL\n ORDER BY p2.tenant_id, p2.phone,\n (SELECT count(*) FROM public.appointments a2 WHERE a2.party_id = p2.id) DESC,\n p2.created_at ASC\n )\n AND (p.tenant_id, p.phone) IN (\n SELECT tenant_id, phone FROM public.people\n WHERE kind = 'customer' AND phone IS NOT NULL\n GROUP BY tenant_id, phone HAVING count(*) > 1\n )\n LOOP\n UPDATE public.people\n SET metadata = COALESCE(metadata, '{}'::jsonb) || jsonb_build_object('dedupedPhone', r.phone),\n phone = NULL\n WHERE id = r.id;\n END LOOP;\nEND $dedupe$;\n`\n\nexport const MIGRATION_001_PUBLIC_BOOKING = `-- ============================================================================\n-- plugin-agenda 001: booking read model + public (anon) booking surface\n--\n-- Ships the objects the agenda providers reference but the spine (packages/db\n-- migrations 001–010) does not define:\n-- §0 converted-pool cleanup — drop the pre-rename v_bookings view / indexes\n-- §1 order_items columns the admin provider writes (duration/assignee)\n-- §2 public.v_appointments — admin read model (authenticated, RLS applies)\n-- §3 public.v_public_services — anon-readable service catalog\n-- §4 public.get_available_slots — anon RPC (mirrors the mock algorithm)\n-- §5 public.create_public_booking — anon RPC (validated, race-safe write)\n--\n-- Core v1 lives directly in PUBLIC (no separate core schema): people (was\n-- persons), appointments (was bookings). This migration is written against public\n-- names and is idempotent + safe on both fresh and converted pools.\n--\n-- Anon-access design: public booking pages run with the publishable key and no\n-- session, so the canonical tenant RLS yields nothing. Anon access is granted\n-- ONLY via the column-whitelisted view (§3) and SECURITY DEFINER RPCs (§4, §5)\n-- with tight input validation and hardcoded statuses.\n-- ============================================================================\n\n-- §0 — converted-pool cleanup. The pre-industry-pool shape shipped a v_bookings\n-- view and persons_/bookings_-named indexes; drop them so this file re-emits the\n-- canonical v_appointments view + people_/appointments_ indexes without leaving\n-- duplicates. All guarded with IF EXISTS → no-ops on a fresh pool.\nDROP VIEW IF EXISTS public.v_bookings;\nDROP INDEX IF EXISTS public.persons_tenant_customer_phone;\nDROP INDEX IF EXISTS public.bookings_assignee_time;\n\n-- §1 — columns the agenda provider writes but 004_archetypes lacks\nALTER TABLE public.order_items\n ADD COLUMN IF NOT EXISTS duration_minutes integer,\n ADD COLUMN IF NOT EXISTS assignee_id uuid REFERENCES public.people(id) ON DELETE SET NULL;\n\n-- Lookup key for public customers (per tenant, by normalized phone).\n-- NOT UNIQUE. It was, and spine/110 says why it cannot be: \\`kind\\` became a\n-- derived column, so an imported 'client' turns into a 'customer' and a\n-- placeholder phone shared by eight real people lands under one key. The upsert\n-- that used to lean on it takes a per-(tenant, phone) advisory lock instead\n-- (003, 009) — the index is here for the lookup that lock guards.\nDROP INDEX IF EXISTS public.people_tenant_customer_phone;\nCREATE INDEX IF NOT EXISTS people_tenant_customer_phone\n ON public.people(tenant_id, phone)\n WHERE kind = 'customer' AND phone IS NOT NULL;\n\n-- Slot-conflict scan\nCREATE INDEX IF NOT EXISTS appointments_assignee_time\n ON public.appointments(assignee_id, starts_at, ends_at)\n WHERE status NOT IN ('cancelled', 'no_show');\n\n-- §2 — admin read model (security_invoker → underlying RLS applies; anon sees 0 rows)\n-- DROP first: 013 widens this view and CREATE OR REPLACE cannot narrow a live\n-- view on replay (\"cannot drop columns from view\"). 013 replays right after.\n-- 013 builds on this one, so the drop needs its dependents out and back (143).\nSELECT app.detach_view_dependents('public.v_appointments');\nDROP VIEW IF EXISTS public.v_appointments;\nCREATE VIEW public.v_appointments\nWITH (security_invoker = true) AS\nSELECT\n b.id, b.tenant_id, b.kind, b.starts_at, b.ends_at, b.status, b.notes,\n b.order_id, b.location_id, b.metadata, b.created_at, b.updated_at,\n b.party_id AS client_id,\n COALESCE(pc.name, b.metadata->>'title') AS client_name,\n pc.phone AS client_phone,\n pc.email AS client_email,\n pc.avatar_url AS client_avatar_url,\n b.assignee_id AS professional_id,\n ps.name AS professional_name,\n ps.avatar_url AS professional_avatar_url,\n l.name AS location_name,\n o.total AS order_total,\n o.status AS order_status,\n (EXTRACT(EPOCH FROM (COALESCE(b.ends_at, b.starts_at) - b.starts_at))::int / 60)\n AS total_duration_minutes\nFROM public.appointments b\nLEFT JOIN public.people pc ON pc.id = b.party_id\nLEFT JOIN public.people ps ON ps.id = b.assignee_id\nLEFT JOIN public.locations l ON l.id = b.location_id\nLEFT JOIN public.orders o ON o.id = b.order_id;\n\nGRANT SELECT ON public.v_appointments TO authenticated, service_role;\nREVOKE SELECT ON public.v_appointments FROM anon;\n\n-- §3 — anon-readable public catalog (owner-rights view = deliberate, whitelisted)\n-- DROP first: 010 widens this view (curation columns) — same replay rule as §2.\nDROP VIEW IF EXISTS public.v_public_services;\nCREATE VIEW public.v_public_services AS\nSELECT\n s.id, s.tenant_id, s.name, s.description, s.price, s.currency,\n COALESCE(s.duration_minutes, 30) AS duration_minutes,\n s.image_url,\n COALESCE((s.metadata->>'sort_order')::int, 0) AS sort_order\nFROM public.services s\nWHERE s.is_active AND s.status = 'active';\n\nGRANT SELECT ON public.v_public_services TO anon, authenticated, service_role;\n\n-- §4 — availability RPC (mirrors plugin-agenda/src/data/mock.ts getAvailableSlots)\nCREATE OR REPLACE FUNCTION public.get_available_slots(\n p_tenant_id uuid,\n p_date date,\n p_duration_minutes integer,\n p_assignee_id uuid DEFAULT NULL,\n p_slot_interval integer DEFAULT 30\n) RETURNS TABLE (slot_start timestamptz, slot_end timestamptz)\nLANGUAGE plpgsql STABLE SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_tz text;\nBEGIN\n -- tight validation: this function is anon-callable\n IF p_duration_minutes IS NULL OR p_duration_minutes NOT BETWEEN 5 AND 480 THEN\n RAISE EXCEPTION 'invalid duration';\n END IF;\n IF p_slot_interval IS NULL OR p_slot_interval NOT BETWEEN 5 AND 240 THEN\n RAISE EXCEPTION 'invalid interval';\n END IF;\n IF p_date IS NULL OR p_date < current_date OR p_date > current_date + 90 THEN\n RETURN;\n END IF;\n\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RETURN; END IF; -- unknown tenant → empty, not an error\n\n RETURN QUERY\n WITH day_schedules AS (\n SELECT sc.assignee_id, sc.starts_at AS win_start, sc.ends_at AS win_end\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND (\n sc.specific_date = p_date\n OR (sc.specific_date IS NULL AND sc.day_of_week = EXTRACT(dow FROM p_date)::smallint)\n )\n ),\n candidate AS (\n SELECT\n ds.assignee_id,\n gs AS s_start,\n gs + make_interval(mins => p_duration_minutes) AS s_end\n FROM day_schedules ds\n CROSS JOIN LATERAL generate_series(\n (p_date + ds.win_start) AT TIME ZONE v_tz,\n ((p_date + ds.win_end) AT TIME ZONE v_tz) - make_interval(mins => p_duration_minutes),\n make_interval(mins => p_slot_interval)\n ) AS gs\n )\n SELECT DISTINCT c.s_start, c.s_end\n FROM candidate c\n WHERE NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = c.assignee_id\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < c.s_end\n AND COALESCE(b.ends_at, b.starts_at) > c.s_start\n )\n ORDER BY 1;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer) FROM public;\nGRANT EXECUTE ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer)\n TO anon, authenticated, service_role;\n\n-- §5 — public booking write RPC (validated, race-safe, hardcoded statuses)\nCREATE OR REPLACE FUNCTION public.create_public_booking(\n p_tenant_id uuid,\n p_service_id uuid,\n p_starts_at timestamptz,\n p_name text,\n p_phone text,\n p_email text DEFAULT NULL,\n p_notes text DEFAULT NULL\n) RETURNS TABLE (booking_id uuid, starts_at timestamptz, ends_at timestamptz)\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n\n -- pick the assignee whose working hours cover the slot\n SELECT sc.assignee_id INTO v_assignee\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (\n sc.specific_date = (p_starts_at AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_starts_at AT TIME ZONE v_tz)::smallint)\n )\n AND (p_starts_at AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- Upsert the customer by (tenant, phone). NOT ON CONFLICT: the partial unique\n -- index this used to infer is gone (spine/110 — a placeholder phone is shared\n -- by real, distinct people). 003 already settled the replacement: take a\n -- per-(tenant, phone) advisory lock so two first-bookings serialise, then look\n -- before inserting. Oldest match wins, so a returning caller keeps the record\n -- that carries their history.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = 'customer' AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, 'customer', trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text) FROM public;\nGRANT EXECUTE ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text)\n TO anon, authenticated, service_role;\n\nSELECT app.reattach_view_dependents();\n`\n\nexport const MIGRATION_002_V_BOOKINGS_COMPAT = `-- Where 000b preserved the legacy beauty view, re-create v_bookings as a\n-- thin alias over it so live pre-M5 clients that SELECT v_bookings by name\n-- keep their full legacy column set. Dropped for good once the beauty app\n-- ships on v_appointments (M5 follow-up).\n\nDO $compat$\nBEGIN\n IF to_regclass('public.v_bookings_legacy_beauty') IS NOT NULL\n AND to_regclass('public.v_bookings') IS NULL THEN\n EXECUTE 'CREATE VIEW public.v_bookings WITH (security_invoker = true) AS SELECT * FROM public.v_bookings_legacy_beauty';\n EXECUTE 'GRANT SELECT ON public.v_bookings TO authenticated, service_role';\n EXECUTE 'REVOKE SELECT ON public.v_bookings FROM anon';\n END IF;\nEND $compat$;\n`\n\nexport const MIGRATION_003_PUBLIC_CLIENT_KIND = `-- ---------------------------------------------------------------------------\n-- Public booking — tenant-configurable client kind\n-- ---------------------------------------------------------------------------\n-- 001 hardcoded kind='customer' for people created by create_public_booking.\n-- Verticals whose client archetype uses another kind (school → 'student',\n-- clinic → whatever the app registers) ended up with people invisible to the\n-- app's own pages/lookups and with entity links resolving to unregistered\n-- routes (#/customers/:id → not found).\n--\n-- The client kind now comes from TENANT SETTINGS (admin-controlled — never\n-- from the anon caller): tenants.settings.booking.client_kind\n-- Default remains 'customer', so existing pools/tenants are unaffected until\n-- they opt in:\n-- UPDATE tenants SET settings = jsonb_set(COALESCE(settings,'{}'::jsonb),\n-- '{booking,client_kind}', '\"student\"') WHERE id = '<tenant>';\n--\n-- The upsert no longer relies on the kind-specific partial unique index\n-- (people_tenant_customer_phone) — a per-(tenant, phone) advisory lock\n-- serializes concurrent first-bookings for any kind. The 001 index stays in\n-- place (harmless, still guards direct customer writes).\n--\n-- Idempotent: CREATE OR REPLACE, same signature as 001.\n-- ---------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.create_public_booking(\n p_tenant_id uuid,\n p_service_id uuid,\n p_starts_at timestamptz,\n p_name text,\n p_phone text,\n p_email text DEFAULT NULL,\n p_notes text DEFAULT NULL\n) RETURNS TABLE (booking_id uuid, starts_at timestamptz, ends_at timestamptz)\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- pick the assignee whose working hours cover the slot\n SELECT sc.assignee_id INTO v_assignee\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (\n sc.specific_date = (p_starts_at AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_starts_at AT TIME ZONE v_tz)::smallint)\n )\n AND (p_starts_at AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone). Kind is tenant-configured, so\n -- the 001 customer-only partial index can't arbitrate — a per-(tenant,\n -- phone) advisory lock serializes concurrent first-bookings instead.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text) FROM public;\nGRANT EXECUTE ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text)\n TO anon, authenticated, service_role;\n`\n\nexport const MIGRATION_004_PUBLIC_BOOKING_ASSIGNEE = `-- ---------------------------------------------------------------------------\n-- Public booking — respect the professional the visitor saw\n-- ---------------------------------------------------------------------------\n-- Until now create_public_booking IGNORED which professional the site showed\n-- availability for and re-picked by working hours (ORDER BY assignee_id\n-- LIMIT 1). With several professionals covering the same slot the booking\n-- landed on someone else than displayed (\"Equipe Great DJs\" on the site,\n-- \"Rafa Groove\" in the agenda). New optional p_assignee_id:\n-- * provided → validate THAT professional's working hours cover the slot and\n-- book them — never silently reassign (mismatch becomes an explicit error);\n-- * NULL → auto-pick as before (sites that don't pin a professional).\n-- Conflict check + advisory lock already run against the resolved assignee, so\n-- the double-book guard follows whichever path resolves.\n--\n-- Signature change (8th arg): the old 7-arg function is DROPPED first —\n-- CREATE OR REPLACE with a different signature would create an ambiguous\n-- PostgREST overload instead of replacing.\n-- Includes 003's tenant-configurable client kind. Idempotent.\n-- ---------------------------------------------------------------------------\nDROP FUNCTION IF EXISTS public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text);\n\nCREATE OR REPLACE FUNCTION public.create_public_booking(\n p_tenant_id uuid,\n p_service_id uuid,\n p_starts_at timestamptz,\n p_name text,\n p_phone text,\n p_email text DEFAULT NULL,\n p_notes text DEFAULT NULL,\n p_assignee_id uuid DEFAULT NULL\n) RETURNS TABLE (booking_id uuid, starts_at timestamptz, ends_at timestamptz)\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- resolve the professional: the one the visitor saw (validated), else the\n -- first whose working hours cover the slot\n SELECT sc.assignee_id INTO v_assignee\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND (\n sc.specific_date = (p_starts_at AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_starts_at AT TIME ZONE v_tz)::smallint)\n )\n AND (p_starts_at AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone), serialized by advisory lock\n -- (kind is tenant-configured, so the customer-only partial index can't\n -- arbitrate)\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text, uuid) FROM public;\nGRANT EXECUTE ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text, uuid)\n TO anon, authenticated, service_role;\n`\n\nexport const MIGRATION_005_AGENT_RPCS = `-- ============================================================================\n-- plugin-agenda 005: server-plane agent write RPC.\n--\n-- public.agent_agenda_create_appointment — the INTERNAL (operator-actor)\n-- counterpart of create_public_booking (001 §5): same invariants (working\n-- hours, advisory-lock race safety, hardcoded statuses), but:\n-- * actor-authorized: public.agent_guard (spine 015) runs role→plan→limit\n-- BEFORE anything — denial comes back as a structured jsonb the agent can\n-- explain conversationally, never a raised exception;\n-- * the client is an EXISTING person id (the agent resolves names→ids via\n-- reads first — ambiguity is a conversation problem, not a SQL one);\n-- * a requested professional is honored (working hours permitting);\n-- * audited: audit_logs row with the acting user.\n--\n-- Contract (all agent_* RPCs): (p_tenant_id, p_actor_user_id, p_payload jsonb)\n-- → jsonb {ok:true, id, record:{...}} | {ok:false, denial:{...}} | {ok:false,\n-- error text}. GRANT authenticated+service_role — NEVER anon (the Fayz broker\n-- calls with the pool service key and injects tenant/actor server-side).\n-- ============================================================================\n\nCREATE OR REPLACE FUNCTION public.agent_agenda_create_appointment(\n p_tenant_id uuid,\n p_actor_user_id uuid,\n p_payload jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_client_id uuid;\n v_service_id uuid;\n v_professional uuid;\n v_starts timestamptz;\n v_notes text;\n v_service record;\n v_client record;\n v_ends timestamptz;\n v_tz text;\n v_order uuid;\n v_booking uuid;\nBEGIN\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_client_id := (p_payload->>'client_id')::uuid;\n v_service_id := (p_payload->>'service_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts := (p_payload->>'starts_at')::timestamptz;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_notes := left(p_payload->>'notes', 500);\n IF v_client_id IS NULL OR v_service_id IS NULL OR v_starts IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'client_id, service_id and starts_at are required');\n END IF;\n IF v_starts <= now() OR v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be in the future (max 1 year)');\n END IF;\n\n -- ── authorization: role → plan → bookings_month cap ──────────────────────\n SELECT count(*) INTO v_used FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.created_at >= date_trunc('month', now());\n v_denial := agent_guard(p_tenant_id, p_actor_user_id,\n 'appointments', 'create', 'bookings_month', v_used, 1);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- ── invariants ───────────────────────────────────────────────────────────\n SELECT p.id, p.name INTO v_client\n FROM people p\n WHERE p.id = v_client_id AND p.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown client for this tenant');\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = v_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown or inactive service');\n END IF;\n\n v_ends := v_starts + make_interval(mins => v_service.duration_minutes);\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n\n -- requested professional honored; otherwise pick one whose hours cover the slot\n SELECT sc.assignee_id INTO v_professional\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (v_professional IS NULL OR sc.assignee_id = v_professional)\n AND (\n sc.specific_date = (v_starts AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM v_starts AT TIME ZONE v_tz)::smallint)\n )\n AND (v_starts AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_professional IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'slot outside working hours for the requested professional');\n END IF;\n\n -- race safety: serialize per (tenant, professional), then conflict-check\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error', 'slot no longer available');\n END IF;\n\n -- ── write (statuses hardcoded) + audit ───────────────────────────────────\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_client_id, v_professional,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_client_id, v_professional, v_order,\n v_starts, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_professional);\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.createAppointment', 'appointment', v_booking::text,\n jsonb_build_object('payload', p_payload, 'order_id', v_order));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_booking,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_booking, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_starts,\n 'ends_at', v_ends,\n 'client_name', v_client.name,\n 'service_name', v_service.name,\n 'price', v_service.price,\n 'status', 'scheduled'\n )\n );\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb)\n TO authenticated, service_role;\n`\n\nexport const MIGRATION_006_AGENT_RPC_LOCALTIME = `-- ============================================================================\n-- plugin-agenda 006: agent_agenda_create_appointment speaks LOCAL time.\n--\n-- Models reliably mangle UTC↔local offsets (\"10h\" became 13:00 BRT via a\n-- wrong sign). The RPC knows the tenant's timezone — so stop asking the model\n-- to convert: \\`starts_at\\` WITHOUT an offset (2026-07-27T10:00) is interpreted\n-- in the tenant tz; an explicit offset still works. The result now carries\n-- starts_at_local/ends_at_local strings so the reply echoes the truth in the\n-- user's own clock. Supersedes 005's function body (new file — applied\n-- migrations are never edited).\n-- ============================================================================\n\nCREATE OR REPLACE FUNCTION public.agent_agenda_create_appointment(\n p_tenant_id uuid,\n p_actor_user_id uuid,\n p_payload jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_client_id uuid;\n v_service_id uuid;\n v_professional uuid;\n v_starts timestamptz;\n v_starts_raw text;\n v_notes text;\n v_service record;\n v_client record;\n v_ends timestamptz;\n v_tz text;\n v_order uuid;\n v_booking uuid;\nBEGIN\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown tenant');\n END IF;\n\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_client_id := (p_payload->>'client_id')::uuid;\n v_service_id := (p_payload->>'service_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts_raw := p_payload->>'starts_at';\n IF v_starts_raw ~ '(Z|[+-][0-9]{2}:?[0-9]{2})$' THEN\n v_starts := v_starts_raw::timestamptz; -- explicit offset\n ELSE\n v_starts := (v_starts_raw::timestamp) AT TIME ZONE v_tz; -- tenant-local\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_notes := left(p_payload->>'notes', 500);\n IF v_client_id IS NULL OR v_service_id IS NULL OR v_starts IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'client_id, service_id and starts_at are required');\n END IF;\n IF v_starts <= now() OR v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be in the future (max 1 year)');\n END IF;\n\n -- ── authorization: role → plan → bookings_month cap ──────────────────────\n SELECT count(*) INTO v_used FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.created_at >= date_trunc('month', now());\n v_denial := agent_guard(p_tenant_id, p_actor_user_id,\n 'appointments', 'create', 'bookings_month', v_used, 1);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- ── invariants ───────────────────────────────────────────────────────────\n SELECT p.id, p.name INTO v_client\n FROM people p\n WHERE p.id = v_client_id AND p.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown client for this tenant');\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = v_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown or inactive service');\n END IF;\n\n v_ends := v_starts + make_interval(mins => v_service.duration_minutes);\n\n SELECT sc.assignee_id INTO v_professional\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (v_professional IS NULL OR sc.assignee_id = v_professional)\n AND (\n sc.specific_date = (v_starts AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM v_starts AT TIME ZONE v_tz)::smallint)\n )\n AND (v_starts AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n -- prefer a professional who is actually FREE at the slot (when the user\n -- did not name one, the first busy professional must not block the booking)\n AND NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = sc.assignee_id\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n )\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_professional IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'no professional is available at that slot (outside working hours or already booked). Suggest a different time. Times are tenant-local, tz ' || v_tz);\n END IF;\n\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error', 'slot no longer available');\n END IF;\n\n -- ── write + audit ────────────────────────────────────────────────────────\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_client_id, v_professional,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_client_id, v_professional, v_order,\n v_starts, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_professional);\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.createAppointment', 'appointment', v_booking::text,\n jsonb_build_object('payload', p_payload, 'order_id', v_order));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_booking,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_booking, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_starts,\n 'ends_at', v_ends,\n 'starts_at_local', to_char(v_starts AT TIME ZONE v_tz, 'YYYY-MM-DD (Dy) HH24:MI') || ' ' || v_tz,\n 'ends_at_local', to_char(v_ends AT TIME ZONE v_tz, 'HH24:MI'),\n 'client_name', v_client.name,\n 'service_name', v_service.name,\n 'price', v_service.price,\n 'status', 'scheduled'\n )\n );\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb)\n TO authenticated, service_role;\n`\n\nexport const MIGRATION_007_SCHEDULE_EXCEPTION_PRECEDENCE = `-- ============================================================================\n-- plugin-agenda 007: specific-date exceptions take PRECEDENCE over weekly hours.\n--\n-- The admin ScheduleEditor (saveException) writes two kinds of specific-date\n-- rows: 'available' = active rows with custom windows for the date; day off\n-- ('unavailable') = ONE inactive 00:00–00:00 sentinel. Until now every reader\n-- treated schedules as a flat union filtered by is_active, so:\n-- • a day off was INVISIBLE (inactive sentinel filtered out, weekly rows\n-- still matched) — the public site kept selling a day the admin closed;\n-- • an 'available' exception ADDED to the weekly hours instead of replacing\n-- them (\"horário especial\" should define the date's hours).\n--\n-- Fix: one helper — agenda_working_windows(tenant, date, assignee) — is now the\n-- single source of a day's windows: if ANY specific-date row exists for an\n-- assignee (active or sentinel), only the ACTIVE specific-date rows count for\n-- that assignee; otherwise the weekly (day_of_week) rows apply. Both readers\n-- are redefined on top of it:\n-- • get_available_slots — body otherwise identical to the latest version\n-- (google-calendar/002_smart_sync §5, tenant-wide 'block' clause KEPT);\n-- • create_public_booking — body otherwise identical to 004.\n--\n-- ORDERING: on pools with the Google Calendar connector this file must run\n-- AFTER integrations/google-calendar/migrations/002_smart_sync.sql (both\n-- redefine get_available_slots; 007 is the superset and must win). Re-running\n-- 007 last is always safe — it preserves 002's block semantics.\n-- ============================================================================\n\n-- ----------------------------------------------------------------------------\n-- §1 agenda_working_windows — the day's working windows, exception-aware.\n-- ----------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.agenda_working_windows(\n p_tenant_id uuid,\n p_date date,\n p_assignee_id uuid DEFAULT NULL\n) RETURNS TABLE (assignee_id uuid, win_start time, win_end time)\nLANGUAGE sql STABLE\nSET search_path = public\nAS $$\n WITH exc AS (\n -- Every specific-date row for the date, ACTIVE OR NOT: the inactive day-off\n -- sentinel must still suppress the weekly rows below.\n SELECT sc.assignee_id, sc.starts_at, sc.ends_at, sc.is_active\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.specific_date = p_date\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n )\n SELECT e.assignee_id, e.starts_at, e.ends_at\n FROM exc e\n WHERE e.is_active\n UNION ALL\n SELECT sc.assignee_id, sc.starts_at, sc.ends_at\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_date)::smallint\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND NOT EXISTS (SELECT 1 FROM exc e WHERE e.assignee_id = sc.assignee_id)\n$$;\n\nREVOKE ALL ON FUNCTION public.agenda_working_windows(uuid, date, uuid) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agenda_working_windows(uuid, date, uuid) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agenda_working_windows(uuid, date, uuid)\n TO authenticated, service_role;\n\n-- ----------------------------------------------------------------------------\n-- §2 get_available_slots — day_schedules now comes from the helper.\n-- Everything else is byte-identical to google-calendar/002_smart_sync §5.\n-- ----------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.get_available_slots(\n p_tenant_id uuid,\n p_date date,\n p_duration_minutes integer,\n p_assignee_id uuid DEFAULT NULL,\n p_slot_interval integer DEFAULT 30\n) RETURNS TABLE (slot_start timestamptz, slot_end timestamptz)\nLANGUAGE plpgsql STABLE SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_tz text;\nBEGIN\n -- tight validation: this function is anon-callable\n IF p_duration_minutes IS NULL OR p_duration_minutes NOT BETWEEN 5 AND 480 THEN\n RAISE EXCEPTION 'invalid duration';\n END IF;\n IF p_slot_interval IS NULL OR p_slot_interval NOT BETWEEN 5 AND 240 THEN\n RAISE EXCEPTION 'invalid interval';\n END IF;\n IF p_date IS NULL OR p_date < current_date OR p_date > current_date + 90 THEN\n RETURN;\n END IF;\n\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RETURN; END IF; -- unknown tenant → empty, not an error\n\n RETURN QUERY\n WITH day_schedules AS (\n SELECT w.assignee_id, w.win_start, w.win_end\n FROM agenda_working_windows(p_tenant_id, p_date, p_assignee_id) w\n ),\n candidate AS (\n SELECT\n ds.assignee_id,\n gs AS s_start,\n gs + make_interval(mins => p_duration_minutes) AS s_end\n FROM day_schedules ds\n CROSS JOIN LATERAL generate_series(\n (p_date + ds.win_start) AT TIME ZONE v_tz,\n ((p_date + ds.win_end) AT TIME ZONE v_tz) - make_interval(mins => p_duration_minutes),\n make_interval(mins => p_slot_interval)\n ) AS gs\n )\n SELECT DISTINCT c.s_start, c.s_end\n FROM candidate c\n WHERE NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n -- SMART SYNC (gcal 002): this professional's own bookings OR any\n -- tenant-wide BLOCK (assignee_id IS NULL AND kind='block') busy the slot.\n AND (b.assignee_id = c.assignee_id\n OR (b.assignee_id IS NULL AND b.kind = 'block'))\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < c.s_end\n AND COALESCE(b.ends_at, b.starts_at) > c.s_start\n )\n ORDER BY 1;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer) FROM public;\nGRANT EXECUTE ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer)\n TO anon, authenticated, service_role;\n\n-- ----------------------------------------------------------------------------\n-- §3 create_public_booking — professional resolution goes through the helper\n-- (a booking on a closed date now fails 'slot outside working hours').\n-- Everything else is byte-identical to 004.\n-- ----------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.create_public_booking(\n p_tenant_id uuid,\n p_service_id uuid,\n p_starts_at timestamptz,\n p_name text,\n p_phone text,\n p_email text DEFAULT NULL,\n p_notes text DEFAULT NULL,\n p_assignee_id uuid DEFAULT NULL\n) RETURNS TABLE (booking_id uuid, starts_at timestamptz, ends_at timestamptz)\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- resolve the professional: the one the visitor saw (validated), else the\n -- first whose EXCEPTION-AWARE working hours cover the slot (007)\n SELECT w.assignee_id INTO v_assignee\n FROM agenda_working_windows(\n p_tenant_id, (p_starts_at AT TIME ZONE v_tz)::date, p_assignee_id) w\n WHERE (p_starts_at AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone), serialized by advisory lock\n -- (kind is tenant-configured, so the customer-only partial index can't\n -- arbitrate)\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text, uuid) FROM public;\nGRANT EXECUTE ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text, uuid)\n TO anon, authenticated, service_role;\n`\n\nexport const MIGRATION_008_AGENT_RPC_EXCEPTION_PRECEDENCE = `-- ============================================================================\n-- plugin-agenda 008: agent_agenda_create_appointment honors schedule exceptions.\n--\n-- Same precedence fix as 007, applied to the agent write path: professional\n-- resolution now goes through agenda_working_windows (007 §1), so a date the\n-- admin closed (day-off sentinel) or re-opened with custom hours (\"horário\n-- especial\") binds the agent exactly like it binds the public site. Everything\n-- else is byte-identical to 006 (LOCAL-time input, free-professional pick,\n-- advisory lock, audit). Requires 007. Supersedes 006's function body.\n-- ============================================================================\n\nCREATE OR REPLACE FUNCTION public.agent_agenda_create_appointment(\n p_tenant_id uuid,\n p_actor_user_id uuid,\n p_payload jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_client_id uuid;\n v_service_id uuid;\n v_professional uuid;\n v_starts timestamptz;\n v_starts_raw text;\n v_notes text;\n v_service record;\n v_client record;\n v_ends timestamptz;\n v_tz text;\n v_order uuid;\n v_booking uuid;\nBEGIN\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown tenant');\n END IF;\n\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_client_id := (p_payload->>'client_id')::uuid;\n v_service_id := (p_payload->>'service_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts_raw := p_payload->>'starts_at';\n IF v_starts_raw ~ '(Z|[+-][0-9]{2}:?[0-9]{2})$' THEN\n v_starts := v_starts_raw::timestamptz; -- explicit offset\n ELSE\n v_starts := (v_starts_raw::timestamp) AT TIME ZONE v_tz; -- tenant-local\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_notes := left(p_payload->>'notes', 500);\n IF v_client_id IS NULL OR v_service_id IS NULL OR v_starts IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'client_id, service_id and starts_at are required');\n END IF;\n IF v_starts <= now() OR v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be in the future (max 1 year)');\n END IF;\n\n -- ── authorization: role → plan → bookings_month cap ──────────────────────\n SELECT count(*) INTO v_used FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.created_at >= date_trunc('month', now());\n v_denial := agent_guard(p_tenant_id, p_actor_user_id,\n 'appointments', 'create', 'bookings_month', v_used, 1);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- ── invariants ───────────────────────────────────────────────────────────\n SELECT p.id, p.name INTO v_client\n FROM people p\n WHERE p.id = v_client_id AND p.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown client for this tenant');\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = v_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown or inactive service');\n END IF;\n\n v_ends := v_starts + make_interval(mins => v_service.duration_minutes);\n\n -- exception-aware windows (007); still prefer a professional who is FREE at\n -- the slot when the user did not name one\n SELECT w.assignee_id INTO v_professional\n FROM agenda_working_windows(\n p_tenant_id, (v_starts AT TIME ZONE v_tz)::date, v_professional) w\n WHERE (v_starts AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n AND NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = w.assignee_id\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n )\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_professional IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'no professional is available at that slot (outside working hours or already booked). Suggest a different time. Times are tenant-local, tz ' || v_tz);\n END IF;\n\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error', 'slot no longer available');\n END IF;\n\n -- ── write + audit ────────────────────────────────────────────────────────\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_client_id, v_professional,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_client_id, v_professional, v_order,\n v_starts, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_professional);\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.createAppointment', 'appointment', v_booking::text,\n jsonb_build_object('payload', p_payload, 'order_id', v_order));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_booking,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_booking, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_starts,\n 'ends_at', v_ends,\n 'starts_at_local', to_char(v_starts AT TIME ZONE v_tz, 'YYYY-MM-DD (Dy) HH24:MI') || ' ' || v_tz,\n 'ends_at_local', to_char(v_ends AT TIME ZONE v_tz, 'HH24:MI'),\n 'client_name', v_client.name,\n 'service_name', v_service.name,\n 'price', v_service.price,\n 'status', 'scheduled'\n )\n );\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agent_agenda_create_appointment(uuid, uuid, jsonb)\n TO authenticated, service_role;\n`\n\nexport const MIGRATION_009_PUBLIC_BOOKING_LOCATION = `-- Public bookings were written with location_id = NULL. The agenda's location\n-- filter is optional (default \"all\"), so they still rendered — but the moment\n-- an operator filtered by their unit, every booking taken from the website\n-- disappeared from the calendar. Single-location tenants are the common case\n-- and have an unambiguous answer, so default to it; multi-location tenants\n-- stay NULL (there is no correct guess) until the public flow asks.\n--\n-- Only the assignment is new; the rest of the body is unchanged from 004.\n\nCREATE OR REPLACE FUNCTION public.create_public_booking(\n p_tenant_id uuid,\n p_service_id uuid,\n p_starts_at timestamptz,\n p_name text,\n p_phone text,\n p_email text DEFAULT NULL,\n p_notes text DEFAULT NULL\n)\nRETURNS TABLE(booking_id uuid, starts_at timestamptz, ends_at timestamptz)\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path TO 'public'\nAS $function$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_location uuid;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n\n -- pick the assignee whose working hours cover the slot\n SELECT sc.assignee_id INTO v_assignee\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (\n sc.specific_date = (p_starts_at AT TIME ZONE v_tz)::date\n OR (sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_starts_at AT TIME ZONE v_tz)::smallint)\n )\n AND (p_starts_at AT TIME ZONE v_tz)::time >= sc.starts_at\n AND (v_ends AT TIME ZONE v_tz)::time <= sc.ends_at\n ORDER BY sc.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- NEW: stamp the unit so the calendar's location filter keeps these visible.\n -- Prefer the schedule's own location; else the tenant's only location.\n SELECT sc.location_id INTO v_location\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND sc.assignee_id = v_assignee\n AND sc.location_id IS NOT NULL\n LIMIT 1;\n\n IF v_location IS NULL THEN\n SELECT l.id INTO v_location\n FROM locations l\n WHERE l.tenant_id = p_tenant_id\n HAVING count(*) = 1; -- unambiguous only\n END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- Upsert the customer by (tenant, phone). NOT ON CONFLICT: the partial unique\n -- index this used to infer is gone (spine/110 — a placeholder phone is shared\n -- by real, distinct people). 003 already settled the replacement: take a\n -- per-(tenant, phone) advisory lock so two first-bookings serialise, then look\n -- before inserting. Oldest match wins, so a returning caller keeps the record\n -- that carries their history.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = 'customer' AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, 'customer', trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, location_id,\n subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee, v_location,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id, location_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order, v_location,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$function$;\n\nGRANT EXECUTE ON FUNCTION public.create_public_booking(uuid, uuid, timestamptz, text, text, text, text) TO anon, authenticated;\n`\n\nexport const MIGRATION_010_PUBLIC_SERVICE_CURATION = `-- plugin-agenda 010: curate what the PUBLIC booking page sells.\n--\n-- v_public_services published every active service, so the website catalog was\n-- \"whatever exists in the system\". That conflates two different questions:\n--\n-- • is this service usable at all? → services.is_active / status\n-- • should a stranger be able to book it? → this flag\n--\n-- Without the split, hiding something from the site means deactivating it —\n-- which also removes it from the internal agenda and orphans its history. The\n-- case that forced this: a school whose public page listed 7 services when it\n-- sells 3, and one of the 4 extras already had real bookings attached.\n--\n-- OPT-OUT on purpose: a service is public unless explicitly marked otherwise.\n-- Opt-in would silently empty every live catalog the moment this ships.\n\nCREATE OR REPLACE VIEW public.v_public_services AS\nSELECT id,\n tenant_id,\n name,\n description,\n price,\n currency,\n COALESCE(duration_minutes, 30) AS duration_minutes,\n image_url,\n COALESCE(((metadata ->> 'sort_order'::text))::integer, 0) AS sort_order\n FROM services s\n WHERE is_active\n AND status = 'active'::text\n -- absent → public (back-compat). Only an explicit false hides it.\n AND COALESCE((metadata ->> 'bookableOnline'::text)::boolean, true);\n`\n\nexport const MIGRATION_011_DEFAULT_ASSIGNEE = `-- plugin-agenda 011: honour a tenant's default professional.\n--\n-- create_public_booking picks the assignee from whoever's working hours cover\n-- the slot, ordered by assignee_id — i.e. the lowest UUID wins. That is fine\n-- when the caller names the professional, and wrong when it does not: the\n-- public page confirms \"Equipe Great DJs\" while the booking silently lands on\n-- an unrelated instructor whose UUID happened to sort first.\n--\n-- Clients shipped before p_assignee_id existed still call this with 7 named\n-- args, so the parameter defaults to NULL and every live booking on those sites\n-- is mis-assigned today. Republishing the SDK fixes the caller, but the sites\n-- already deployed cannot be fixed that way — this can, from the database.\n--\n-- Precedence: explicit arg > tenant default > first covering schedule.\n-- Tenants without the setting keep exactly the previous behaviour.\n\nCREATE OR REPLACE FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text DEFAULT NULL::text, p_notes text DEFAULT NULL::text, p_assignee_id uuid DEFAULT NULL::uuid)\n RETURNS TABLE(booking_id uuid, starts_at timestamp with time zone, ends_at timestamp with time zone)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_requested uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- resolve the professional, in order of trust:\n -- 1. the id the caller sent (the one the visitor actually saw)\n -- 2. the tenant's configured default (settings->>'defaultAssigneeId')\n -- 3. whoever's working hours cover the slot\n --\n -- Step 2 is why this migration exists. Older published clients call this with\n -- 7 named args, leaving p_assignee_id NULL, and step 3 then resolved to\n -- \"lowest assignee UUID\" — an arbitrary instructor who had nothing to do with\n -- the name the site displayed on the confirmation screen. The default gives\n -- those clients a correct answer without waiting for a redeploy.\n v_requested := COALESCE(\n p_assignee_id,\n (SELECT NULLIF(t.settings ->> 'defaultAssigneeId', '')::uuid\n FROM tenants t WHERE t.id = p_tenant_id)\n );\n\n SELECT w.assignee_id INTO v_assignee\n FROM agenda_working_windows(\n p_tenant_id, (p_starts_at AT TIME ZONE v_tz)::date, v_requested) w\n WHERE (p_starts_at AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone), serialized by advisory lock\n -- (kind is tenant-configured, so the customer-only partial index can't\n -- arbitrate)\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$function$;\n`\n\nexport const MIGRATION_012_DROP_LEGACY_BOOKING_OVERLOAD = `-- plugin-agenda 012: retire the pre-assignee create_public_booking overload.\n--\n-- ⚠️ DO NOT APPLY UNTIL @fayz-ai/plugin-agenda IS REPUBLISHED *AND* EVERY LIVE\n-- SITE HAS BEEN REDEPLOYED. Applying early breaks public booking on any\n-- site still serving a bundle that calls the 7-argument signature — the\n-- call stops resolving and every submission fails.\n--\n-- Some pools carry two overloads side by side:\n-- create_public_booking(uuid,uuid,timestamptz,text,text,text,text)\n-- create_public_booking(uuid,uuid,timestamptz,text,text,text,text,uuid)\n--\n-- Nothing errors when both exist, which is exactly the problem: a stale client\n-- silently resolves to the 7-arg one, which cannot know which professional the\n-- visitor was shown and falls back to \"lowest assignee UUID\". The site confirms\n-- one name, the agenda records another, and no one finds out until someone\n-- compares the two screens.\n--\n-- 011 makes that fallback survivable (tenant default). This makes it\n-- impossible — but only once no caller needs the old signature.\n--\n-- Verify before running:\n-- 1. npm view @fayz-ai/plugin-agenda version → the republished version\n-- 2. every deployed bundle greps for p_assignee_id:\n-- curl -s https://<site>/assets/index-*.js | grep -c p_assignee_id\n-- Each must be ≥ 2 (slots + booking). Zero means that site still needs it.\n\nDROP FUNCTION IF EXISTS public.create_public_booking(\n uuid, uuid, timestamptz, text, text, text, text\n);\n`\n\nexport const MIGRATION_013_NORMALIZE_V_APPOINTMENTS = `-- plugin-agenda 013: one booking read model — v_appointments.\n--\n-- Three views described the same 34 rows:\n--\n-- v_bookings → thin alias over the legacy view (002 compat shim)\n-- v_bookings_legacy_beauty → the pre-pools shape, still feeding 5 rep_* views\n-- v_appointments → the canonical name, and the only one the SDK reads\n--\n-- The school pool already had only v_appointments; the salon pool carried all\n-- three. Same data, three names, and reports quietly wired to the oldest one.\n--\n-- v_appointments was a strict SUBSET, so it could not simply absorb them. It\n-- gains the 7 columns it lacked — most importantly \\`services\\`, the order_items\n-- aggregate that 4 of the 5 reports depend on. That also retires a documented\n-- N+1: getBookingById fetches order_items in a second round-trip precisely\n-- because this view had no line items (see plugin-agenda/src/data/supabase.ts).\n--\n-- Deliberately NOT copied from the legacy view:\n-- • total_duration_minutes — legacy sums order_items durations, the canonical\n-- measures the slot. They disagree, no report reads it, and the SDK relies\n-- on the canonical meaning. Kept as-is.\n-- • client_name — the canonical COALESCEs with metadata->>'title' so blocks\n-- and personal events show a label instead of NULL. Kept as-is (an\n-- improvement the legacy shape never had).\n\n-- 1. v_appointments becomes the superset. Columns are APPENDED: CREATE OR\n-- REPLACE VIEW cannot reorder or drop, and the SDK selects '*'.\nCREATE OR REPLACE VIEW public.v_appointments\nWITH (security_invoker = true) AS\n SELECT b.id,\n b.tenant_id,\n b.kind,\n b.starts_at,\n b.ends_at,\n b.status,\n b.notes,\n b.order_id,\n b.location_id,\n b.metadata,\n b.created_at,\n b.updated_at,\n b.party_id AS client_id,\n COALESCE(pc.name, (b.metadata ->> 'title'::text)) AS client_name,\n pc.phone AS client_phone,\n pc.email AS client_email,\n pc.avatar_url AS client_avatar_url,\n b.assignee_id AS professional_id,\n ps.name AS professional_name,\n ps.avatar_url AS professional_avatar_url,\n l.name AS location_name,\n o.total AS order_total,\n o.status AS order_status,\n ((EXTRACT(epoch FROM (COALESCE(b.ends_at, b.starts_at) - b.starts_at)))::integer / 60) AS total_duration_minutes,\n -- appended:\n o.reference_number,\n o.status AS stage,\n (o.metadata ->> 'direction'::text) AS direction,\n ( SELECT json_agg(json_build_object('id', oi.id, 'serviceId', oi.service_id,\n 'name', oi.name, 'durationMinutes', oi.duration_minutes,\n 'price', oi.unit_price, 'assigneeId', oi.assignee_id)\n ORDER BY oi.sort_order)\n FROM order_items oi\n WHERE (oi.order_id = b.order_id)) AS services,\n inv.status AS payment_status,\n inv.paid AS order_paid,\n inv.balance AS order_balance\n FROM (((((appointments b\n LEFT JOIN people pc ON ((pc.id = b.party_id)))\n LEFT JOIN people ps ON ((ps.id = b.assignee_id)))\n LEFT JOIN locations l ON ((l.id = b.location_id)))\n LEFT JOIN orders o ON ((o.id = b.order_id)))\n LEFT JOIN v_invoice_balances inv ON ((inv.invoice_id = b.order_id)));\n\n-- 2. Repoint the reports off the legacy view. Bodies are unchanged\n-- except for the source relation.\n\nCREATE OR REPLACE VIEW public.rep_appointments_by_period AS\nSELECT tenant_id,\n id AS booking_id,\n (starts_at)::date AS date,\n starts_at,\n client_id,\n client_name,\n professional_id,\n professional_name,\n COALESCE(((services -> 0) ->> 'name'::text), ((services -> 0) ->> 'serviceName'::text)) AS service_name,\n status,\n order_total AS revenue,\n created_at,\n updated_at\n FROM v_appointments b;\n\n-- legacy_pre_pools only exists on pools migrated from the pre-pool era; fresh\n-- pools get the same shape with confirmation columns defaulting to pending/NULL.\nDO $$\nBEGIN\n IF to_regclass('legacy_pre_pools.appointments') IS NOT NULL THEN\n EXECUTE $v$\n CREATE OR REPLACE VIEW public.rep_confirmation_queue AS\n SELECT b.tenant_id,\n b.id AS booking_id,\n (b.starts_at)::date AS date,\n b.starts_at,\n b.client_id,\n b.client_name,\n b.professional_id,\n b.professional_name,\n COALESCE(((b.services -> 0) ->> 'name'::text), ((b.services -> 0) ->> 'serviceName'::text)) AS service_name,\n COALESCE(a.confirmation_status, 'pending'::text) AS confirmation_status,\n a.confirmation_channel,\n a.confirmation_sent_at,\n a.confirmed_at,\n b.created_at,\n b.updated_at\n FROM (v_appointments b\n LEFT JOIN legacy_pre_pools.appointments a ON ((a.booking_id = b.id)))\n WHERE ((b.status <> ALL (ARRAY['cancelled'::text, 'no_show'::text])) AND (b.starts_at >= (now() - '1 day'::interval)))\n $v$;\n ELSE\n EXECUTE $v$\n CREATE OR REPLACE VIEW public.rep_confirmation_queue AS\n SELECT b.tenant_id,\n b.id AS booking_id,\n (b.starts_at)::date AS date,\n b.starts_at,\n b.client_id,\n b.client_name,\n b.professional_id,\n b.professional_name,\n COALESCE(((b.services -> 0) ->> 'name'::text), ((b.services -> 0) ->> 'serviceName'::text)) AS service_name,\n 'pending'::text AS confirmation_status,\n NULL::text AS confirmation_channel,\n NULL::timestamptz AS confirmation_sent_at,\n NULL::timestamptz AS confirmed_at,\n b.created_at,\n b.updated_at\n FROM v_appointments b\n WHERE ((b.status <> ALL (ARRAY['cancelled'::text, 'no_show'::text])) AND (b.starts_at >= (now() - '1 day'::interval)))\n $v$;\n END IF;\nEND $$;\n\n-- v_clients (beauty Ring-2 extension) may not exist on non-salon pools — the\n-- report only makes sense where it does.\nDO $$\nBEGIN\n IF to_regclass('public.v_clients') IS NULL THEN RETURN; END IF;\n EXECUTE $v$\n CREATE OR REPLACE VIEW public.rep_new_clients AS\n SELECT c.tenant_id,\n c.id AS client_id,\n (c.created_at)::date AS date,\n c.name AS client_name,\n c.origin,\n first_booking.service_name AS first_service,\n c.created_at,\n c.updated_at\n FROM (v_clients c\n LEFT JOIN LATERAL ( SELECT COALESCE(((b.services -> 0) ->> 'name'::text), ((b.services -> 0) ->> 'serviceName'::text)) AS service_name\n FROM v_appointments b\n WHERE (b.client_id = c.id)\n ORDER BY b.starts_at\n LIMIT 1) first_booking ON (true))\n $v$;\nEND $$;\n\nCREATE OR REPLACE VIEW public.rep_revenue_by_professional AS\nSELECT tenant_id,\n (starts_at)::date AS date,\n professional_id,\n COALESCE(professional_name, 'Sem profissional'::text) AS professional_name,\n (count(*))::integer AS appointment_count,\n (COALESCE(sum(NULLIF(order_total, (0)::numeric)), (0)::numeric))::numeric(14,2) AS total_revenue,\n (COALESCE(avg(NULLIF(order_total, (0)::numeric)), (0)::numeric))::numeric(14,2) AS avg_ticket,\n (0)::numeric(14,2) AS commission,\n max(updated_at) AS updated_at\n FROM v_appointments b\n WHERE (status <> ALL (ARRAY['cancelled'::text, 'no_show'::text]))\n GROUP BY tenant_id, ((starts_at)::date), professional_id, COALESCE(professional_name, 'Sem profissional'::text);\n\nCREATE OR REPLACE VIEW public.rep_revenue_by_service AS\nSELECT b.tenant_id,\n (b.starts_at)::date AS date,\n NULLIF((service_item.value ->> 'serviceId'::text), ''::text) AS service_id,\n COALESCE((service_item.value ->> 'name'::text), (service_item.value ->> 'serviceName'::text), 'Sem servico'::text) AS service_name,\n (count(DISTINCT b.id))::integer AS quantity,\n (COALESCE(sum((NULLIF((service_item.value ->> 'price'::text), ''::text))::numeric), (0)::numeric))::numeric(14,2) AS total_revenue,\n (COALESCE(avg((NULLIF((service_item.value ->> 'price'::text), ''::text))::numeric), (0)::numeric))::numeric(14,2) AS avg_ticket,\n max(b.updated_at) AS updated_at\n FROM (v_appointments b\n CROSS JOIN LATERAL jsonb_array_elements(COALESCE((b.services)::jsonb, '[]'::jsonb)) service_item(value))\n WHERE (b.status <> ALL (ARRAY['cancelled'::text, 'no_show'::text]))\n GROUP BY b.tenant_id, ((b.starts_at)::date), NULLIF((service_item.value ->> 'serviceId'::text), ''::text), COALESCE((service_item.value ->> 'name'::text), (service_item.value ->> 'serviceName'::text), 'Sem servico'::text);\n\n-- 3. Retire the duplicates. v_bookings goes first: it reads the legacy view.\n-- Nothing in the SDK references either name (checked: only migrations and a\n-- README mention v_bookings).\nDROP VIEW IF EXISTS public.v_bookings;\nDROP VIEW IF EXISTS public.v_bookings_legacy_beauty;\n`\n\nexport const MIGRATION_014_AGENT_RPC_UPDATE_APPOINTMENT = `-- ============================================================================\n-- plugin-agenda 014: agent_agenda_update_appointment — remarcar / reatribuir /\n-- cancelar um agendamento existente.\n--\n-- Lacuna que isso fecha: o agente sabia CRIAR e não sabia MEXER. Pedido real\n-- (\"remarca esse paciente pra 16:30\") caía no updateRecord genérico, que bate\n-- em v_appointments — uma view — e devolve read_only; o modelo então \"resolvia\"\n-- abrindo um agendamento NOVO, deixando o antigo de pé. Duplicar a agenda de um\n-- salão é pior do que não fazer nada.\n--\n-- Mesma cadeia de guardas do 008 (agent_guard → janela de trabalho com exceções\n-- → lock advisory → checagem de conflito → auditoria), com três diferenças:\n-- • ação 'edit', sem cota (remarcar não consome bookings_month);\n-- • o próprio agendamento é excluído da checagem de conflito consigo mesmo;\n-- • cancelar não precisa de horário livre — só o guard.\n-- Requer 007 (agenda_working_windows). Idempotente.\n-- ============================================================================\n\nCREATE OR REPLACE FUNCTION public.agent_agenda_update_appointment(\n p_tenant_id uuid,\n p_actor_user_id uuid,\n p_payload jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_denial jsonb;\n v_id uuid;\n v_tz text;\n v_row record;\n v_starts_raw text;\n v_starts timestamptz;\n v_ends timestamptz;\n v_duration int;\n v_professional uuid;\n v_status text;\n v_notes text;\n v_wants_move boolean;\n v_wants_status boolean;\nBEGIN\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown tenant');\n END IF;\n\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_id := (p_payload->>'appointment_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts_raw := p_payload->>'starts_at';\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_status := nullif(trim(lower(p_payload->>'status')), '');\n v_notes := left(p_payload->>'notes', 500);\n v_wants_move := v_starts_raw IS NOT NULL OR v_professional IS NOT NULL;\n v_wants_status := v_status IS NOT NULL;\n\n IF v_id IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'appointment_id is required — search the agenda first and reuse the id of the appointment to change');\n END IF;\n IF NOT v_wants_move AND NOT v_wants_status AND v_notes IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'nothing to change: send starts_at, professional_id, status or notes');\n END IF;\n IF v_status IS NOT NULL\n AND v_status NOT IN ('scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show') THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'status must be one of scheduled, confirmed, in_progress, completed, cancelled, no_show');\n END IF;\n\n -- ── the appointment must exist, in THIS tenant ───────────────────────────\n SELECT b.id, b.starts_at, b.ends_at, b.assignee_id, b.status, b.party_id, b.order_id\n INTO v_row\n FROM appointments b\n WHERE b.id = v_id AND b.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown appointment for this tenant');\n END IF;\n\n -- ── authorization: role → plan. No cap: editing frees nothing and buys\n -- nothing, so charging bookings_month for a reschedule would be wrong.\n v_denial := agent_guard(p_tenant_id, p_actor_user_id, 'appointments', 'edit');\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- Duration is preserved across a move — a 60-minute appointment stays 60.\n v_duration := GREATEST(\n COALESCE(EXTRACT(EPOCH FROM (v_row.ends_at - v_row.starts_at)) / 60, 30)::int, 5);\n v_professional := COALESCE(v_professional, v_row.assignee_id);\n\n IF v_wants_move THEN\n IF v_starts_raw IS NOT NULL THEN\n BEGIN\n IF v_starts_raw ~ '(Z|[+-][0-9]{2}:?[0-9]{2})$' THEN\n v_starts := v_starts_raw::timestamptz; -- explicit offset\n ELSE\n v_starts := (v_starts_raw::timestamp) AT TIME ZONE v_tz; -- tenant-local\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid starts_at: ' || SQLERRM);\n END;\n ELSE\n v_starts := v_row.starts_at;\n END IF;\n v_ends := v_starts + make_interval(mins => v_duration);\n\n IF v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be within the next year');\n END IF;\n\n -- Working window (exception-aware, 007) for the target professional.\n IF NOT EXISTS (\n SELECT 1\n FROM agenda_working_windows(\n p_tenant_id, (v_starts AT TIME ZONE v_tz)::date, v_professional) w\n WHERE w.assignee_id = v_professional\n AND (v_starts AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'that slot is outside the professional''s working hours. Suggest a different time. Times are tenant-local, tz ' || v_tz);\n END IF;\n\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.id <> v_id -- never conflicts with itself\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'that slot is already taken. Suggest a different time.');\n END IF;\n END IF;\n\n -- ── write + audit ────────────────────────────────────────────────────────\n UPDATE appointments b SET\n starts_at = COALESCE(v_starts, b.starts_at),\n ends_at = COALESCE(v_ends, b.ends_at),\n assignee_id = v_professional,\n status = COALESCE(v_status, b.status),\n notes = COALESCE(v_notes, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || jsonb_build_object('lastAgentEdit', now()),\n updated_at = now()\n WHERE b.id = v_id AND b.tenant_id = p_tenant_id;\n\n -- The order mirrors the appointment's assignee/status so the financial side\n -- does not drift from the calendar.\n IF v_row.order_id IS NOT NULL THEN\n UPDATE orders o SET\n assignee_id = v_professional,\n status = CASE WHEN v_status = 'cancelled' THEN 'cancelled' ELSE o.status END,\n updated_at = now()\n WHERE o.id = v_row.order_id AND o.tenant_id = p_tenant_id;\n END IF;\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.updateAppointment', 'appointment', v_id::text,\n jsonb_build_object('payload', p_payload,\n 'previous', jsonb_build_object(\n 'starts_at', v_row.starts_at,\n 'ends_at', v_row.ends_at,\n 'assignee_id', v_row.assignee_id,\n 'status', v_row.status)));\n\n SELECT a.id, a.starts_at, a.ends_at, a.status, a.client_name, a.professional_name\n INTO v_row\n FROM v_appointments a WHERE a.id = v_id;\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_id,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_id, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_row.starts_at,\n 'ends_at', v_row.ends_at,\n 'starts_at_local', to_char(v_row.starts_at AT TIME ZONE v_tz, 'YYYY-MM-DD (Dy) HH24:MI') || ' ' || v_tz,\n 'ends_at_local', to_char(v_row.ends_at AT TIME ZONE v_tz, 'HH24:MI'),\n 'client_name', v_row.client_name,\n 'professional_name', v_row.professional_name,\n 'status', v_row.status\n )\n );\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_update_appointment(uuid, uuid, jsonb) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agent_agenda_update_appointment(uuid, uuid, jsonb) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agent_agenda_update_appointment(uuid, uuid, jsonb)\n TO authenticated, service_role;\n`\n\nexport const MIGRATION_015_ANALYTICS_READ_MODELS = `-- ============================================================================\n-- @fayz-ai/plugin-agenda — read model for the analytics engine, and the\n-- security_invoker the report views never got.\n--\n-- TWO THINGS, and the first one is a hole, not a feature.\n--\n-- 1. rep_appointments_by_period, rep_revenue_by_service and\n-- rep_revenue_by_professional were created without\n-- \\`WITH (security_invoker = true)\\`. A view runs as its OWNER, migrations are\n-- applied as \\`postgres\\`, and a table owner is exempt from that table's RLS —\n-- so on a shared industry pool any signed-in user of ANY tenant could read\n-- every tenant's agenda revenue. The spine's 044_view_invoker.sql closes it\n-- everywhere at once; this carries the fix home to the plugin that owns the\n-- views, as that file asks. ALTER VIEW ... SET is additive and idempotent,\n-- so the two agree wherever both land.\n--\n-- Registering a leaky view in the analytics allowlist would have WIDENED it:\n-- analytics_run takes the tenant id as a PARAMETER, so without invoker\n-- semantics a client could simply pass somebody else's. The tenant predicate\n-- is defence in depth; RLS is the lock.\n--\n-- 2. plg_agenda_rep_bookings — rep_appointments_by_period plus the 0/1 flags.\n-- The engine has no conditional aggregate (see 024), so \"no-show rate\" and\n-- \"revenue actually earned\" cannot be expressed by a card over the raw view:\n-- its \\`revenue\\` is order_total on EVERY row, which bills the school for the\n-- lesson the student skipped. The flags put the condition in the read model,\n-- where it can be read once and audited.\n--\n-- Idempotent. Guarded per object, so a pool without the agenda skips it.\n-- ============================================================================\n\n-- ----------------------------------------------------------------------------\n-- 1. Close the leak on the existing report views.\n-- ----------------------------------------------------------------------------\nDO $$\nDECLARE\n v text;\n leaky text[] := ARRAY[\n 'rep_appointments_by_period',\n 'rep_revenue_by_service',\n 'rep_revenue_by_professional',\n 'rep_confirmation_queue'\n ];\nBEGIN\n FOREACH v IN ARRAY leaky LOOP\n IF to_regclass('public.' || v) IS NOT NULL THEN\n EXECUTE format('ALTER VIEW public.%I SET (security_invoker = true)', v);\n END IF;\n END LOOP;\nEND $$;\n\n-- ----------------------------------------------------------------------------\n-- 2. The analytics read model.\n--\n-- \\`date\\` is the spine, not created_at: a booking is measured by when it\n-- HAPPENS, so a range that reads \"this month\" must return this month's\n-- lessons and not the ones typed into the system this month.\n-- ----------------------------------------------------------------------------\nDO $$\nBEGIN\n IF to_regclass('public.rep_appointments_by_period') IS NULL THEN\n RAISE NOTICE 'agenda: rep_appointments_by_period missing — read model skipped';\n RETURN;\n END IF;\n\n EXECUTE $v$\n CREATE OR REPLACE VIEW public.plg_agenda_rep_bookings\n WITH (security_invoker = true) AS\n SELECT\n b.tenant_id,\n b.booking_id,\n b.date,\n b.starts_at,\n b.client_id,\n b.client_name,\n b.professional_id,\n b.professional_name,\n b.service_name,\n b.status,\n b.revenue AS booked_revenue,\n -- What the chair actually earned, and what it did not.\n CASE WHEN b.status IN ('cancelled', 'no_show') THEN 0 ELSE COALESCE(b.revenue, 0) END AS effective_revenue,\n CASE WHEN b.status IN ('cancelled', 'no_show') THEN COALESCE(b.revenue, 0) ELSE 0 END AS lost_revenue,\n CASE WHEN b.status = 'completed' THEN 1 ELSE 0 END AS is_completed,\n CASE WHEN b.status = 'cancelled' THEN 1 ELSE 0 END AS is_cancelled,\n CASE WHEN b.status = 'no_show' THEN 1 ELSE 0 END AS is_no_show,\n b.created_at,\n b.updated_at\n FROM public.rep_appointments_by_period b\n $v$;\n\n GRANT SELECT ON public.plg_agenda_rep_bookings TO authenticated;\nEND $$;\n\n-- ----------------------------------------------------------------------------\n-- 3. Register.\n-- ----------------------------------------------------------------------------\nDO $$\nBEGIN\n IF to_regclass('public.plg_analytics_read_models') IS NULL THEN\n RAISE NOTICE 'agenda: analytics engine not installed — read models not registered';\n RETURN;\n END IF;\n\n IF to_regclass('public.plg_agenda_rep_bookings') IS NOT NULL THEN\n INSERT INTO public.plg_analytics_read_models (name, date_column, tenant_column, description) VALUES\n ('plg_agenda_rep_bookings', 'date', 'tenant_id',\n 'One row per booking, dated by when it happens, with status flags and earned/lost revenue')\n ON CONFLICT (name) DO UPDATE\n SET date_column = EXCLUDED.date_column,\n tenant_column = EXCLUDED.tenant_column,\n description = EXCLUDED.description;\n END IF;\n\n IF to_regclass('public.rep_revenue_by_service') IS NOT NULL THEN\n INSERT INTO public.plg_analytics_read_models (name, date_column, tenant_column, description) VALUES\n ('rep_revenue_by_service', 'date', 'tenant_id',\n 'Revenue per service per day; cancellations and no-shows already excluded')\n ON CONFLICT (name) DO UPDATE\n SET date_column = EXCLUDED.date_column,\n tenant_column = EXCLUDED.tenant_column,\n description = EXCLUDED.description;\n END IF;\n\n IF to_regclass('public.rep_revenue_by_professional') IS NOT NULL THEN\n INSERT INTO public.plg_analytics_read_models (name, date_column, tenant_column, description) VALUES\n ('rep_revenue_by_professional', 'date', 'tenant_id',\n 'Revenue per professional per day; cancellations and no-shows already excluded')\n ON CONFLICT (name) DO UPDATE\n SET date_column = EXCLUDED.date_column,\n tenant_column = EXCLUDED.tenant_column,\n description = EXCLUDED.description;\n END IF;\nEND $$;\n`\n\nexport const MIGRATION_016_PUBLIC_SERVICES_RELEASE = `-- 016_public_services_release.sql\n--\n-- A service released only to one unit was bookable by anyone. Fix for #201.\n--\n-- \\`v_public_services\\` is the anonymous booking catalog. It runs with owner\n-- rights on purpose — anon holds no membership and no tenant claim, so under\n-- \\`security_invoker\\` the RLS on products/services would return nothing and the\n-- public page would go blank. That is the right call, but it means the release\n-- rule #139 put on the internal path never applied here:\n--\n-- products_available_in (075:77) is RESTRICTIVE … TO authenticated\n--\n-- so \\`available_in\\` governed every logged-in reader and nobody else. A service\n-- released to branch B1 alone was listed, and bookable, to the whole internet.\n--\n-- The public catalog is TENANT-wide: create_public_booking takes p_tenant_id and\n-- no unit, so there is no unit context in which \"released to B1\" could be\n-- honoured. A unit-restricted service is therefore not a public offering, and\n-- the view says so — the same rule the internal path uses (\"no available_in\n-- tuple ⇒ everywhere\"), read from the anonymous side where \"everywhere\" is the\n-- only scope that exists.\n--\n-- Consequence worth stating plainly: a service released per unit disappears from\n-- the public page. That is the fix, not a side effect — until the public path\n-- carries a unit, listing it publicly is the bug. The booking RPC refuses it too,\n-- so a stale service id cannot walk in through the back door.\n--\n-- Replay-safe: CREATE OR REPLACE on both objects, no DDL, no data touched.\n\nCREATE OR REPLACE VIEW public.v_public_services AS\nSELECT s.id,\n s.tenant_id,\n s.name,\n s.description,\n s.price,\n s.currency,\n COALESCE(s.duration_minutes, 30) AS duration_minutes,\n s.image_url,\n COALESCE(((s.metadata ->> 'sort_order'::text))::integer, 0) AS sort_order\n FROM services s\n WHERE s.is_active\n AND s.status = 'active'::text\n -- absent → public (back-compat). Only an explicit false hides it.\n AND COALESCE((s.metadata ->> 'bookableOnline'::text)::boolean, true)\n -- …and released to everywhere, not to particular units (#201). A tuple here\n -- means \"these units only\", which the tenant-wide public page cannot honour.\n AND NOT EXISTS (\n SELECT 1 FROM app.resource_grants g\n WHERE g.tenant_id = s.tenant_id\n AND g.resource_type = 'catalog.product'\n AND g.resource_id = s.id\n AND g.relation = 'available_in');\n\nCOMMENT ON VIEW public.v_public_services IS\n 'Anonymous booking catalog. Owner-rights on purpose (anon has no tenant claim), so the release rule is written into the body: only services with no available_in tuple are public — see #201.';\n\n-- The RPC must agree with the view, or the id from a cached page still books.\nCREATE OR REPLACE FUNCTION public.agenda_assert_service_is_public(p_tenant_id uuid, p_service_id uuid)\nRETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF EXISTS (SELECT 1 FROM app.resource_grants g\n WHERE g.tenant_id = p_tenant_id\n AND g.resource_type = 'catalog.product'\n AND g.resource_id = p_service_id\n AND g.relation = 'available_in') THEN\n RAISE EXCEPTION 'este serviço não está disponível para agendamento online'\n USING ERRCODE = '42501',\n HINT = 'The service is released to specific units; the public booking path is tenant-wide and cannot honour a unit release (#201).';\n END IF;\nEND $$;\nREVOKE ALL ON FUNCTION public.agenda_assert_service_is_public(uuid, uuid) FROM public, anon, authenticated;\n\n-- create_public_booking re-emitted from 011 with exactly one line added: the\n-- assert above, right after the service is resolved. Everything else is 011's\n-- body verbatim, so this is a guard, not a rewrite.\nCREATE OR REPLACE FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text DEFAULT NULL::text, p_notes text DEFAULT NULL::text, p_assignee_id uuid DEFAULT NULL::uuid)\n RETURNS TABLE(booking_id uuid, starts_at timestamp with time zone, ends_at timestamp with time zone)\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO 'public'\nAS $function$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_requested uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n -- …and it must be a PUBLIC service, not merely an existing one. A service\n -- released to particular units is not a tenant-wide offering, and this path has\n -- no unit to honour the release in; without this an id from a cached page still\n -- booked what the catalog no longer lists (#201).\n PERFORM public.agenda_assert_service_is_public(p_tenant_id, p_service_id);\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- resolve the professional, in order of trust:\n -- 1. the id the caller sent (the one the visitor actually saw)\n -- 2. the tenant's configured default (settings->>'defaultAssigneeId')\n -- 3. whoever's working hours cover the slot\n --\n -- Step 2 is why this migration exists. Older published clients call this with\n -- 7 named args, leaving p_assignee_id NULL, and step 3 then resolved to\n -- \"lowest assignee UUID\" — an arbitrary instructor who had nothing to do with\n -- the name the site displayed on the confirmation screen. The default gives\n -- those clients a correct answer without waiting for a redeploy.\n v_requested := COALESCE(\n p_assignee_id,\n (SELECT NULLIF(t.settings ->> 'defaultAssigneeId', '')::uuid\n FROM tenants t WHERE t.id = p_tenant_id)\n );\n\n SELECT w.assignee_id INTO v_assignee\n FROM agenda_working_windows(\n p_tenant_id, (p_starts_at AT TIME ZONE v_tz)::date, v_requested) w\n WHERE (p_starts_at AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone), serialized by advisory lock\n -- (kind is tenant-configured, so the customer-only partial index can't\n -- arbitrate)\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO order_items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$function$;\n`\n\nexport const MIGRATION_017_BOOKING_CHANNEL_REPLY = `-- ============================================================================\n-- plugin-agenda 016: plg_booking_apply_channel_reply — the customer tapped\n-- Confirmar, and the horário actually changes.\n--\n-- This is the whole point of the WhatsApp wave. Legacy beautyplace matched the\n-- WORD the customer typed (\"sim\", \"confirmo\"), which had no way to know WHICH\n-- appointment was meant and so confirmed every future one they had; the\n-- workaround was a 48-hour re-enrichment subsystem that existed only to guess.\n-- The button carries the appointment id in its payload, so there is nothing to\n-- guess — and this function is the other half: the id arrives, the state\n-- machine is checked, one row changes.\n--\n-- SERVICE-ROLE ONLY. The caller is the tyxter-webhook edge function, acting on\n-- a signed delivery from the provider — there is no session and no auth.uid().\n-- That is also why the tenant is not a parameter: it is READ from the\n-- appointment. A tenant id in the signature would be a tenant id the caller\n-- could get wrong, and the caller is code reacting to the outside world.\n--\n-- Idempotent by design, not by luck: re-applying an action that already\n-- happened returns the current state with \\`changed: false\\` and emits NOTHING.\n-- Tyxter delivers at least once, so the same tap arrives twice as a matter of\n-- routine, and a second \\`agenda.booking_cancelled\\` would send the customer a\n-- second cancellation message for one cancellation.\n-- Idempotent + safe to re-run.\n-- ============================================================================\n\n-- \\`p_expect_tenant_id\\` is the caller saying which tenant it BELIEVES this\n-- booking belongs to, and it is the difference between a safe function and a\n-- way to confirm any appointment in the pool by guessing a uuid. The button\n-- payload arrives from a customer's phone; WhatsApp echoes back the id we put\n-- on the button, and nothing stops a crafted client from echoing a different\n-- one. The webhook knows which tenant the CONVERSATION belongs to, and that is\n-- the claim checked here — before the update, not after it.\n--\n-- A mismatch answers \\`not_found\\` and not \\`not_allowed\\`, deliberately: the two\n-- would let a prober tell \"this uuid is somebody's appointment\" from \"this uuid\n-- is nothing\", which is a booking-id oracle.\nCREATE OR REPLACE FUNCTION public.plg_booking_apply_channel_reply(\n p_booking_id uuid,\n p_action text,\n p_expect_tenant_id uuid DEFAULT NULL\n) RETURNS jsonb\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public\nAS $fn$\nDECLARE\n v_action text := nullif(trim(lower(p_action)), '');\n v_target text;\n v_row record;\n v_tz text;\n v_starts timestamptz;\n v_event text;\n v_payload jsonb;\nBEGIN\n IF v_action IS NULL OR v_action NOT IN ('confirm', 'cancel') THEN\n RETURN jsonb_build_object('result', 'not_allowed', 'reason', 'unknown_action');\n END IF;\n IF p_booking_id IS NULL THEN\n RETURN jsonb_build_object('result', 'not_found', 'reason', 'no_booking_id');\n END IF;\n\n v_target := CASE WHEN v_action = 'confirm' THEN 'confirmed' ELSE 'cancelled' END;\n\n -- FOR UPDATE, because two deliveries of the same tap race each other and the\n -- loser must read the state the winner wrote, not the state both started from.\n SELECT b.id, b.tenant_id, b.status, b.starts_at\n INTO v_row\n FROM public.appointments b\n WHERE b.id = p_booking_id\n FOR UPDATE;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('result', 'not_found', 'booking_id', p_booking_id);\n END IF;\n\n IF p_expect_tenant_id IS NOT NULL AND v_row.tenant_id <> p_expect_tenant_id THEN\n RETURN jsonb_build_object('result', 'not_found', 'booking_id', p_booking_id);\n END IF;\n\n -- Already there. The answer is the outcome, not an error: the customer sees\n -- \"confirmado\" either way, and a webhook that 500s on a duplicate is a\n -- webhook Tyxter retries eight times over a day and a half.\n IF v_row.status = v_target THEN\n RETURN jsonb_build_object(\n 'result', v_target, 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n -- Confirming is only meaningful from the two states that mean \"not settled\n -- yet\". 'pending' is the table's own DEFAULT and 'scheduled' is what every\n -- write path sets, so both are live appointments awaiting the customer.\n -- Confirming a completed or cancelled one would rewrite history.\n IF v_action = 'confirm' AND v_row.status NOT IN ('pending', 'scheduled') THEN\n RETURN jsonb_build_object(\n 'result', 'not_allowed', 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n -- Cancelling is allowed from anything that has not already ENDED. A confirmed\n -- appointment can still be cancelled — that is the ordinary case — but one\n -- already cancelled or already completed cannot.\n IF v_action = 'cancel' AND v_row.status IN ('cancelled', 'completed') THEN\n RETURN jsonb_build_object(\n 'result', 'not_allowed', 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n UPDATE public.appointments\n SET status = v_target, updated_at = now()\n WHERE id = v_row.id;\n\n -- ── the fact ──────────────────────────────────────────────────────────────\n -- Emitted HERE and not by the caller. The write happened in the database, so\n -- the browser emitter never sees it (packages/db/migrations/027 is the whole\n -- argument), and a webhook that updated the row and then failed to post the\n -- event would leave a confirmed appointment nobody was told about.\n --\n -- The payload is BOOKING_FIELDS from plugin-agenda's message-events.ts, field\n -- for field, so an automation reacting to a WhatsApp confirmation renders the\n -- same message as one reacting to a confirmation made in the app.\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM public.tenants t WHERE t.id = v_row.tenant_id;\n v_tz := COALESCE(v_tz, 'America/Sao_Paulo');\n v_starts := v_row.starts_at;\n\n SELECT jsonb_build_object(\n 'customer_name', COALESCE(a.client_name, ''),\n 'service_name', COALESCE((\n SELECT string_agg(s->>'name', ' + ')\n FROM jsonb_array_elements(COALESCE(a.services::jsonb, '[]'::jsonb)) AS s), ''),\n 'professional_name', COALESCE(a.professional_name, ''),\n 'booking_date', to_char(v_starts AT TIME ZONE v_tz, 'DD/MM/YYYY'),\n 'booking_time', to_char(v_starts AT TIME ZONE v_tz, 'HH24:MI'),\n 'location_name', COALESCE(a.location_name, ''),\n 'customer_phone', COALESCE(a.client_phone, ''),\n 'source', 'channel_reply')\n INTO v_payload\n FROM public.v_appointments a\n WHERE a.id = v_row.id;\n\n v_event := CASE WHEN v_action = 'confirm'\n THEN 'agenda.booking_confirmed'\n ELSE 'agenda.booking_cancelled' END;\n\n PERFORM public.plg_emit_event(\n v_event,\n COALESCE(v_payload, '{}'::jsonb),\n 'booking',\n v_row.id::text,\n v_row.tenant_id,\n NULL);\n\n RETURN jsonb_build_object(\n 'result', v_target, 'changed', true, 'event_key', v_event,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id,\n 'status', v_target, 'previous_status', v_row.status);\nEND;\n$fn$;\n\n-- The webhook has the service-role key and no session; nothing else may move an\n-- appointment without one. Granting \\`authenticated\\` here would be a way to\n-- confirm any appointment in the pool by id, with no tenant check anywhere in\n-- the body — the check this function deliberately does not make, because its\n-- only caller cannot present a tenant to check against.\nREVOKE ALL ON FUNCTION public.plg_booking_apply_channel_reply(uuid, text, uuid) FROM public;\nREVOKE ALL ON FUNCTION public.plg_booking_apply_channel_reply(uuid, text, uuid) FROM anon;\nREVOKE ALL ON FUNCTION public.plg_booking_apply_channel_reply(uuid, text, uuid) FROM authenticated;\nGRANT EXECUTE ON FUNCTION public.plg_booking_apply_channel_reply(uuid, text, uuid) TO service_role;\n`\n\nexport const MIGRATION_018_THE_AGENDA_DECLARES_ITS_SPECIES = `-- ---------------------------------------------------------------------------\n-- 020_the_agenda_declares_its_species.sql — the agenda owns the species of the\n-- Compromisso and of the Agenda, and says so in a row (#274, ADR 0017).\n--\n-- The base owns the FORM: \\`public.appointments\\` and \\`public.schedules\\` are\n-- archetypes, with their columns, their RLS and their screens. What KIND of\n-- appointment exists is the plugin's, and since 147 that is a row in a registry\n-- with a real foreign key behind it — not a literal a plugin hopes nobody else\n-- also chose.\n--\n-- ── This closes a break, not a formality ────────────────────────────────────\n-- 147 created \\`appointment_kinds\\` and \\`schedule_kinds\\` empty, and adopted only\n-- what a live pool already held. Three of the four pools have appointments, so\n-- adoption covered them and nothing looked wrong. A FRESH cluster has neither —\n-- so the first booking on a brand-new pool would have been refused by the FK,\n-- with a message about a constraint rather than about a missing declaration.\n-- Found by the anchoring rule the same week it was written (#283), which is the\n-- argument for having it: the alternative was finding it in a customer's first\n-- five minutes.\n--\n-- ── Why the plugin and not the base ─────────────────────────────────────────\n-- Registering these in 147 would have been quicker and wrong. \\`working_hours\\`\n-- is not a fact about scheduling in general; it is how THIS plugin models a\n-- professional's week, and a vertical that models availability differently must\n-- be able to register its own without editing the base. The rule the registry\n-- exists to make enforceable is exactly this one, so the agenda goes first.\n-- ---------------------------------------------------------------------------\n\nDO $$\nBEGIN\n IF to_regprocedure('public.register_kind(text, text, text, text[], jsonb, text)') IS NULL THEN\n RAISE NOTICE 'plugin-agenda 020: register_kind missing (spine < 147) — skipped';\n RETURN;\n END IF;\n\n -- ── the Compromisso ────────────────────────────────────────────────────\n -- Statuses are the agenda's own lifecycle, the same vocabulary 090 gave the\n -- commercial document that accompanies an appointment. Transitions are left\n -- NULL: the plugin's RPCs own the machine, and a second one in the registry\n -- would be a second opinion about the same fact.\n PERFORM public.register_kind(\n 'appointment', 'appointment', 'agenda',\n ARRAY['scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show'],\n NULL,\n 'A booked appointment — the Compromisso the agenda schedules, confirms and closes.');\n\n PERFORM public.register_kind(\n 'appointment', 'block', 'agenda',\n ARRAY['scheduled', 'cancelled'],\n NULL,\n 'Time deliberately taken off the calendar: a break, a meeting, an absence. Occupies a slot and is never billed.');\n\n -- ── the Agenda itself ──────────────────────────────────────────────────\n PERFORM public.register_kind(\n 'schedule', 'working_hours', 'agenda', NULL, NULL,\n 'A professional''s recurring availability — the week that says when a slot can exist at all.');\n\n PERFORM public.register_kind(\n 'schedule', 'exception', 'agenda', NULL, NULL,\n 'A dated override of the working week: a holiday, a half-day, a one-off extension. Beats the recurring rule for its date (007).');\n\n PERFORM public.register_kind(\n 'schedule', 'block', 'agenda', NULL, NULL,\n 'A closed period on the calendar, independent of any one professional.');\nEND $$;\n`\n\nexport const MIGRATION_019_THE_DEFINER_FUNCTIONS_STOP_TRUSTING_THE_PATH = `-- ---------------------------------------------------------------------------\n-- 019_the_definer_functions_stop_trusting_the_path — every SECURITY DEFINER function this plugin\n-- owns stops resolving names the caller's way (#283).\n--\n-- The shape being closed: a definer function runs as its OWNER but resolves\n-- unqualified names using the CALLER's \\`search_path\\`. Anyone who can put an\n-- object earlier in that path gets it executed with the owner's rights. 157\n-- removed the ability to plant one in \\`public\\`; this removes the other half,\n-- which is the function trusting the path at all.\n--\n-- ── Why ALTER and not a re-emitted CREATE ───────────────────────────────────\n-- These functions are live in pools. Re-emitting each body to add one clause\n-- would copy hundreds of lines for a one-word change, and every copy is a\n-- chance to alter behaviour by accident. \\`ALTER FUNCTION … SET search_path\\`\n-- changes exactly the property in question and nothing else.\n--\n-- ── Why \\`public, pg_catalog\\` and not '' ─────────────────────────────────────\n-- The empty path is stricter and demands every name be schema-qualified — the\n-- right shape for something written today, and a rewrite of bodies written\n-- before the rule. What closes the hole is that the path is FIXED rather than\n-- inherited; these bodies already read \\`public\\` objects by bare name, so\n-- pinning to what they were written against keeps them correct and stops the\n-- caller having any say. The booking path is called by an anonymous shopper, which is exactly the caller whose path should count for nothing.\n-- ---------------------------------------------------------------------------\n\nDO $pin$\nDECLARE\n v_fn record;\n v_pinned integer := 0;\nBEGIN\n FOR v_fn IN\n SELECT p.oid, p.proname, pg_get_function_identity_arguments(p.oid) AS args\n FROM pg_proc p\n JOIN pg_namespace n ON n.oid = p.pronamespace\n WHERE n.nspname = 'public'\n AND p.prosecdef\n AND p.proname = ANY (ARRAY['create_public_booking', 'fn_gcal_push_booking'])\n AND NOT EXISTS (\n SELECT 1 FROM unnest(coalesce(p.proconfig, ARRAY[]::text[])) AS cfg\n WHERE cfg LIKE 'search\\\\_path=%'\n )\n LOOP\n EXECUTE format('ALTER FUNCTION public.%I(%s) SET search_path = public, pg_catalog',\n v_fn.proname, v_fn.args);\n v_pinned := v_pinned + 1;\n END LOOP;\n IF v_pinned > 0 THEN\n RAISE NOTICE 'plugin-agenda: pinned search_path on % definer function(s)', v_pinned;\n END IF;\nEND $pin$;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000b_v_bookings_rename\", sql: MIGRATION_000B_V_BOOKINGS_RENAME },\n { id: \"000c_dedupe_customer_phones\", sql: MIGRATION_000C_DEDUPE_CUSTOMER_PHONES },\n { id: \"001_public_booking\", sql: MIGRATION_001_PUBLIC_BOOKING },\n { id: \"002_v_bookings_compat\", sql: MIGRATION_002_V_BOOKINGS_COMPAT },\n { id: \"003_public_client_kind\", sql: MIGRATION_003_PUBLIC_CLIENT_KIND },\n { id: \"004_public_booking_assignee\", sql: MIGRATION_004_PUBLIC_BOOKING_ASSIGNEE },\n { id: \"005_agent_rpcs\", sql: MIGRATION_005_AGENT_RPCS },\n { id: \"006_agent_rpc_localtime\", sql: MIGRATION_006_AGENT_RPC_LOCALTIME },\n { id: \"007_schedule_exception_precedence\", sql: MIGRATION_007_SCHEDULE_EXCEPTION_PRECEDENCE },\n { id: \"008_agent_rpc_exception_precedence\", sql: MIGRATION_008_AGENT_RPC_EXCEPTION_PRECEDENCE },\n { id: \"009_public_booking_location\", sql: MIGRATION_009_PUBLIC_BOOKING_LOCATION },\n { id: \"010_public_service_curation\", sql: MIGRATION_010_PUBLIC_SERVICE_CURATION },\n { id: \"011_default_assignee\", sql: MIGRATION_011_DEFAULT_ASSIGNEE },\n { id: \"012_drop_legacy_booking_overload\", sql: MIGRATION_012_DROP_LEGACY_BOOKING_OVERLOAD },\n { id: \"013_normalize_v_appointments\", sql: MIGRATION_013_NORMALIZE_V_APPOINTMENTS },\n { id: \"014_agent_rpc_update_appointment\", sql: MIGRATION_014_AGENT_RPC_UPDATE_APPOINTMENT },\n { id: \"015_analytics_read_models\", sql: MIGRATION_015_ANALYTICS_READ_MODELS },\n { id: \"016_public_services_release\", sql: MIGRATION_016_PUBLIC_SERVICES_RELEASE },\n { id: \"017_booking_channel_reply\", sql: MIGRATION_017_BOOKING_CHANNEL_REPLY },\n { id: \"018_the_agenda_declares_its_species\", sql: MIGRATION_018_THE_AGENDA_DECLARES_ITS_SPECIES },\n { id: \"019_the_definer_functions_stop_trusting_the_path\", sql: MIGRATION_019_THE_DEFINER_FUNCTIONS_STOP_TRUSTING_THE_PATH },\n]\n","// ---------------------------------------------------------------------------\n// Bridge factory: adapts FinancialDataProvider → AgendaFinancialBridge\n// Consumer apps call this at plugin wiring time.\n// ---------------------------------------------------------------------------\n\nimport type { FinancialDataProvider } from '@fayz-ai/plugin-financial'\nimport type { AgendaFinancialBridge, BookingPaymentSummary, BookingPaymentDetail, BookingPaymentStatus } from './financial-bridge'\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\n\n/**\n * Pure commission math: percentage of a realized order total, rounded to cents.\n * Exported for unit-testing and reuse; the bridge method below wraps the I/O.\n * Returns 0 for a non-positive base or rate so callers can skip empty accruals.\n */\nexport function computeCommissionAmount(total: number, ratePercent: number): number {\n const base = Number(total) || 0\n const rate = Number(ratePercent) || 0\n if (base <= 0 || rate <= 0) return 0\n return Math.round(base * (rate / 100) * 100) / 100\n}\n\nfunction computeStatus(movements: Array<{ status: string }>): BookingPaymentStatus {\n if (movements.length === 0) return 'none'\n const allPaid = movements.every((m) => m.status === 'paid')\n if (allPaid) return 'paid'\n const allCancelled = movements.every((m) => m.status === 'cancelled')\n if (allCancelled) return 'cancelled'\n const anyOverdue = movements.some((m) => m.status === 'overdue')\n if (anyOverdue) return 'overdue'\n const anyPaid = movements.some((m) => m.status === 'paid' || m.status === 'partial')\n if (anyPaid) return 'partial'\n return 'pending'\n}\n\n/**\n * Create an AgendaFinancialBridge backed by the financial plugin's data provider.\n *\n * @example\n * const financialProvider = createSupabaseFinancialProvider()\n * const agenda = createAgendaPlugin({\n * financialBridge: createFinancialBridge(financialProvider),\n * })\n */\nexport function createFinancialBridge(provider: FinancialDataProvider): AgendaFinancialBridge {\n return {\n async resolvePaymentStatuses(orderIds: string[]): Promise<Map<string, BookingPaymentSummary>> {\n const result = new Map<string, BookingPaymentSummary>()\n if (orderIds.length === 0) return result\n\n // Single batch query instead of N individual getInvoiceById calls\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return result\n\n try {\n const [{ data: orders }, { data: movements }] = await Promise.all([\n supabase\n .from('orders')\n .select('id, kind, status, total, reference_number, metadata')\n .in('id', orderIds),\n supabase\n .from('plg_financial_movements')\n .select('invoice_id, status, paid_amount')\n .in('invoice_id', orderIds),\n ])\n\n const movementsByOrderId = new Map<string, Array<{ status: string; paid_amount: number }>>()\n for (const movement of movements ?? []) {\n const invoiceId = movement.invoice_id as string | undefined\n if (!invoiceId) continue\n movementsByOrderId.set(invoiceId, [...(movementsByOrderId.get(invoiceId) ?? []), movement])\n }\n\n for (const order of orders ?? []) {\n const orderMovements = movementsByOrderId.get(order.id) ?? []\n const meta = (order.metadata ?? {}) as Record<string, unknown>\n const paidAmount = orderMovements.length > 0\n ? orderMovements.reduce((sum, movement) => sum + (Number(movement.paid_amount) || 0), 0)\n : Number(meta.paidAmount) || 0\n\n result.set(order.id, {\n invoiceId: order.id,\n referenceNumber: order.reference_number as string | undefined,\n status: orderMovements.length > 0 ? computeStatus(orderMovements) : mapInvoiceStatus(order.status as string),\n totalAmount: Number(order.total) || 0,\n paidAmount,\n })\n }\n } catch { /* non-blocking */ }\n\n return result\n },\n\n async getPaymentDetail(orderId: string): Promise<BookingPaymentDetail | null> {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return null\n\n // Single query: get order + movements in parallel\n const [orderRes, movRes] = await Promise.all([\n supabase.from('orders').select('id, status, total, reference_number, metadata').eq('id', orderId).single(),\n supabase.from('plg_financial_movements').select('*').eq('invoice_id', orderId).order('due_date'),\n ])\n\n const order = orderRes.data\n if (!order) return null\n const meta = (order.metadata ?? {}) as Record<string, unknown>\n\n // Collect unique payment_method_type_ids to resolve names in one query\n const typeIds = [...new Set((movRes.data ?? []).map((m: any) => m.payment_method_type_id).filter(Boolean))]\n let typeNames: Record<string, string> = {}\n if (typeIds.length > 0) {\n const { data: types } = await supabase.from('plg_financial_payment_method_types').select('id, name').in('id', typeIds)\n typeNames = Object.fromEntries((types ?? []).map((t: any) => [t.id, t.name]))\n }\n\n const movements = (movRes.data ?? []).map((m: Record<string, unknown>) => ({\n id: String(m.id),\n amount: Number(m.amount) || 0,\n paidAmount: Number(m.paid_amount) || 0,\n status: String(m.status ?? 'pending'),\n dueDate: String(m.due_date ?? ''),\n installmentNumber: m.installment_number != null ? Number(m.installment_number) : undefined,\n paymentDate: m.payment_date ? String(m.payment_date) : undefined,\n paymentMethodTypeName: m.payment_method_type_id ? typeNames[String(m.payment_method_type_id)] : undefined,\n cardBrand: m.card_brand ? String(m.card_brand) : undefined,\n cardInstallments: m.card_installments ? Number(m.card_installments) : undefined,\n }))\n\n return {\n invoiceId: order.id,\n referenceNumber: order.reference_number as string | undefined,\n status: movements.length > 0 ? computeStatus(movements) : mapInvoiceStatus(order.status as string),\n totalAmount: Number(order.total) || 0,\n paidAmount: Number(meta.paidAmount) || 0,\n movements,\n }\n },\n\n async createInvoiceFromOrder(orderId: string, options?: {\n installments?: number\n dueDate?: string\n paymentMethodTypeId?: string\n }): Promise<string> {\n // Promote the existing order to an invoice_receivable atomically via the\n // shared DB function (ref + stage/direction + N installments, idempotent).\n // status='invoiced' is valid for appointment/service_order (CHECK).\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not available')\n const { error } = await supabase.rpc('fn_invoice_from_order', {\n p_order_id: orderId,\n p_due_date: options?.dueDate ?? null,\n p_status: 'invoiced',\n p_installments: options?.installments ?? 1,\n p_direction: 'credit',\n })\n if (error) throw new Error(error.message)\n return orderId\n },\n\n async payMovement(input) {\n await provider.payMovement({\n movementId: input.movementId,\n amount: input.amount,\n paymentDate: input.paymentDate,\n paymentMethodTypeId: input.paymentMethodTypeId,\n paymentMethodId: input.paymentMethodId,\n bankAccountId: input.bankAccountId,\n cardBrand: input.cardBrand,\n cardInstallments: input.cardInstallments,\n })\n },\n\n async createCommissionMovement(orderId, options) {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return null\n\n // Order carries the assigned professional (assignee_id) and realized total.\n const { data: order } = await supabase\n .from('orders')\n .select('id, tenant_id, assignee_id, total')\n .eq('id', orderId)\n .single()\n if (!order || !order.assignee_id) return null // no professional → no commission\n\n // The rate belongs to the professional's ROLE, not to the person: same\n // human, different unit, different rate (143). v_staff, which this used to\n // ask, is declared by no migration and has no such column anywhere.\n const { data: staff } = await supabase\n .from('v_professional_rates')\n .select('commission_rate')\n .eq('id', order.assignee_id)\n .single()\n\n const rate = Number(staff?.commission_rate) || 0\n const base = Number(order.total) || 0\n const amount = computeCommissionAmount(base, rate)\n if (amount <= 0) return null // nothing configured/realized to accrue\n\n // Idempotent: one commission accrual per order. Reuse if already present.\n const { data: existing } = await supabase\n .from('plg_financial_movements')\n .select('id')\n .eq('invoice_id', orderId)\n .eq('movement_kind', 'commission')\n .limit(1)\n if (existing && existing.length > 0) return existing[0].id as string\n\n const dueDate = options?.dueDate ?? new Date().toISOString().slice(0, 10)\n\n const { data: inserted } = await supabase\n .from('plg_financial_movements')\n .insert({\n tenant_id: order.tenant_id,\n invoice_id: orderId,\n direction: 'debit', // payable to the professional\n movement_kind: 'commission',\n amount,\n paid_amount: 0,\n status: 'pending',\n due_date: dueDate,\n metadata: {\n source: 'agenda',\n kind: 'commission',\n professionalId: order.assignee_id,\n commissionRate: rate,\n baseAmount: base,\n },\n })\n .select('id')\n .single()\n\n return (inserted?.id as string | undefined) ?? null\n },\n\n async checkout(orderId, input) {\n // 1. Create invoice (single installment, due today)\n const today = new Date().toISOString().slice(0, 10)\n const invoiceId = await this.createInvoiceFromOrder(orderId, { installments: 1, dueDate: today })\n\n // 2. Get the created movement\n const detail = await this.getPaymentDetail(invoiceId)\n if (!detail || detail.movements.length === 0) throw new Error('No movement created')\n\n const movement = detail.movements[0]\n\n // 3. Pay it in full\n await this.payMovement({\n movementId: movement.id,\n amount: movement.amount,\n paymentDate: today,\n paymentMethodTypeId: input.paymentMethodTypeId,\n paymentMethodId: input.paymentMethodId,\n bankAccountId: input.bankAccountId,\n cardBrand: input.cardBrand,\n cardInstallments: input.cardInstallments,\n })\n\n // 4. Return updated detail\n return (await this.getPaymentDetail(invoiceId))!\n },\n\n async getPaymentMethodTypes() {\n const types = await provider.getPaymentMethodTypes()\n return types.map((t: any) => ({ id: t.id, name: t.name, transactionType: t.transactionType }))\n },\n\n async getBankAccounts() {\n const accounts = await provider.getBankAccounts()\n return accounts\n .filter((a: any) => a.isActive)\n .map((a: any) => ({ id: a.id, name: a.name, accountType: a.accountType }))\n },\n\n async getPaymentMethods(paymentMethodTypeId: string) {\n const methods = await provider.getPaymentMethods()\n return methods\n .filter((m: any) => m.paymentMethodTypeId === paymentMethodTypeId && m.isActive)\n .map((m: any) => ({ id: m.id, name: m.name }))\n },\n }\n}\n\nfunction mapInvoiceStatus(status: string): BookingPaymentStatus {\n switch (status) {\n case 'paid': return 'paid'\n case 'partial': return 'partial'\n case 'overdue': return 'overdue'\n case 'cancelled': return 'cancelled'\n case 'invoiced': return 'pending'\n case 'pending': return 'pending'\n case 'scheduled': return 'none'\n case 'confirmed': return 'none'\n case 'in_progress': return 'none'\n case 'completed': return 'none'\n case 'no_show': return 'none'\n case 'booked': return 'none'\n default: return 'pending'\n }\n}\n","// Booking ↔ Google Calendar event mapping — the SINGLE SOURCE OF TRUTH.\n//\n// These helpers are pure and Deno-friendly (only `import type`, no runtime\n// node/react/https imports), so the Supabase edge function imports this exact\n// file via a relative path (`../../src/integrations/google-calendar/mapping.ts`)\n// instead of keeping a divergent mirror. `import type` is elided by the Deno /\n// esbuild bundler, so the plugin `types.ts`/`CalendarBooking` type imports never\n// become runtime dependencies of the function bundle.\n//\n// Two callers, two input shapes:\n// • the SDK/UI works with the rich `CalendarBooking` (camelCase, joined) — see\n// bookingToEvent / eventToBookingPatch;\n// • the edge function + RPCs work with the raw `AppointmentRow` (snake_case DB\n// columns) — see appointmentRowToEvent / eventToAppointmentPatch.\n// Field decisions (title, all-day, cancel) are made once, here.\nimport type { CalendarBooking } from '../../types'\nimport type { GCalEvent, AppointmentRow, CalendarChannel, CalendarChannelRow } from './types'\n\nexport interface GCalEventInput {\n summary: string\n description?: string\n // Timed events use dateTime; all-day events use date (YYYY-MM-DD).\n start: { dateTime?: string; date?: string; timeZone?: string }\n end: { dateTime?: string; date?: string; timeZone?: string }\n}\n\n/** Normalized time window read off a Google event, all-day aware. */\nexport interface EventTimes {\n startsAt: string\n endsAt: string\n allDay: boolean\n}\n\n// --- Booking (rich SDK shape) → event -------------------------------------\n\n/** Build the event title from the booking's services + client. */\nexport function bookingSummary(b: Pick<CalendarBooking, 'services' | 'clientName'>): string {\n const services = (b.services ?? []).map((s) => s.name).filter(Boolean).join(', ')\n const who = b.clientName ?? ''\n if (services && who) return `${services} — ${who}`\n return services || who || 'Appointment'\n}\n\n/** Map a Fayz booking to a Google Calendar event input. Returns null when the booking has no end. */\nexport function bookingToEvent(b: CalendarBooking, timeZone?: string): GCalEventInput | null {\n if (!b.startsAt || !b.endsAt) return null\n const notes = [b.notes, b.professionalName ? `Pro: ${b.professionalName}` : '', b.locationName ?? '']\n .filter(Boolean).join('\\n')\n return {\n summary: bookingSummary(b),\n description: notes || undefined,\n start: { dateTime: b.startsAt, timeZone },\n end: { dateTime: b.endsAt, timeZone },\n }\n}\n\n/** Map an inbound Google event change to a partial booking update (reschedule/cancel), all-day aware. */\nexport function eventToBookingPatch(ev: GCalEvent): { startsAt?: string; endsAt?: string; status?: 'cancelled' } {\n if (ev.status === 'cancelled') return { status: 'cancelled' }\n const t = eventTimes(ev)\n return { startsAt: t.startsAt, endsAt: t.endsAt }\n}\n\n// --- Appointment row (raw DB shape) → event -------------------------------\n\n/**\n * Build the event title from an appointments row's denormalized metadata.\n * The raw row has no joined services/client, so we read the names the app\n * stamps onto metadata (serviceNames, contactName/clientName).\n */\nexport function appointmentRowSummary(row: AppointmentRow): string {\n const m = row.metadata ?? {}\n const services = (m.serviceNames as string) ?? ''\n const who = (m.contactName as string) ?? (m.clientName as string) ?? ''\n if (services && who) return `${services} — ${who}`\n return services || who || 'Appointment'\n}\n\n/** Map a raw appointments row to a Google event input (outbound push from the edge function). */\nexport function appointmentRowToEvent(row: AppointmentRow): GCalEventInput {\n return {\n summary: appointmentRowSummary(row),\n description: row.notes ?? undefined,\n start: { dateTime: row.starts_at },\n end: { dateTime: row.ends_at ?? row.starts_at },\n }\n}\n\n/**\n * Map an inbound Google event to a DB-friendly appointment patch (snake_case\n * times), all-day aware, cancellation included. Consumed by the edge function\n * when calling gcal_apply_event_patch.\n */\nexport function eventToAppointmentPatch(ev: GCalEvent): {\n starts_at?: string\n ends_at?: string\n summary?: string\n allDay?: boolean\n cancelled: boolean\n} {\n if (ev.status === 'cancelled') return { cancelled: true }\n const t = eventTimes(ev)\n return { starts_at: t.startsAt, ends_at: t.endsAt, summary: ev.summary, allDay: t.allDay, cancelled: false }\n}\n\n// --- Shared time normalization (all-day aware) ----------------------------\n\n/**\n * Read a normalized {startsAt, endsAt, allDay} window off a Google event.\n * All-day events carry `start.date`/`end.date` (YYYY-MM-DD, end exclusive) and\n * no dateTime; timed events carry dateTime. Falls back start→end when one side\n * is missing so callers always get a usable pair.\n */\nexport function eventTimes(ev: GCalEvent): EventTimes {\n const allDay = !ev.start?.dateTime && !!ev.start?.date\n const startsAt = ev.start?.dateTime ?? ev.start?.date ?? ''\n const endsAt = ev.end?.dateTime ?? ev.end?.date ?? startsAt\n return { startsAt, endsAt, allDay }\n}\n\n// --- Channel resolution (outbound destination priority) -------------------\n\n/** Convert a raw plg_calendar_channels row (snake_case) to the camelCase CalendarChannel. */\nexport function channelRowToChannel(r: CalendarChannelRow): CalendarChannel {\n return {\n id: r.id,\n integrationId: r.integration_id,\n tenantId: r.tenant_id,\n googleCalendarId: r.google_calendar_id,\n summary: r.summary ?? null,\n color: r.color ?? null,\n direction: r.direction,\n targetKind: r.target_kind ?? null,\n targetId: r.target_id ?? null,\n importMode: r.import_mode ?? 'appointment',\n syncToken: r.sync_token ?? null,\n channelId: r.channel_id ?? null,\n resourceId: r.resource_id ?? null,\n channelExpiresAt: r.channel_expires_at ?? null,\n isActive: r.is_active ?? true,\n createdAt: r.created_at ?? '',\n updatedAt: r.updated_at ?? '',\n }\n}\n\nexport interface ChannelMatchInput {\n assigneeId?: string | null\n serviceIds?: string[]\n locationId?: string | null\n}\n\n/**\n * Pick the outbound destination channel for a booking, by priority:\n * 1. a channel targeting the booking's assignee,\n * 2. else a channel targeting one of the booking's services,\n * 3. else a channel targeting the booking's location,\n * 4. else the whole-agenda channel (targetKind === null).\n * Only active outbound/bidirectional channels are eligible. Returns null when\n * nothing matches (caller falls back to the integration's default calendar).\n */\nexport function resolveTargetChannel(\n channels: CalendarChannel[],\n booking: ChannelMatchInput,\n): CalendarChannel | null {\n const eligible = channels.filter(\n (c) => c.isActive && (c.direction === 'outbound' || c.direction === 'bidirectional'),\n )\n const serviceIds = booking.serviceIds ?? []\n\n if (booking.assigneeId) {\n const byAssignee = eligible.find((c) => c.targetKind === 'assignee' && c.targetId === booking.assigneeId)\n if (byAssignee) return byAssignee\n }\n if (serviceIds.length) {\n const byService = eligible.find((c) => c.targetKind === 'service' && !!c.targetId && serviceIds.includes(c.targetId))\n if (byService) return byService\n }\n if (booking.locationId) {\n const byLocation = eligible.find((c) => c.targetKind === 'location' && c.targetId === booking.locationId)\n if (byLocation) return byLocation\n }\n return eligible.find((c) => c.targetKind === null) ?? null\n}\n","// Where the Google grant lives — and the one place that changes when it moves.\n//\n// It moved (FAY-1359/1360, 2026-08-12). It used to live on\n// plg_calendar_integrations as `oauth_refresh_token` / `oauth_access_token`: a\n// tenant-RLS table the browser reads, so every authenticated member of the\n// tenant — reception included — could pull a refresh token down the wire, which\n// is durable access to someone's whole calendar. It now lives in the platform\n// vault, and the edge function redeems a short-lived access token per call.\n//\n// So this file no longer answers \"is there a grant?\" at all: `plg_connections`\n// does, through the shared connection store, the same as every other connector.\n// What is left here is the ONE rule that outlived the credential — the browser\n// reads named columns off the integration row and never `*`.\nimport type { CalendarIntegrationRow } from './types'\n\n/**\n * The columns the browser may read off the integration row. An explicit list,\n * not `*` — `select('*')` is how the refresh token reached the browser in the\n * first place, and a column added later should have to be let in on purpose.\n *\n * There is no credential column left to exclude. The list stays anyway: it is\n * cheap, and the day someone adds one, this is what makes them notice.\n */\nexport const CONNECTION_COLUMNS = 'id, provider, calendar_id, active, last_sync_at'\n\n/**\n * Whether the calendar side of the integration is switched on.\n *\n * NOT \"is the connector connected\" — that question belongs to\n * `plg_connections` and is asked through the connection store. This one only\n * says whether the tenant's own sync state row is live, which is what the\n * health rule needs before it complains about a stale cursor.\n */\nexport function isIntegrationActive(\n row: Pick<CalendarIntegrationRow, 'active'> | null | undefined,\n): boolean {\n return !!row && row.active !== false\n}\n\n/**\n * The patch that stops the calendar side.\n *\n * It does not revoke anything: the grant is the platform's, and revoking it at\n * Google is the platform's disconnect. This turns off the sync state row.\n */\nexport function disconnectPatch(): Record<string, unknown> {\n return { active: false, updated_at: new Date().toISOString() }\n}\n","// Canonical DB object names for the Google Calendar connector.\n//\n// Plugin-owned tables carry the platform `plg_<plugin>_` prefix (DATA-MODEL.md\n// Ring 1). Single source of truth so the connector data layer (supabase.ts) and\n// the google-calendar-sync edge function never drift on a table name. The SQL\n// side is owned by ./migrations/001_google_calendar.sql + 002_smart_sync.sql\n// (fresh installs) and 003_plg_rename.sql (legacy-pool rename).\n// webhookDeliveries/automationOutbox were recovered from the deployed bundles on\n// 2026-08-12 (FAY-1379): both live functions read them off this map, but the two\n// tables existed only in the pool — 006 is the migration that creates them.\nexport const GCAL_TABLES = {\n integrations: 'plg_calendar_integrations',\n channels: 'plg_calendar_channels',\n syncLog: 'plg_calendar_sync_log',\n webhookDeliveries: 'plg_calendar_webhook_deliveries',\n automationOutbox: 'plg_calendar_automation_outbox',\n} as const\n","// Google Calendar integration (control plane) — Supabase client.\n//\n// Thin client. Split of responsibilities:\n// • anything that touches Google goes through the google-calendar-sync edge\n// function, which redeems the tenant's grant from the platform vault;\n// • plain tenant-scoped reads/writes (integration row, channels, log) hit the\n// tables directly under RLS.\n//\n// No call from here carries a credential, and none can: the browser has never\n// been able to see the grant since FAY-1359, and what it sends instead is a\n// runtime token that only says WHICH TENANT is asking.\nimport {\n CONNECTOR_RUNTIME_TOKEN_HEADER,\n connectorRuntimeToken,\n getSupabaseClientOptional,\n getActiveTenantId,\n} from '@fayz-ai/core'\nimport { channelRowToChannel } from '../mapping'\nimport { CONNECTION_COLUMNS, disconnectPatch, isIntegrationActive } from '../credentials'\nimport { GCAL_TABLES } from './tables'\nimport type {\n CalendarIntegration,\n CalendarSyncLogEntry,\n CalendarChannel,\n ExternalEventPreview,\n GoogleCalendarListEntry,\n ImportEventsResult,\n} from '../types'\n\nconst FUNCTION = 'google-calendar-sync'\n\nfunction sb() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\n/**\n * One call to the data plane, carrying the two things it cannot derive.\n *\n * The Supabase session goes in `Authorization`, and the Fayz runtime token in\n * its own header — that is the one the function forwards to redeem this\n * tenant's Google grant. An edge function cannot mint one, so a call without it\n * is a call the function must refuse; asking for it here means the refusal\n * happens before the round trip instead of as a 401 the clinic sees.\n */\nasync function invoke<T>(body: Record<string, unknown>): Promise<T> {\n const tenantId = getActiveTenantId()\n const runtimeToken = await connectorRuntimeToken({ tenantId })\n\n const { data, error } = await sb().functions.invoke(FUNCTION, {\n body: { ...body, tenantId },\n headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken },\n })\n if (error) throw new Error(error.message)\n return data as T\n}\n\n/** Snake_case patch for plg_calendar_channels writes (RLS-scoped). */\nexport interface CalendarChannelInput {\n id?: string\n integrationId?: string\n googleCalendarId: string\n summary?: string | null\n color?: string | null\n direction?: CalendarChannel['direction']\n targetKind?: CalendarChannel['targetKind']\n targetId?: string | null\n importMode?: CalendarChannel['importMode']\n isActive?: boolean\n}\n\nexport interface GoogleCalendarProvider {\n getIntegration(): Promise<CalendarIntegration | null>\n /**\n * Make sure this tenant HAS a sync state row, and switch it on.\n *\n * The OAuth callback used to create it, as a side effect of writing the\n * refresh token into it. That callback is the platform's now and knows\n * nothing about this pool's tables, so the row has to be created on the way\n * back from consent — a channel FKs to it, and a de-para with no integration\n * to hang from is the shape of \"conectei e não dá para escolher a agenda\".\n */\n ensureIntegration(): Promise<void>\n setCalendar(calendarId: string): Promise<void>\n disconnect(): Promise<void>\n /** Manually pull external changes now (inbound). */\n syncNow(): Promise<{ fetched: number; written: number; discovered?: number }>\n getSyncLog(): Promise<CalendarSyncLogEntry[]>\n // --- smart sync: multi-calendar channels + import wizard ---\n /** List the user's Google calendars for the de-para picker (needs the API → function). */\n listGoogleCalendars(): Promise<GoogleCalendarListEntry[]>\n /** Read this tenant's channels (RLS). */\n listChannels(): Promise<CalendarChannel[]>\n /** Create/update a channel (RLS upsert on integration_id + google_calendar_id). */\n saveChannel(input: CalendarChannelInput): Promise<void>\n /** Delete a channel by id (RLS). */\n deleteChannel(id: string): Promise<void>\n /** Preview future events not yet linked to an appointment (import wizard). */\n listExternalEvents(params?: { channelId?: string; timeMin?: string }): Promise<ExternalEventPreview[]>\n /** Import selected external events as appointments. */\n importEvents(items: { channelId: string; eventId: string }[]): Promise<ImportEventsResult>\n}\n\nexport function createGoogleCalendarProvider(): GoogleCalendarProvider {\n return {\n async getIntegration() {\n // Named columns, never `*`: the credential must not be able to ride along.\n const { data } = await sb().from(GCAL_TABLES.integrations).select(CONNECTION_COLUMNS).eq('provider', 'google').limit(1).maybeSingle()\n if (!data) return null\n return {\n id: data.id,\n provider: data.provider,\n calendarId: data.calendar_id ?? 'primary',\n active: isIntegrationActive(data),\n // The sync state row existing is not the same as the clinic having\n // authorized Google — `plg_connections` owns that answer now, and the\n // connector asks it through the connection store.\n connected: isIntegrationActive(data),\n lastSyncAt: data.last_sync_at ?? undefined,\n }\n },\n\n async ensureIntegration() {\n const { error } = await sb()\n .from(GCAL_TABLES.integrations)\n .upsert(\n {\n tenant_id: getActiveTenantId(),\n provider: 'google',\n active: true,\n updated_at: new Date().toISOString(),\n },\n { onConflict: 'tenant_id,provider' },\n )\n if (error) throw new Error(error.message)\n },\n\n async setCalendar(calendarId) {\n await sb().from(GCAL_TABLES.integrations).update({ calendar_id: calendarId, updated_at: new Date().toISOString() }).eq('provider', 'google')\n },\n\n async disconnect() {\n // Two writes, and the order matters: the function stops the watches at\n // Google while the grant still works, then the row goes inactive. No\n // token is cleared here because none is stored here — revoking the grant\n // is the platform's call, since it is the platform that holds it.\n await invoke({ action: 'disconnect' })\n await sb().from(GCAL_TABLES.integrations).update(disconnectPatch()).eq('provider', 'google')\n },\n\n async syncNow() {\n return invoke<{ fetched: number; written: number; discovered?: number }>({\n action: 'pull_events',\n trigger: 'manual',\n })\n },\n\n async getSyncLog() {\n const { data } = await sb().from(GCAL_TABLES.syncLog).select('*').order('created_at', { ascending: false }).limit(20)\n return (data ?? []).map((r: any) => ({\n id: r.id, direction: r.direction, trigger: r.trigger ?? undefined,\n status: r.status, fetched: r.fetched ?? 0, written: r.written ?? 0,\n error: r.error ?? undefined, createdAt: r.created_at,\n }))\n },\n\n async listGoogleCalendars() {\n const result = await invoke<{ calendars: GoogleCalendarListEntry[] }>({ action: 'list_calendars' })\n return result.calendars ?? []\n },\n\n async listChannels() {\n const { data } = await sb().from(GCAL_TABLES.channels).select('*').order('created_at', { ascending: true })\n return (data ?? []).map(channelRowToChannel)\n },\n\n async saveChannel(input) {\n const tenantId = getActiveTenantId()\n // Resolve the integration id when the caller didn't pass one.\n let integrationId = input.integrationId\n if (!integrationId) {\n const { data } = await sb().from(GCAL_TABLES.integrations).select('id').eq('provider', 'google').limit(1).maybeSingle()\n integrationId = data?.id\n }\n const row: Record<string, unknown> = {\n integration_id: integrationId,\n tenant_id: tenantId,\n google_calendar_id: input.googleCalendarId,\n updated_at: new Date().toISOString(),\n }\n if (input.id !== undefined) row.id = input.id\n if (input.summary !== undefined) row.summary = input.summary\n if (input.color !== undefined) row.color = input.color\n if (input.direction !== undefined) row.direction = input.direction\n if (input.targetKind !== undefined) row.target_kind = input.targetKind\n if (input.targetId !== undefined) row.target_id = input.targetId\n if (input.importMode !== undefined) row.import_mode = input.importMode\n if (input.isActive !== undefined) row.is_active = input.isActive\n const { error } = await sb().from(GCAL_TABLES.channels).upsert(row, { onConflict: 'integration_id,google_calendar_id' })\n if (error) throw new Error(error.message)\n },\n\n async deleteChannel(id) {\n const { error } = await sb().from(GCAL_TABLES.channels).delete().eq('id', id)\n if (error) throw new Error(error.message)\n },\n\n async listExternalEvents(params) {\n const result = await invoke<{ events: ExternalEventPreview[] }>({\n action: 'list_external_events',\n channelId: params?.channelId,\n timeMin: params?.timeMin,\n })\n return result.events ?? []\n },\n\n async importEvents(items) {\n return invoke<ImportEventsResult>({ action: 'import_events', items })\n },\n }\n}\n","// What \"connected\" is not enough to tell you.\n//\n// A green badge only says a grant exists. The ways this connector actually\n// stops working are quieter: the last run errored, nothing has run in an hour,\n// no calendar is mapped to import from, or the Google watch that delivers\n// inbound changes has lapsed. Deriving them in one pure function means the\n// status badge (getStatus) and the panel say the same thing, and means the rule\n// is testable without a Google account.\nimport type { CalendarChannel, CalendarSyncLogEntry } from './types'\n\nexport type GoogleCalendarHealthStatus = 'disconnected' | 'healthy' | 'attention' | 'error'\n\nexport type GoogleCalendarHealthIssueCode =\n | 'sync_error'\n | 'sync_missing'\n | 'sync_stale'\n | 'inbound_channel_missing'\n | 'watch_missing'\n | 'watch_expiring'\n | 'timezone_mismatch'\n\nexport interface GoogleCalendarHealthIssue {\n code: GoogleCalendarHealthIssueCode\n detail?: string\n}\n\nexport interface GoogleCalendarHealth {\n status: GoogleCalendarHealthStatus\n issues: GoogleCalendarHealthIssue[]\n}\n\nexport function deriveGoogleCalendarHealth(input: {\n connected: boolean\n lastSyncAt?: string\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n calendarTimeZones?: string[]\n localTimeZone?: string\n now?: number\n staleAfterMs?: number\n renewBeforeMs?: number\n}): GoogleCalendarHealth {\n if (!input.connected) return { status: 'disconnected', issues: [] }\n\n const now = input.now ?? Date.now()\n const staleAfterMs = input.staleAfterMs ?? 45 * 60_000\n // Google watches expire in ~7 days; the platform's renewal clock is expected\n // to act a day out, so a shorter window than that is already a warning.\n const renewBeforeMs = input.renewBeforeMs ?? 24 * 60 * 60_000\n const issues: GoogleCalendarHealthIssue[] = []\n const latest = input.logs[0]\n\n if (latest && latest.status !== 'success' && latest.status !== 'skipped') {\n issues.push({ code: 'sync_error', detail: latest.error })\n }\n if (!input.lastSyncAt) {\n issues.push({ code: 'sync_missing' })\n } else {\n const lastSyncMs = new Date(input.lastSyncAt).getTime()\n if (!Number.isFinite(lastSyncMs) || lastSyncMs < now - staleAfterMs) {\n issues.push({ code: 'sync_stale', detail: input.lastSyncAt })\n }\n }\n\n const inbound = input.channels.filter(\n (channel) => channel.isActive && (channel.direction === 'inbound' || channel.direction === 'bidirectional'),\n )\n if (inbound.length === 0) issues.push({ code: 'inbound_channel_missing' })\n for (const channel of inbound) {\n if (!channel.channelId || !channel.resourceId || !channel.channelExpiresAt) {\n issues.push({ code: 'watch_missing', detail: channel.summary ?? channel.googleCalendarId })\n continue\n }\n const expiresAt = new Date(channel.channelExpiresAt).getTime()\n if (!Number.isFinite(expiresAt) || expiresAt <= now + renewBeforeMs) {\n issues.push({ code: 'watch_expiring', detail: channel.summary ?? channel.googleCalendarId })\n }\n }\n\n // A calendar in another timezone is not an error, but it is the single most\n // common reason an imported event lands \"three hours off\".\n const localTimeZone = input.localTimeZone\n const mismatchedTimeZones = [...new Set(input.calendarTimeZones ?? [])]\n .filter(Boolean)\n .filter((timeZone) => localTimeZone && timeZone !== localTimeZone)\n if (mismatchedTimeZones.length > 0) {\n issues.push({ code: 'timezone_mismatch', detail: mismatchedTimeZones.join(', ') })\n }\n\n return {\n status: issues.some((issue) => issue.code === 'sync_error')\n ? 'error'\n : issues.length > 0\n ? 'attention'\n : 'healthy',\n issues,\n }\n}\n","// What the connector's panel and its status badge both need, read once.\n//\n// It used to be read twice. The panel awaited `getIntegration()`, and then —\n// with that answer already in hand — called `readHealth()`, which awaited\n// `getIntegration()` again, plus a second `getSyncLog()` and a second\n// `listChannels()`. Sequential, so the transport's in-flight de-duplication\n// could not collapse them: the first request had already settled when the\n// second was issued. Three tables, six requests, for one screen.\n//\n// Extracted out of the component so the count is assertable without a DOM.\nimport { deriveGoogleCalendarHealth } from './health'\nimport type { GoogleCalendarHealth } from './health'\nimport type { CalendarChannel, CalendarIntegration, CalendarSyncLogEntry } from './types'\n\n/** The narrow slice of the provider this needs — a fake is three functions. */\nexport interface GoogleCalendarPanelSource {\n getIntegration(): Promise<CalendarIntegration | null>\n getSyncLog(): Promise<CalendarSyncLogEntry[]>\n listChannels(): Promise<CalendarChannel[]>\n}\n\nexport interface GoogleCalendarPanelData {\n integration: CalendarIntegration | null\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n health: GoogleCalendarHealth\n}\n\nfunction localTimeZone(): string | undefined {\n // The Google calendar's own timezone is not in the calendarList response the\n // function returns today, so timezone_mismatch stays dormant until it is.\n return typeof Intl !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : undefined\n}\n\n/** Derive health from rows the caller already holds. Pure — it never fetches. */\nexport function googleCalendarHealthOf(input: {\n integration: CalendarIntegration | null\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n}): GoogleCalendarHealth {\n if (!input.integration?.connected) return { status: 'disconnected', issues: [] }\n return deriveGoogleCalendarHealth({\n connected: true,\n lastSyncAt: input.integration.lastSyncAt,\n logs: input.logs,\n channels: input.channels,\n localTimeZone: localTimeZone(),\n })\n}\n\n/**\n * One read per table. Tolerant: a partial read still reports, and a\n * disconnected integration costs exactly one request.\n */\nexport async function readGoogleCalendarPanel(\n provider: GoogleCalendarPanelSource,\n): Promise<GoogleCalendarPanelData> {\n const integration = await provider.getIntegration().catch(() => null)\n if (!integration?.connected) {\n return { integration, logs: [], channels: [], health: { status: 'disconnected', issues: [] } }\n }\n const [logs, channels] = await Promise.all([\n provider.getSyncLog().catch(() => [] as CalendarSyncLogEntry[]),\n provider.listChannels().catch(() => [] as CalendarChannel[]),\n ])\n return { integration, logs, channels, health: googleCalendarHealthOf({ integration, logs, channels }) }\n}\n","// A small round swatch tinted with a Google calendar's backgroundColor.\n//\n// Google's calendarList entries carry a `backgroundColor` hex; we render it as a\n// dot next to the calendar summary in the de-para list and as the leading dot of\n// the origin badge in the import wizard. Falls back to the muted border when a\n// calendar has no color (rare, e.g. some shared calendars).\nimport React from 'react'\n\nexport function CalendarColorDot({\n color,\n className = '',\n}: {\n color?: string | null\n className?: string\n}) {\n return (\n <span\n className={`inline-block h-2.5 w-2.5 shrink-0 rounded-full border border-black/10 ${className}`}\n style={{ backgroundColor: color || 'hsl(var(--muted-foreground))' }}\n aria-hidden\n />\n )\n}\n","// Host-plugin lookups for the smart-sync de-para target picker.\n//\n// A channel can target one professional (assignee), one service, or one location\n// instead of the whole agenda. To offer real pickers (not raw uuid inputs) the\n// connector reuses plugin-agenda's own data providers — it lives inside the same\n// package, so these are in-process reads under the same RLS:\n// • professionals + locations → createSupabaseAgendaProvider()\n// • services → createSupabasePublicBookingProvider() (v_public_services)\n// Everything is loaded once, lazily, and degrades to an empty list (the row then\n// falls back to a plain uuid input) if a lookup is unavailable for the tenant.\nimport { useEffect, useState } from 'react'\nimport { getActiveTenantId } from '@fayz-ai/core'\nimport { createSupabaseAgendaProvider } from '../../../data'\nimport { createSupabasePublicBookingProvider } from '../../../public/data/supabase'\nimport type { ChannelTargetKind } from '../types'\n\n/** A pickable target option (assignee/service/location) — id + display name. */\nexport interface LookupOption {\n id: string\n name: string\n}\n\nexport interface AgendaLookups {\n assignee: LookupOption[]\n service: LookupOption[]\n location: LookupOption[]\n}\n\nconst EMPTY: AgendaLookups = { assignee: [], service: [], location: [] }\n\nexport interface UseAgendaLookupsResult {\n lookups: AgendaLookups\n loading: boolean\n /** True when at least one of the three lookups returned rows. */\n hasAny: boolean\n}\n\n/**\n * Load professionals / services / locations for the target picker. Failures are\n * swallowed per-lookup (each falls back to an empty list) so a missing table or\n * a vertical without services never breaks the whole de-para screen.\n */\nexport function useAgendaLookups(enabled: boolean): UseAgendaLookupsResult {\n const [lookups, setLookups] = useState<AgendaLookups>(EMPTY)\n const [loading, setLoading] = useState(false)\n\n useEffect(() => {\n if (!enabled) return\n let cancelled = false\n setLoading(true)\n void (async () => {\n const agenda = createSupabaseAgendaProvider()\n const tenantId = getActiveTenantId()\n const publicProvider = tenantId\n ? createSupabasePublicBookingProvider({ tenantId })\n : null\n\n const [assignee, location, service] = await Promise.all([\n agenda.getProfessionals().then(\n (rows) => rows.map((p) => ({ id: p.id, name: p.name })),\n () => [] as LookupOption[],\n ),\n (agenda.getLocations?.() ?? Promise.resolve([])).then(\n (rows) => rows.map((l) => ({ id: l.id, name: l.name })),\n () => [] as LookupOption[],\n ),\n (publicProvider?.getServices() ?? Promise.resolve([])).then(\n (rows) => rows.map((s) => ({ id: s.id, name: s.name })),\n () => [] as LookupOption[],\n ),\n ])\n\n if (cancelled) return\n setLookups({ assignee, service, location })\n setLoading(false)\n })()\n\n return () => {\n cancelled = true\n }\n }, [enabled])\n\n const hasAny =\n lookups.assignee.length > 0 ||\n lookups.service.length > 0 ||\n lookups.location.length > 0\n\n return { lookups, loading, hasAny }\n}\n\n/** Options available for a given target kind (empty for whole-agenda / null). */\nexport function optionsForKind(\n lookups: AgendaLookups,\n kind: ChannelTargetKind,\n): LookupOption[] {\n if (kind === 'assignee') return lookups.assignee\n if (kind === 'service') return lookups.service\n if (kind === 'location') return lookups.location\n return []\n}\n","// De-para (mapping) list — one row per Google calendar.\n//\n// Reads the user's Google calendars (listGoogleCalendars) and this tenant's\n// existing channels (listChannels), joins them by google_calendar_id, and lets\n// the user, per calendar:\n// • toggle sync on/off → creates/updates the channel (is_active)\n// • pick a direction → Two-way / Import only / Export only / Off\n// • pick a target → Whole agenda / Professional / Service / Location\n// • pick an import mode → Block / Appointment\n// Every change is persisted immediately via saveChannel (RLS upsert on\n// integration_id + google_calendar_id), snapshotting the calendar summary+color\n// onto the channel. Target ids come from real host lookups (useAgendaLookups);\n// if a lookup is empty for the tenant the row degrades to a raw uuid input.\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { Loader2, AlertCircle, RefreshCw } from 'lucide-react'\nimport {\n Button,\n Checkbox,\n Badge,\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n toast,\n} from '@fayz-ai/ui'\nimport type { GoogleCalendarProvider } from '../data/supabase'\nimport type {\n CalendarChannel,\n ChannelDirection,\n ChannelTargetKind,\n ChannelImportMode,\n GoogleCalendarListEntry,\n} from '../types'\nimport { CalendarColorDot } from './CalendarColorDot'\nimport { useAgendaLookups, optionsForKind } from './useAgendaLookups'\n\nconst DIRECTION_LABELS: Record<ChannelDirection, string> = {\n bidirectional: 'Two-way',\n inbound: 'Import only',\n outbound: 'Export only',\n off: 'Off',\n}\nconst IMPORT_MODE_LABELS: Record<ChannelImportMode, string> = {\n block: 'Block',\n appointment: 'Appointment',\n}\n// 'agenda' is the UI sentinel for the whole-agenda target (target_kind = null).\nconst TARGET_KIND_LABELS: Record<'agenda' | 'assignee' | 'service' | 'location', string> = {\n agenda: 'Whole agenda',\n assignee: 'Professional',\n service: 'Service',\n location: 'Location',\n}\nconst NO_TARGET = '__none__'\n\n/** Defaults for a freshly-enabled calendar (mirror the migration defaults). */\nfunction defaultChannel(): {\n direction: ChannelDirection\n targetKind: ChannelTargetKind\n targetId: string | null\n importMode: ChannelImportMode\n} {\n return { direction: 'bidirectional', targetKind: null, targetId: null, importMode: 'block' }\n}\n\nexport function ChannelMappingList({\n provider,\n onChannelsChange,\n}: {\n provider: GoogleCalendarProvider\n /** Bubble the current channels up so the parent can gate the import wizard. */\n onChannelsChange?: (channels: CalendarChannel[]) => void\n}) {\n const [calendars, setCalendars] = useState<GoogleCalendarListEntry[]>([])\n const [byGcalId, setByGcalId] = useState<Record<string, CalendarChannel>>({})\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [savingId, setSavingId] = useState<string | null>(null)\n\n const { lookups, hasAny: hasLookups } = useAgendaLookups(true)\n\n const load = useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const [cals, channels] = await Promise.all([\n provider.listGoogleCalendars(),\n provider.listChannels(),\n ])\n setCalendars(cals)\n const map: Record<string, CalendarChannel> = {}\n for (const ch of channels) map[ch.googleCalendarId] = ch\n setByGcalId(map)\n onChannelsChange?.(channels)\n } catch (e: any) {\n setError(e?.message ?? 'Could not load Google calendars')\n } finally {\n setLoading(false)\n }\n }, [provider, onChannelsChange])\n\n useEffect(() => {\n void load()\n }, [load])\n\n /** Persist a patch for one calendar, then refresh channels (keeps ids correct). */\n const persist = useCallback(\n async (\n cal: GoogleCalendarListEntry,\n patch: {\n direction?: ChannelDirection\n targetKind?: ChannelTargetKind\n targetId?: string | null\n importMode?: ChannelImportMode\n isActive?: boolean\n },\n ) => {\n const existing = byGcalId[cal.id]\n const base = existing ?? { ...defaultChannel(), isActive: true }\n setSavingId(cal.id)\n try {\n await provider.saveChannel({\n id: existing?.id,\n googleCalendarId: cal.id,\n summary: cal.summary,\n color: cal.backgroundColor ?? null,\n direction: patch.direction ?? base.direction,\n targetKind: patch.targetKind !== undefined ? patch.targetKind : base.targetKind,\n targetId: patch.targetId !== undefined ? patch.targetId : base.targetId ?? null,\n importMode: patch.importMode ?? base.importMode,\n isActive: patch.isActive !== undefined ? patch.isActive : base.isActive,\n })\n const channels = await provider.listChannels()\n const map: Record<string, CalendarChannel> = {}\n for (const ch of channels) map[ch.googleCalendarId] = ch\n setByGcalId(map)\n onChannelsChange?.(channels)\n } catch (e: any) {\n toast.error(e?.message ?? 'Could not save calendar mapping')\n } finally {\n setSavingId(null)\n }\n },\n [byGcalId, provider, onChannelsChange],\n )\n\n if (loading) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin inline\" />\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"rounded-md border border-warning/40 bg-warning-soft/40 px-3 py-3 text-sm\">\n <div className=\"flex items-center gap-2 text-warning-soft-foreground\">\n <AlertCircle className=\"h-4 w-4\" /> {error}\n </div>\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => void load()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Retry\n </Button>\n </div>\n )\n }\n\n if (calendars.length === 0) {\n return (\n <p className=\"py-6 text-center text-sm text-muted-foreground\">\n No Google calendars found on this account.\n </p>\n )\n }\n\n return (\n <div className=\"rounded-md border divide-y\">\n {calendars.map((cal) => {\n const ch = byGcalId[cal.id]\n const active = !!ch?.isActive\n const saving = savingId === cal.id\n const direction: ChannelDirection = ch?.direction ?? 'bidirectional'\n const targetKind: ChannelTargetKind = ch?.targetKind ?? null\n const importMode: ChannelImportMode = ch?.importMode ?? 'block'\n // Import mode only matters when Google can write into the agenda.\n const canImport = direction === 'inbound' || direction === 'bidirectional'\n const kindOptions = optionsForKind(lookups, targetKind)\n\n return (\n <div key={cal.id} className=\"px-3 py-3 space-y-3\">\n <div className=\"flex items-center gap-2.5\">\n <Checkbox\n checked={active}\n disabled={saving}\n onChange={(next) => void persist(cal, { isActive: next })}\n />\n <CalendarColorDot color={cal.backgroundColor} />\n <span className=\"text-sm font-medium truncate\">{cal.summary}</span>\n {cal.primary && (\n <Badge variant=\"outline\" className=\"shrink-0\">\n Primary\n </Badge>\n )}\n {saving && <Loader2 className=\"ml-auto h-3.5 w-3.5 animate-spin text-muted-foreground\" />}\n </div>\n\n {active && (\n <div className=\"grid gap-2 pl-[26px] sm:grid-cols-2 lg:grid-cols-4\">\n {/* Direction */}\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Direction</span>\n <Select\n value={direction}\n onValueChange={(v) => void persist(cal, { direction: v as ChannelDirection })}\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(DIRECTION_LABELS) as ChannelDirection[]).map((d) => (\n <SelectItem key={d} value={d}>\n {DIRECTION_LABELS[d]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n\n {/* Target kind */}\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Target</span>\n <Select\n value={targetKind ?? 'agenda'}\n onValueChange={(v) =>\n void persist(cal, {\n targetKind: v === 'agenda' ? null : (v as ChannelTargetKind),\n // Reset the id whenever the kind changes.\n targetId: null,\n })\n }\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(TARGET_KIND_LABELS) as Array<keyof typeof TARGET_KIND_LABELS>).map(\n (k) => (\n <SelectItem key={k} value={k}>\n {TARGET_KIND_LABELS[k]}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Select>\n </label>\n\n {/* Target id — real picker when we have lookups, uuid input otherwise */}\n {targetKind && (\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">\n {TARGET_KIND_LABELS[targetKind]}\n </span>\n {kindOptions.length > 0 ? (\n <Select\n value={ch?.targetId ?? NO_TARGET}\n onValueChange={(v) =>\n void persist(cal, { targetId: v === NO_TARGET ? null : v })\n }\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue placeholder=\"Select…\" />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map((o) => (\n <SelectItem key={o.id} value={o.id}>\n {o.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <input\n defaultValue={ch?.targetId ?? ''}\n placeholder=\"uuid\"\n onBlur={(e) =>\n void persist(cal, { targetId: e.target.value.trim() || null })\n }\n className=\"w-full mt-1 h-8 rounded-input border border-input bg-card px-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n )}\n </label>\n )}\n\n {/* Import mode — only when inbound */}\n {canImport && (\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Import as</span>\n <Select\n value={importMode}\n onValueChange={(v) => void persist(cal, { importMode: v as ChannelImportMode })}\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(IMPORT_MODE_LABELS) as ChannelImportMode[]).map((m) => (\n <SelectItem key={m} value={m}>\n {IMPORT_MODE_LABELS[m]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n )}\n </div>\n )}\n </div>\n )\n })}\n {!hasLookups && (\n <p className=\"px-3 py-2 text-[11px] text-muted-foreground\">\n No professional/service/location lookups available — target ids fall back to manual uuid\n entry.\n </p>\n )}\n </div>\n )\n}\n","// Import wizard — pull FUTURE Google events into the agenda as blocks/appointments.\n//\n// listExternalEvents() returns events on the active inbound channels that are not\n// yet linked to an appointment. The user ticks the ones to bring in and confirms;\n// importEvents() runs them through gcal_import_event (honouring each channel's\n// import_mode + target) and returns a per-item tally {imported, skipped, errors}.\n// Events show their source calendar as a colored badge and an \"All-day\" badge\n// when applicable; times are formatted pt-BR.\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Loader2, CalendarPlus, CheckCircle2, AlertCircle, RefreshCw, X } from 'lucide-react'\nimport { Button, Checkbox, Badge, toast } from '@fayz-ai/ui'\nimport type { GoogleCalendarProvider } from '../data/supabase'\nimport type { CalendarChannel, ExternalEventPreview, ImportEventsResult } from '../types'\nimport { CalendarColorDot } from './CalendarColorDot'\n\n/** pt-BR datetime label, all-day aware (date only for all-day events). */\nfunction formatWhen(ev: ExternalEventPreview): string {\n const start = new Date(ev.startsAt)\n if (ev.allDay) {\n return start.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })\n }\n return start.toLocaleString('pt-BR', {\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n })\n}\n\nexport function ImportEventsWizard({\n provider,\n channels,\n onClose,\n onImported,\n}: {\n provider: GoogleCalendarProvider\n /** Active channels — used to label each event with its source calendar + color. */\n channels: CalendarChannel[]\n onClose: () => void\n /** Fired after a successful import so the parent can refresh status/history. */\n onImported?: (result: ImportEventsResult) => void\n}) {\n const [events, setEvents] = useState<ExternalEventPreview[]>([])\n const [selected, setSelected] = useState<Set<string>>(new Set())\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [importing, setImporting] = useState(false)\n const [result, setResult] = useState<ImportEventsResult | null>(null)\n\n const channelById = useMemo(() => {\n const m: Record<string, CalendarChannel> = {}\n for (const c of channels) m[c.id] = c\n return m\n }, [channels])\n\n const load = useCallback(async () => {\n setLoading(true)\n setError(null)\n setResult(null)\n try {\n const rows = await provider.listExternalEvents()\n setEvents(rows)\n setSelected(new Set(rows.map((r) => r.eventId)))\n } catch (e: any) {\n setError(e?.message ?? 'Could not load upcoming events')\n } finally {\n setLoading(false)\n }\n }, [provider])\n\n useEffect(() => {\n void load()\n }, [load])\n\n const toggle = (eventId: string) =>\n setSelected((prev) => {\n const next = new Set(prev)\n if (next.has(eventId)) next.delete(eventId)\n else next.add(eventId)\n return next\n })\n\n const allSelected = events.length > 0 && selected.size === events.length\n const toggleAll = () =>\n setSelected(allSelected ? new Set() : new Set(events.map((e) => e.eventId)))\n\n async function handleImport() {\n const items = events\n .filter((e) => selected.has(e.eventId))\n .map((e) => ({ channelId: e.channelId, eventId: e.eventId }))\n if (items.length === 0) return\n setImporting(true)\n try {\n const res = await provider.importEvents(items)\n setResult(res)\n onImported?.(res)\n toast.success(`Imported ${res.imported} · skipped ${res.skipped}`)\n // Drop imported events from the list so the wizard reflects the new state.\n await load()\n } catch (e: any) {\n toast.error(e?.message ?? 'Import failed')\n } finally {\n setImporting(false)\n }\n }\n\n return (\n <div className=\"rounded-card border bg-card\">\n <div className=\"flex items-center gap-2 border-b px-3 py-2\">\n <CalendarPlus className=\"h-4 w-4 text-muted-foreground\" />\n <h4 className=\"text-sm font-semibold\">Import future events</h4>\n <button\n onClick={onClose}\n className=\"ml-auto rounded p-1 text-muted-foreground hover:bg-muted/50\"\n aria-label=\"Close\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n {loading ? (\n <div className=\"py-8 text-center text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin inline\" />\n </div>\n ) : error ? (\n <div className=\"p-3\">\n <div className=\"flex items-center gap-2 text-sm text-warning-soft-foreground\">\n <AlertCircle className=\"h-4 w-4\" /> {error}\n </div>\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => void load()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Retry\n </Button>\n </div>\n ) : events.length === 0 ? (\n <div className=\"py-8 px-4 text-center space-y-1\">\n <p className=\"text-sm font-medium\">You're all caught up</p>\n <p className=\"text-xs text-muted-foreground\">\n No upcoming Google events left to import on your active calendars.\n </p>\n {result && (\n <p className=\"text-xs text-success\">\n Imported {result.imported} · skipped {result.skipped}\n {result.errors.length > 0 ? ` · ${result.errors.length} errors` : ''}\n </p>\n )}\n </div>\n ) : (\n <>\n <div className=\"flex items-center gap-2.5 border-b px-3 py-2\">\n <Checkbox checked={allSelected} onChange={toggleAll} />\n <span className=\"text-xs text-muted-foreground\">\n {selected.size} of {events.length} selected\n </span>\n </div>\n <div className=\"max-h-[320px] overflow-y-auto divide-y\">\n {events.map((ev) => {\n const ch = channelById[ev.channelId]\n return (\n <label\n key={ev.eventId}\n className=\"flex items-start gap-2.5 px-3 py-2.5 cursor-pointer hover:bg-muted/30\"\n >\n <Checkbox\n checked={selected.has(ev.eventId)}\n onChange={() => toggle(ev.eventId)}\n />\n <div className=\"min-w-0 flex-1 space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">\n {ev.summary || '(no title)'}\n </span>\n {ev.allDay && (\n <Badge variant=\"secondary\" className=\"shrink-0\">\n All-day\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{formatWhen(ev)}</span>\n <span className=\"inline-flex items-center gap-1\">\n <CalendarColorDot color={ch?.color} />\n {ch?.summary ?? ev.calendarId}\n </span>\n </div>\n </div>\n </label>\n )\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t px-3 py-2\">\n {result && (\n <span className=\"text-xs text-muted-foreground\">\n Last run: {result.imported} imported\n {result.errors.length > 0 ? `, ${result.errors.length} errors` : ''}\n </span>\n )}\n <Button\n size=\"sm\"\n className=\"ml-auto\"\n disabled={importing || selected.size === 0}\n onClick={handleImport}\n >\n {importing ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n )}\n Import {selected.size > 0 ? selected.size : ''}\n </Button>\n </div>\n </>\n )}\n </div>\n )\n}\n","// Google Calendar as a unified ConnectorDefinition.\n//\n// Surfaces inside plugin-agenda's settings → Integrations tab (the host),\n// rendered by the shared ConnectorsHub. The hub handles the OAuth connect/\n// disconnect; what is left here is declared through the four seams the hub\n// renders in four different places, because they are four different questions:\n//\n// getStatus().issues → Visão geral what is wrong right now\n// listRuns → Sincronizações what has already happened\n// syncActions → Sincronizações sync now, import future events\n// ExtraPanel → Configurações the de-para, and nothing else\n//\n// All four used to be one `ExtraPanel` on the settings tab — health warnings, a\n// calendar mapping, an import wizard and a run log stacked under a heading that\n// said \"Configurações\". That is what the founder called *bem ruim e estranho\n// junto na tela de settings direto*, and none of it was a rendering problem: the\n// panel was the only seam there was, so everything arrived through it.\nimport React, { useEffect, useState } from 'react'\nimport type { ConnectorDefinition, SyncRun, SyncTrigger } from '@fayz-ai/core'\nimport { connectionStatus, createConnectionStore } from '@fayz-ai/core'\nimport { fayzConnectorOAuth } from '@fayz-ai/admin'\nimport { createGoogleCalendarProvider } from './data/supabase'\nimport { readGoogleCalendarPanel } from './panel-data'\nimport type { GoogleCalendarHealth, GoogleCalendarHealthIssueCode } from './health'\nimport type { CalendarChannel, CalendarSyncLogEntry } from './types'\nimport { ChannelMappingList } from './components/ChannelMappingList'\nimport { ImportEventsWizard } from './components/ImportEventsWizard'\n\nconst provider = createGoogleCalendarProvider()\n\nexport const GOOGLE_CALENDAR_CONNECTOR_ID = 'google-calendar'\n\n/**\n * \"Is Google Calendar on for this tenant?\" — asked of `plg_connections`, the\n * one table every connector answers it from.\n *\n * It used to be asked of `plg_calendar_integrations.token_expires_at`: a\n * timestamp stamped whenever a token was stored, which meant the answer was a\n * by-product of the credential living in this pool. The credential is in the\n * platform vault now, so that column is gone (migration 007) and so is the\n * question it answered.\n */\nexport const googleCalendarConnectionStore = () =>\n createConnectionStore(GOOGLE_CALENDAR_CONNECTOR_ID, {\n settingsKeys: ['calendarId'],\n })\n\n// Product copy: what each derived issue means to the person reading the badge.\nconst HEALTH_LABELS: Record<GoogleCalendarHealthIssueCode, string> = {\n sync_error: 'a última sincronização falhou',\n sync_missing: 'nenhuma sincronização foi feita ainda',\n sync_stale: 'sem sincronizar há mais de uma hora',\n inbound_channel_missing: 'nenhuma agenda do Google está marcada para importar',\n watch_missing: 'o aviso automático do Google não está ativo',\n watch_expiring: 'o aviso automático do Google está prestes a expirar',\n timezone_mismatch: 'o fuso horário do Google é diferente do seu',\n}\n\n/** One issue as a sentence. */\nfunction issueLine(issue: GoogleCalendarHealth['issues'][number]): string {\n const label = HEALTH_LABELS[issue.code]\n return issue.detail ? `${label} (${issue.detail})` : label\n}\n\n/** One line for the status badge — the first thing wrong, or that all is well. */\nfunction healthDetail(health: GoogleCalendarHealth): string | undefined {\n if (health.status === 'disconnected') return undefined\n if (health.status === 'healthy') return 'Sincronizando normalmente'\n return issueLine(health.issues[0])\n}\n\n/** Read everything the health rule needs. Tolerant: a partial read still reports. */\nasync function readHealth(): Promise<GoogleCalendarHealth> {\n return (await readGoogleCalendarPanel(provider)).health\n}\n\n/** Channels Google is allowed to write INTO the agenda from (gate the import wizard). */\nfunction inboundChannels(channels: CalendarChannel[]): CalendarChannel[] {\n return channels.filter(\n (c) => c.isActive && (c.direction === 'inbound' || c.direction === 'bidirectional'),\n )\n}\n\n/** The four words the column holds (migrations/001); anything else is a manual run. */\nconst TRIGGERS: readonly SyncTrigger[] = ['on-write', 'scheduled', 'manual', 'webhook']\n\n/**\n * This connector's own log, in the one shape the shared history renders.\n *\n * `plg_calendar_sync_log` predates `plg_sync_runs` and still holds the rows, so\n * the mapping is here rather than a migration nobody needs yet — what the\n * surface asked for is a {@link SyncRun}, not a table.\n */\nfunction toSyncRun(entry: CalendarSyncLogEntry): SyncRun {\n return {\n connectionId: '',\n connectorId: 'google-calendar',\n direction: entry.direction === 'inbound' ? 'inbound' : 'outbound',\n triggerKind: TRIGGERS.includes(entry.trigger as SyncTrigger) ? (entry.trigger as SyncTrigger) : 'manual',\n status: entry.status === 'success' || entry.status === 'partial' || entry.status === 'running'\n ? entry.status\n : 'error',\n id: entry.id,\n fetched: entry.fetched,\n written: entry.written,\n error: entry.error ?? null,\n startedAt: entry.createdAt,\n }\n}\n\n/**\n * The de-para, and nothing else — the Configurações tab.\n *\n * Which Google calendar feeds which professional IS configuration: it is chosen\n * once, changed on a Tuesday in March, and never \"finished\". Everything that\n * used to sit above and below it in this component was not — a health warning is\n * status, an import is an act, a run log is history, and each of them now\n * arrives through the seam that renders it where it belongs.\n */\nfunction GoogleCalendarMapping() {\n const [connected, setConnected] = useState(false)\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n void provider\n .getIntegration()\n .then((i) => { if (!cancelled) setConnected(!!i?.connected) })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoaded(true) })\n return () => { cancelled = true }\n }, [])\n\n if (!loaded || !connected) return null\n\n return (\n <div className=\"space-y-2\">\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n Diga o que cada agenda do Google sincroniza — um profissional, um serviço, um local, ou a\n sua agenda inteira. Cada mudança é salva na hora.\n </p>\n <ChannelMappingList provider={provider} />\n </div>\n )\n}\n\n/**\n * The import, as the shared surface opens it. The wizard is untouched — what\n * went away is the button, the spinner and the toast around it.\n */\nfunction GoogleCalendarImport({ onClose, onRan }: { onClose(): void; onRan?(): void }) {\n const [channels, setChannels] = useState<CalendarChannel[]>([])\n\n useEffect(() => {\n let cancelled = false\n void provider\n .listChannels()\n .then((ch) => { if (!cancelled) setChannels(ch) })\n .catch(() => {})\n return () => { cancelled = true }\n }, [])\n\n return (\n <ImportEventsWizard\n provider={provider}\n channels={inboundChannels(channels)}\n onClose={onClose}\n onImported={() => onRan?.()}\n />\n )\n}\n\nexport const googleCalendarConnectorDef: ConnectorDefinition = {\n id: 'google-calendar',\n hostPluginId: 'agenda',\n name: 'Google Calendar',\n description: 'Two-way sync between your bookings and Google Calendar.',\n icon: 'Calendar',\n authKind: 'oauth',\n category: 'scheduling',\n // `direction` is who reaches for whom: this app reaches Google (consent, push,\n // pull). The data being BIDIRECTIONAL is a property of the entity, and is\n // declared where the type allows it — see ./connector.ts, capability\n // `booking: 'bidirectional'`.\n direction: 'outbound',\n // Sync only, and deliberately: the agenda has to exist inside the app — to be\n // listed, filtered, reported on, and read when Google is unreachable. An\n // agentic plane would answer questions but leave the calendar screen empty.\n planes: ['sync'],\n docsUrl: 'https://support.google.com/calendar',\n // What it needs, grounded in what the data plane actually does. `booking` is\n // read AND written: the pull path lands external events through the\n // `gcal_import_event` / `gcal_apply_event_patch` RPCs (migrations/002 §\n // \"import\"), which INSERT and UPDATE public.appointments, and the push path\n // reads the appointment plus its items to compose the Google event.\n //\n // Marked sensitive because of what leaves the tenant, not because of the row\n // count: the event title is \"<serviços> — <nome do cliente>\" and the\n // description carries the appointment notes (./mapping.ts). Someone\n // authorizing this is sending client names and visit notes to Google, and that\n // is the fact the consent view exists to put in front of them.\n permissions: [\n {\n kind: 'data',\n resource: 'booking',\n actions: ['read', 'write'],\n reason:\n 'Ler os agendamentos para criar os eventos no Google, e gravar aqui os eventos que você criar por lá. Nome do cliente, serviços e observações vão no evento.',\n sensitive: true,\n },\n // The three facts that change what Google should show, and only those.\n // `booking_completed`/`booking_no_show` are left out because Google has no\n // notion of either and the event does not move; `booking_reminder` likewise.\n {\n kind: 'event',\n resource: 'agenda.booking_created',\n actions: ['listen'],\n reason: 'Saber que um horário foi marcado, para criar o evento no Google Calendar.',\n },\n {\n kind: 'event',\n resource: 'agenda.booking_rescheduled',\n actions: ['listen'],\n reason: 'Saber que um horário mudou, para mover o evento no Google Calendar.',\n },\n {\n kind: 'event',\n resource: 'agenda.booking_cancelled',\n actions: ['listen'],\n reason: 'Saber que um agendamento foi cancelado, para apagar o evento do Google Calendar.',\n },\n ],\n // Keys copied from ../../lib/message-events.ts, which is where the agenda\n // declares them.\n //\n // `agenda.booking_completed` and `agenda.booking_no_show` are left out on\n // purpose: Google has no notion of either, and the event does not move, so\n // waking the connector for them is a round-trip that changes nothing.\n // `agenda.booking_reminder` is left out for the same reason — a reminder is\n // not a change to the calendar.\n //\n // Deletion is missing because the agenda declares no `booking_deleted` fact;\n // a hard delete is delivered by the trigger in migrations/004, not by an\n // event. That asymmetry is real and is written down in ./GOOGLE-CALENDAR.md.\n subscribesTo: [\n 'agenda.booking_created',\n 'agenda.booking_rescheduled',\n 'agenda.booking_cancelled',\n ],\n // These are not preferences someone chose — they are what the integration IS,\n // so they appear only while the connection is live and disconnecting is the\n // way out. Today the trigger in migrations/004 delivers them; when the Fayz\n // ingress lands it takes over the same three, which is what makes that swap a\n // configuration change instead of a rewrite.\n managedAutomations: [\n { eventKey: 'agenda.booking_created', label: 'Criar o evento no Google Calendar quando um horário é agendado aqui' },\n { eventKey: 'agenda.booking_rescheduled', label: 'Mover o evento no Google Calendar quando o horário é remarcado' },\n { eventKey: 'agenda.booking_cancelled', label: 'Apagar o evento do Google Calendar quando o agendamento é cancelado' },\n ],\n // The two moments that DO exist in code, as opposed to the three above, which\n // are delivered by the trigger in migrations/004 rather than by an ingress.\n // Both are sync moments and both reach `booking`, which is what `touches`\n // says — the connector cannot name a resource it did not ask for.\n invokedAt: [\n {\n key: 'agenda.booking.push',\n label: 'Um horário é criado, remarcado ou cancelado aqui, e o evento é atualizado no Google',\n plane: 'sync',\n trigger: 'on-write',\n touches: ['booking'],\n },\n {\n key: 'agenda.calendar.pull',\n label: 'O Google avisa que algo mudou por lá, e os eventos são trazidos para cá',\n plane: 'sync',\n trigger: 'webhook',\n touches: ['booking'],\n },\n ],\n /**\n * The LIST row, from the connection the hub already batched — one request for\n * N connectors, and no calendar read at all.\n */\n ...connectionStatus(\n GOOGLE_CALENDAR_CONNECTOR_ID,\n (connection) => (connection?.active ? { connected: true, plane: 'sync' } : { connected: false }),\n { store: googleCalendarConnectionStore },\n ),\n /**\n * The DETAIL screen, where health is worth a round-trip.\n *\n * Two questions, in order, and they are not the same one: `plg_connections`\n * says whether the clinic authorized Google, and ./health.ts says whether the\n * sync is actually working. Asking only the second is what let a connection\n * read as \"conectado\" off a token timestamp; asking only the first would\n * report a healthy connector that has not synced since Tuesday.\n */\n async getStatus() {\n try {\n const connection = await googleCalendarConnectionStore().get()\n if (!connection?.active) return { connected: false }\n\n const health = await readHealth()\n // `detail` is the one line a row has room for; `issues` is all of them,\n // for the detail screen. A connection can be unwell in three ways at once.\n return {\n connected: true,\n plane: 'sync',\n detail: healthDetail(health),\n issues: health.issues.map(issueLine),\n }\n } catch {\n return { connected: false }\n }\n },\n // Consent runs on the platform: it holds the Google client pair, takes the\n // callback and puts the grant in the vault. This pool used to do all three.\n startOAuth: fayzConnectorOAuth(GOOGLE_CALENDAR_CONNECTOR_ID),\n /**\n * The other half of the consent. The platform stores the grant; the pool\n * stores \"is it on?\", and with nobody writing the second the connector would\n * answer \"não conectado\" to a clinic that had just authorized Google.\n *\n * Called with no values — the credential is not ours to see.\n */\n saveConnection: async () => {\n // The sync state row first: a channel FKs to it, so a connection saved\n // without one is a connector that says \"conectado\" and cannot map a single\n // calendar. It used to be created as a side effect of storing the token.\n await provider.ensureIntegration()\n await googleCalendarConnectionStore().save({ active: true })\n },\n /**\n * Three things end a connection, and only the first is this pool's:\n * the row flips inactive (here)\n * the watches are stopped at Google and the cursors cleared (the function)\n * the grant is revoked (the platform — it holds the token)\n *\n * The function call is best-effort on purpose: a clinic that already revoked\n * us at Google gets a 409 from it, and refusing to disconnect over that would\n * leave the connector on with no way to turn it off.\n */\n disconnect: async () => {\n try {\n await provider.disconnect()\n } catch {\n /* Google already gone, or the pool's watches were never opened */\n }\n await googleCalendarConnectionStore().disconnect()\n },\n // Disconnecting stops the traffic; it does not undo it. Said here because the\n // question is only ever asked next to the button.\n disconnectNote:\n 'Desconectar para a sincronização nos dois sentidos. Os agendamentos já importados continuam aqui, e os eventos já criados continuam no Google.',\n async listRuns(options) {\n try {\n const log = await provider.getSyncLog()\n const runs = log.map(toSyncRun)\n return options?.limit ? runs.slice(0, options.limit) : runs\n } catch {\n return []\n }\n },\n // Declared, not drawn — the same seam Bling uses. Behaviour unchanged.\n syncActions: [\n {\n key: 'sync_now',\n label: 'Sincronizar agora',\n direction: 'inbound',\n run: async () => {\n const result = await provider.syncNow()\n return `Sincronizado — ${result.written} atualizados`\n },\n },\n {\n key: 'import_events',\n label: 'Importar eventos futuros',\n direction: 'inbound',\n // Hidden rather than disabled: nothing to bring in, and a greyed control\n // reads as something the reader failed to do.\n available: async () => {\n try {\n return inboundChannels(await provider.listChannels()).length > 0\n } catch {\n return false\n }\n },\n Component: GoogleCalendarImport,\n run: async () => {},\n },\n ],\n ExtraPanel: GoogleCalendarMapping,\n}\n","// AUTO-GENERATED from 001_google_calendar.sql, 002_smart_sync.sql, 003_plg_rename.sql, 004_drop_oauth_tokens.sql, 005_outbound_vault_delivery.sql, 006_webhook_deliveries_outbox.sql, 007_credential_free_install.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_001_GOOGLE_CALENDAR = `-- ---------------------------------------------------------------------------\n-- Google Calendar integration (bidirectional) — connection + audit + triggers\n-- ---------------------------------------------------------------------------\n-- Outbound (Fayz booking → Google event) fires from a trigger on public.appointments\n-- via pg_net to the google-calendar-sync edge function (push_event). Inbound\n-- (Google → booking) runs on a pg_cron schedule (pull_events) and/or a Google\n-- watch-channel webhook. The booking↔event link is stored on\n-- public.appointments.metadata.googleCalendarEventId (no schema change there).\n\n-- Plugin-owned tables carry the platform \\`plg_<plugin>_\\` prefix (DATA-MODEL.md\n-- Ring 1). Legacy pools provisioned under the old \\`calendar_*\\` names are migrated\n-- by 003_plg_rename.sql; fresh installs are born with the prefixed names here.\nCREATE TABLE IF NOT EXISTS public.plg_calendar_integrations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n provider text NOT NULL DEFAULT 'google',\n oauth_refresh_token text,\n oauth_access_token text,\n token_expires_at timestamptz,\n calendar_id text NOT NULL DEFAULT 'primary',\n -- Incremental pull cursor + Google watch channel bookkeeping.\n sync_token text,\n channel_id text,\n channel_resource_id text,\n channel_expires_at timestamptz,\n active boolean NOT NULL DEFAULT true,\n last_sync_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, provider)\n);\nALTER TABLE public.plg_calendar_integrations ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_integrations_tenant ON public.plg_calendar_integrations(tenant_id);\n\nCREATE TABLE IF NOT EXISTS public.plg_calendar_sync_log (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n direction text NOT NULL, -- inbound | outbound\n trigger text, -- on-write | scheduled | webhook | manual\n status text NOT NULL DEFAULT 'success', -- success | partial | error\n fetched integer NOT NULL DEFAULT 0,\n written integer NOT NULL DEFAULT 0,\n error text,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_calendar_sync_log ENABLE ROW LEVEL SECURITY;\n\n-- RLS: tenant isolation.\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY['plg_calendar_integrations','plg_calendar_sync_log'])\n LOOP\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_rls') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids())) WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_rls', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- ---------------------------------------------------------------------------\n-- Outbound trigger: booking change → edge function (push_event).\n-- Requires pg_net + a configured function URL. Set once per project:\n-- ALTER DATABASE postgres SET app.gcal_sync_url = 'https://<ref>.functions.supabase.co/google-calendar-sync';\n-- ALTER DATABASE postgres SET app.gcal_service_key = '<service-role-key>';\n-- Safe to skip in environments without pg_net — outbound also works via the\n-- client-side withGoogleCalendarSync() decorator.\n-- ---------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql SECURITY DEFINER AS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\nBEGIN\n IF url IS NULL OR url = '' THEN RETURN COALESCE(NEW, OLD); END IF;\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object('Content-Type', 'application/json', 'Authorization', 'Bearer ' || COALESCE(key, '')),\n body := jsonb_build_object('action', 'push_event', 'op', op, 'bookingId', rec.id, 'tenantId', rec.tenant_id)\n );\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\nDROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;\nCREATE TRIGGER trg_gcal_push\n AFTER INSERT OR UPDATE OR DELETE ON public.appointments\n FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();\n\n-- Inbound schedule (optional): pull external changes every 10 minutes.\n-- SELECT cron.schedule('gcal-pull', '*/10 * * * *', $$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object('Content-Type','application/json','Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events'));\n-- $$);\n`\n\nexport const MIGRATION_002_SMART_SYNC = `-- ---------------------------------------------------------------------------\n-- Google Calendar SMART SYNC — multi-calendar de-para + loop-safe two-way sync\n-- ---------------------------------------------------------------------------\n-- Builds on 001_google_calendar.sql. Where 001 modelled a single calendar per\n-- tenant (plg_calendar_integrations, one outbound trigger, a pull template), 002\n-- makes the sync vertical-agnostic and bidirectional-safe:\n--\n-- §1 public.plg_calendar_channels — de-para: one Google calendar → one sync\n-- target (whole tenant / assignee / service\n-- / location), per direction + import mode\n-- §2 fn_gcal_push_booking (REPLACE)— loop-prevention guard + correlation id\n-- §3 plg_calendar_sync_log — correlation_id + channel_id_ref columns\n-- §4 inbound write functions — the ONLY path Google→booking writes take\n-- (gcal_import_event / gcal_apply_event_patch\n-- / gcal_unlink_channel), SECURITY DEFINER,\n-- service_role-only\n-- §5 get_available_slots (REPLACE) — tenant-wide imported blocks now also\n-- remove slots for every professional\n-- §6 pg_cron template — per-channel pull\n--\n-- Idempotent / re-runnable: IF NOT EXISTS, CREATE OR REPLACE, DROP … IF EXISTS.\n-- Written against the canonical public names (appointments uses starts_at/ends_at,\n-- metadata jsonb, party_id/assignee_id — see packages/db 004_archetypes.sql).\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — plg_calendar_channels: multi-calendar de-para (vertical-agnostic)\n-- target_kind NULL → whole tenant agenda (agency-os): every professional\n-- target_kind 'assignee' → calendar maps to one professional (school: teacher)\n-- target_kind 'service' | 'location' → clinic-style mapping\n-- import_mode 'block' → inbound events become opaque busy blocks\n-- import_mode 'appointment' → inbound events become real appointments\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_channels (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n integration_id uuid NOT NULL REFERENCES public.plg_calendar_integrations(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL,\n google_calendar_id text NOT NULL,\n summary text,\n color text,\n direction text NOT NULL DEFAULT 'bidirectional'\n CHECK (direction IN ('inbound','outbound','bidirectional','off')),\n target_kind text CHECK (target_kind IN ('assignee','service','location')),\n target_id uuid,\n import_mode text NOT NULL DEFAULT 'block'\n CHECK (import_mode IN ('block','appointment')),\n sync_token text,\n channel_id text,\n resource_id text,\n channel_expires_at timestamptz,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (integration_id, google_calendar_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_tenant ON public.plg_calendar_channels(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_integration ON public.plg_calendar_channels(integration_id);\n\nALTER TABLE public.plg_calendar_channels ENABLE ROW LEVEL SECURITY;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_channels TO authenticated;\n-- service_role bypasses RLS, but this table is born after 004's blanket grant,\n-- so grant it explicitly (the inbound functions run as definer/service_role).\nGRANT ALL ON public.plg_calendar_channels TO service_role;\n\nDROP TRIGGER IF EXISTS plg_calendar_channels_updated_at ON public.plg_calendar_channels;\nCREATE TRIGGER plg_calendar_channels_updated_at BEFORE UPDATE ON public.plg_calendar_channels\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\n-- RLS: tenant isolation (padrão 001) + explicit service_role FOR ALL policy\n-- (matches the vigente service_role policy pattern from 001_core payment_events).\nDROP POLICY IF EXISTS plg_calendar_channels_rls ON public.plg_calendar_channels;\nCREATE POLICY plg_calendar_channels_rls ON public.plg_calendar_channels\n FOR ALL TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()))\n WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));\n\nDROP POLICY IF EXISTS plg_calendar_channels_service ON public.plg_calendar_channels;\nCREATE POLICY plg_calendar_channels_service ON public.plg_calendar_channels\n FOR ALL TO service_role USING (true) WITH CHECK (true);\n\n-- ===========================================================================\n-- §2 — Outbound trigger with loop-prevention + correlation id.\n-- CREATE OR REPLACE of 001's fn_gcal_push_booking. Same pg_net → edge function\n-- payload (app.gcal_sync_url / app.gcal_service_key), but now:\n-- * SKIP the push when the write itself came from the Google sync, detected by\n-- the TRANSACTION-LOCAL GUC app.booking_origin = 'google' — set by every §4\n-- writer via set_config(..., true) and gone when the transaction ends.\n-- This is what stops the Google→booking→Google→… echo loop.\n-- Deliberately NOT a persistent metadata check: a sticky marker\n-- (metadata.syncOrigin) would permanently mute pushes for imported events,\n-- so a later admin edit would never reach Google. metadata.syncOrigin is\n-- kept by §4 as provenance only — this trigger does not read it.\n-- * carry a correlation_id so both directions can be stitched in the sync log\n-- (from GUC app.booking_correlation_id, else a fresh uuid — design ported\n-- from PR #7).\n-- ===========================================================================\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql SECURITY DEFINER AS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- Loop guard: never bounce a Google-originated write back to Google.\n -- Transaction-local GUC only (see §2 header for why not persistent metadata).\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n IF url IS NULL OR url = '' THEN RETURN COALESCE(NEW, OLD); END IF;\n\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object('Content-Type', 'application/json',\n 'Authorization', 'Bearer ' || COALESCE(key, '')),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- Re-assert the trigger (idempotent; unchanged from 001).\nDROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;\nCREATE TRIGGER trg_gcal_push\n AFTER INSERT OR UPDATE OR DELETE ON public.appointments\n FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();\n\n-- ===========================================================================\n-- §3 — sync log: correlate the two directions + reference the source channel.\n-- ===========================================================================\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS correlation_id uuid;\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS channel_id_ref uuid\n REFERENCES public.plg_calendar_channels(id) ON DELETE SET NULL;\n-- Unlinked future events seen during a pull (import-wizard candidates), so the\n-- log can show \"N eventos aguardando import\" without re-hitting Google.\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS discovered integer;\n\n-- ===========================================================================\n-- §4 — Inbound write path (Google → booking). THE single entry point used by\n-- the edge function (scheduled pull, webhook, and the import wizard). All three\n-- functions are SECURITY DEFINER with SET search_path = public and are granted\n-- to service_role ONLY (anon/authenticated explicitly revoked) — they bypass the\n-- tenant RLS on purpose and must never be reachable from the anon/authenticated\n-- PostgREST surface. Every writer sets the TRANSACTION-LOCAL GUC\n-- app.booking_origin='google' (set_config ..., true) so §2's trigger suppresses\n-- the echo for THIS write only; metadata.syncOrigin is provenance, not a guard.\n-- ===========================================================================\n\n-- gcal_import_event: create (or idempotently update) a booking from a Google\n-- event, honouring the channel's import_mode + target mapping.\n-- kind = 'block' | 'appointment' (from channel.import_mode)\n-- assignee_id = channel.target_id when target_kind='assignee', else NULL\n-- (NULL = tenant-wide → blocks every professional, see §5)\n-- location_id = channel.target_id when target_kind='location', else NULL\n-- status = 'scheduled'\n-- No order is created — an external import is not a sale. Idempotent on\n-- (tenant_id, metadata.googleCalendarEventId): update in place if seen before.\nCREATE OR REPLACE FUNCTION public.gcal_import_event(\n p_tenant_id uuid,\n p_channel_id uuid,\n p_event_id text,\n p_etag text,\n p_summary text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_all_day boolean,\n p_description text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_ch record;\n v_kind text;\n v_assignee uuid;\n v_location uuid;\n v_ends timestamptz;\n v_meta jsonb;\n v_existing uuid;\n v_appt uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL OR p_starts_at IS NULL THEN\n RAISE EXCEPTION 'gcal_import_event: tenant, event id and start are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n -- Resolve the channel mapping (must belong to the same tenant).\n SELECT c.import_mode, c.target_kind, c.target_id\n INTO v_ch\n FROM plg_calendar_channels c\n WHERE c.id = p_channel_id AND c.tenant_id = p_tenant_id;\n IF NOT FOUND THEN RAISE EXCEPTION 'gcal_import_event: unknown channel for tenant'; END IF;\n\n v_kind := CASE WHEN v_ch.import_mode = 'appointment' THEN 'appointment' ELSE 'block' END;\n v_assignee := CASE WHEN v_ch.target_kind = 'assignee' THEN v_ch.target_id ELSE NULL END;\n v_location := CASE WHEN v_ch.target_kind = 'location' THEN v_ch.target_id ELSE NULL END;\n\n -- All-day events without an explicit end block the whole day so §5 excludes it.\n v_ends := COALESCE(\n p_ends_at,\n CASE WHEN COALESCE(p_all_day, false) THEN p_starts_at + interval '1 day' ELSE p_starts_at END\n );\n\n v_meta := jsonb_build_object(\n 'syncOrigin', 'google',\n 'googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalChannelId', p_channel_id::text,\n 'allDay', COALESCE(p_all_day, false),\n 'title', p_summary,\n 'source', 'google_import'\n );\n\n -- Idempotency: has this event already been imported for the tenant?\n SELECT b.id INTO v_existing\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_existing IS NOT NULL THEN\n UPDATE appointments b\n SET kind = v_kind,\n assignee_id = v_assignee,\n location_id = v_location,\n starts_at = p_starts_at,\n ends_at = v_ends,\n status = 'scheduled',\n notes = COALESCE(p_description, p_summary),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || v_meta,\n updated_at = now()\n WHERE b.id = v_existing\n RETURNING b.id INTO v_appt;\n ELSE\n INSERT INTO appointments (tenant_id, kind, assignee_id, location_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, v_kind, v_assignee, v_location,\n p_starts_at, v_ends, 'scheduled', COALESCE(p_description, p_summary), v_meta)\n RETURNING id INTO v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\n-- gcal_apply_event_patch: apply an inbound reschedule/cancel to an already-linked\n-- booking. Located by metadata.googleCalendarEventId. Echo suppression: if the\n-- stored gcalEtag already equals the incoming etag, this is our own write coming\n-- back — skip and return NULL. Every real write re-stamps syncOrigin='google'.\nCREATE OR REPLACE FUNCTION public.gcal_apply_event_patch(\n p_tenant_id uuid,\n p_event_id text,\n p_etag text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_summary text,\n p_cancelled boolean\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_appt uuid;\n v_curr_etag text;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_apply_event_patch: tenant and event id are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT b.id, b.metadata->>'gcalEtag'\n INTO v_appt, v_curr_etag\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_appt IS NULL THEN RETURN NULL; END IF; -- not linked here\n IF p_etag IS NOT NULL AND p_etag = v_curr_etag THEN\n RETURN NULL; -- echo: nothing changed\n END IF;\n\n IF COALESCE(p_cancelled, false) THEN\n UPDATE appointments b\n SET status = 'cancelled',\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google', 'gcalEtag', p_etag),\n updated_at = now()\n WHERE b.id = v_appt;\n ELSE\n UPDATE appointments b\n SET starts_at = COALESCE(p_starts_at, b.starts_at),\n ends_at = COALESCE(p_ends_at, b.ends_at),\n notes = COALESCE(p_summary, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google',\n 'gcalEtag', p_etag,\n 'title', COALESCE(p_summary, b.metadata->>'title')),\n updated_at = now()\n WHERE b.id = v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\n-- gcal_stamp_outbound: after the edge function creates the Google event for an\n-- outbound push, it stamps the fresh event id/etag back onto the appointment.\n-- Bookkeeping only — must not re-fire §2's trigger, hence the GUC. Does NOT set\n-- metadata.syncOrigin (the booking's provenance is still the app/site).\nCREATE OR REPLACE FUNCTION public.gcal_stamp_outbound(\n p_tenant_id uuid,\n p_booking_id uuid,\n p_event_id text,\n p_etag text DEFAULT NULL,\n p_calendar_id text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_booking_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_stamp_outbound: tenant, booking and event id are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n UPDATE appointments b\n SET metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalSyncedAt', now())\n || CASE WHEN p_calendar_id IS NULL THEN '{}'::jsonb\n ELSE jsonb_build_object('gcalCalendarId', p_calendar_id) END,\n updated_at = now()\n WHERE b.id = p_booking_id AND b.tenant_id = p_tenant_id\n RETURNING b.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- gcal_unlink_channel: forget the incremental cursor + Google watch bookkeeping\n-- for a channel (used on disconnect / re-watch). Leaves the mapping row in place.\nCREATE OR REPLACE FUNCTION public.gcal_unlink_channel(\n p_channel_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n UPDATE plg_calendar_channels c\n SET sync_token = NULL,\n channel_id = NULL,\n resource_id = NULL,\n channel_expires_at = NULL,\n updated_at = now()\n WHERE c.id = p_channel_id\n RETURNING c.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- Lock the inbound writers to service_role only.\nDO $$\nDECLARE fn text;\nBEGIN\n FOR fn IN SELECT unnest(ARRAY[\n 'public.gcal_import_event(uuid, uuid, text, text, text, timestamptz, timestamptz, boolean, text)',\n 'public.gcal_apply_event_patch(uuid, text, text, timestamptz, timestamptz, text, boolean)',\n 'public.gcal_stamp_outbound(uuid, uuid, text, text, text)',\n 'public.gcal_unlink_channel(uuid)'\n ])\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION %s FROM public, anon, authenticated', fn);\n EXECUTE format('GRANT EXECUTE ON FUNCTION %s TO service_role', fn);\n END LOOP;\nEND $$;\n\n-- ===========================================================================\n-- §5 — get_available_slots: imported Google blocks must remove availability.\n-- CREATE OR REPLACE keeping the EXACT signature (anon + admin both call it, and\n-- it is graded on the same shape as plugin-agenda/src/migrations/001_public_booking.sql).\n--\n-- Conceptual diff vs 001 — ONE condition in the overlap NOT EXISTS:\n-- before: AND b.assignee_id = c.assignee_id\n-- after: AND (b.assignee_id = c.assignee_id\n-- OR (b.assignee_id IS NULL AND b.kind = 'block'))\n-- Rationale: a tenant-wide BLOCK imported from Google (target_kind NULL →\n-- assignee_id IS NULL, kind 'block', see §4) must busy-out the slot for EVERY\n-- professional. Restricted to kind='block' so an unassigned admin appointment\n-- keeps the 001 behaviour (blocks nobody). Per-assignee rows keep matching on\n-- assignee_id.\n-- Everything else is byte-identical to 001: the status filter already covers\n-- \"any non-cancelled kind\" (no_show also excluded), and the p_assignee_id-NULL\n-- fan-out across staff via day_schedules is preserved untouched.\n-- ===========================================================================\nCREATE OR REPLACE FUNCTION public.get_available_slots(\n p_tenant_id uuid,\n p_date date,\n p_duration_minutes integer,\n p_assignee_id uuid DEFAULT NULL,\n p_slot_interval integer DEFAULT 30\n) RETURNS TABLE (slot_start timestamptz, slot_end timestamptz)\nLANGUAGE plpgsql STABLE SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_tz text;\nBEGIN\n -- tight validation: this function is anon-callable\n IF p_duration_minutes IS NULL OR p_duration_minutes NOT BETWEEN 5 AND 480 THEN\n RAISE EXCEPTION 'invalid duration';\n END IF;\n IF p_slot_interval IS NULL OR p_slot_interval NOT BETWEEN 5 AND 240 THEN\n RAISE EXCEPTION 'invalid interval';\n END IF;\n IF p_date IS NULL OR p_date < current_date OR p_date > current_date + 90 THEN\n RETURN;\n END IF;\n\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RETURN; END IF; -- unknown tenant → empty, not an error\n\n RETURN QUERY\n WITH day_schedules AS (\n SELECT sc.assignee_id, sc.starts_at AS win_start, sc.ends_at AS win_end\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND (\n sc.specific_date = p_date\n OR (sc.specific_date IS NULL AND sc.day_of_week = EXTRACT(dow FROM p_date)::smallint)\n )\n ),\n candidate AS (\n SELECT\n ds.assignee_id,\n gs AS s_start,\n gs + make_interval(mins => p_duration_minutes) AS s_end\n FROM day_schedules ds\n CROSS JOIN LATERAL generate_series(\n (p_date + ds.win_start) AT TIME ZONE v_tz,\n ((p_date + ds.win_end) AT TIME ZONE v_tz) - make_interval(mins => p_duration_minutes),\n make_interval(mins => p_slot_interval)\n ) AS gs\n )\n SELECT DISTINCT c.s_start, c.s_end\n FROM candidate c\n WHERE NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n -- SMART SYNC: match this professional's own bookings OR any tenant-wide\n -- BLOCK (assignee_id IS NULL AND kind='block', e.g. imported from Google\n -- with a whole-tenant channel) — the latter busies the slot for every\n -- professional. Assignee-less rows of other kinds (an unassigned admin\n -- appointment) keep the 001 behaviour and do not block anyone.\n AND (b.assignee_id = c.assignee_id\n OR (b.assignee_id IS NULL AND b.kind = 'block'))\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < c.s_end\n AND COALESCE(b.ends_at, b.starts_at) > c.s_start\n )\n ORDER BY 1;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer) FROM public;\nGRANT EXECUTE ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer)\n TO anon, authenticated, service_role;\n\n-- ===========================================================================\n-- §6 — Inbound schedule (optional) — per-channel incremental pull.\n-- Supersedes the single-calendar template in 001. Enable once per project after\n-- setting app.gcal_sync_url / app.gcal_service_key (see 001 header). The edge\n-- function fans out over active channels, using each channel's sync_token cursor:\n--\n-- SELECT cron.schedule('gcal-pull', '*/10 * * * *', $CRON$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object(\n-- 'Content-Type','application/json',\n-- 'Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events'))\n-- $CRON$);\n--\n-- Or drive one row per channel from SQL (tighter scoping / per-channel cadence):\n--\n-- SELECT cron.schedule('gcal-pull-'||ch.id::text, '*/10 * * * *', format($CRON$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object(\n-- 'Content-Type','application/json',\n-- 'Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events','channelId',%L))\n-- $CRON$, ch.id))\n-- FROM public.plg_calendar_channels ch\n-- WHERE ch.is_active AND ch.direction IN ('inbound','bidirectional');\n-- ===========================================================================\n`\n\nexport const MIGRATION_003_PLG_RENAME = `-- ---------------------------------------------------------------------------\n-- 003_plg_rename.sql — standardize the Google Calendar connector objects onto\n-- the platform \\`plg_<plugin>_\\` prefix (DATA-MODEL.md Ring 1).\n--\n-- calendar_integrations → plg_calendar_integrations\n-- calendar_channels → plg_calendar_channels\n-- calendar_sync_log → plg_calendar_sync_log\n--\n-- Legacy-pool remediation ONLY: 001/002 now create the prefixed names directly,\n-- so fresh installs never reach a rename branch. Fully idempotent and guarded —\n-- every RENAME fires only when the old object exists and the new one does not,\n-- so re-running (or running on an already-prefixed pool) is a no-op.\n--\n-- A table RENAME preserves its data, RLS state, policies, grants, indexes,\n-- constraints and triggers (they follow the table), so §1 only renames the\n-- table + the explicitly-named indexes. §2 then re-points the SECURITY DEFINER\n-- gcal_* functions whose bodies hard-code the old table names.\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — Guarded table + index renames.\n-- ===========================================================================\nDO $$\nBEGIN\n IF to_regclass('public.calendar_integrations') IS NOT NULL\n AND to_regclass('public.plg_calendar_integrations') IS NULL THEN\n ALTER TABLE public.calendar_integrations RENAME TO plg_calendar_integrations;\n END IF;\n\n IF to_regclass('public.calendar_channels') IS NOT NULL\n AND to_regclass('public.plg_calendar_channels') IS NULL THEN\n ALTER TABLE public.calendar_channels RENAME TO plg_calendar_channels;\n END IF;\n\n IF to_regclass('public.calendar_sync_log') IS NOT NULL\n AND to_regclass('public.plg_calendar_sync_log') IS NULL THEN\n ALTER TABLE public.calendar_sync_log RENAME TO plg_calendar_sync_log;\n END IF;\n\n -- Named indexes do not follow a table rename automatically.\n IF to_regclass('public.idx_calendar_integrations_tenant') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_integrations_tenant') IS NULL THEN\n ALTER INDEX public.idx_calendar_integrations_tenant RENAME TO idx_plg_calendar_integrations_tenant;\n END IF;\n\n IF to_regclass('public.idx_calendar_channels_tenant') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_channels_tenant') IS NULL THEN\n ALTER INDEX public.idx_calendar_channels_tenant RENAME TO idx_plg_calendar_channels_tenant;\n END IF;\n\n IF to_regclass('public.idx_calendar_channels_integration') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_channels_integration') IS NULL THEN\n ALTER INDEX public.idx_calendar_channels_integration RENAME TO idx_plg_calendar_channels_integration;\n END IF;\nEND $$;\n\n-- ===========================================================================\n-- §2 — Re-point the inbound SECURITY DEFINER writers at the prefixed names.\n-- These bodies are byte-identical to 002_smart_sync.sql except the calendar_*\n-- table references, which now read plg_calendar_*. gcal_apply_event_patch and\n-- gcal_stamp_outbound only touch public.appointments (unaffected by the rename)\n-- and are re-asserted here for completeness so all four writers stay in step.\n-- ===========================================================================\n\nCREATE OR REPLACE FUNCTION public.gcal_import_event(\n p_tenant_id uuid,\n p_channel_id uuid,\n p_event_id text,\n p_etag text,\n p_summary text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_all_day boolean,\n p_description text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_ch record;\n v_kind text;\n v_assignee uuid;\n v_location uuid;\n v_ends timestamptz;\n v_meta jsonb;\n v_existing uuid;\n v_appt uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL OR p_starts_at IS NULL THEN\n RAISE EXCEPTION 'gcal_import_event: tenant, event id and start are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT c.import_mode, c.target_kind, c.target_id\n INTO v_ch\n FROM plg_calendar_channels c\n WHERE c.id = p_channel_id AND c.tenant_id = p_tenant_id;\n IF NOT FOUND THEN RAISE EXCEPTION 'gcal_import_event: unknown channel for tenant'; END IF;\n\n v_kind := CASE WHEN v_ch.import_mode = 'appointment' THEN 'appointment' ELSE 'block' END;\n v_assignee := CASE WHEN v_ch.target_kind = 'assignee' THEN v_ch.target_id ELSE NULL END;\n v_location := CASE WHEN v_ch.target_kind = 'location' THEN v_ch.target_id ELSE NULL END;\n\n v_ends := COALESCE(\n p_ends_at,\n CASE WHEN COALESCE(p_all_day, false) THEN p_starts_at + interval '1 day' ELSE p_starts_at END\n );\n\n v_meta := jsonb_build_object(\n 'syncOrigin', 'google',\n 'googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalChannelId', p_channel_id::text,\n 'allDay', COALESCE(p_all_day, false),\n 'title', p_summary,\n 'source', 'google_import'\n );\n\n SELECT b.id INTO v_existing\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_existing IS NOT NULL THEN\n UPDATE appointments b\n SET kind = v_kind,\n assignee_id = v_assignee,\n location_id = v_location,\n starts_at = p_starts_at,\n ends_at = v_ends,\n status = 'scheduled',\n notes = COALESCE(p_description, p_summary),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || v_meta,\n updated_at = now()\n WHERE b.id = v_existing\n RETURNING b.id INTO v_appt;\n ELSE\n INSERT INTO appointments (tenant_id, kind, assignee_id, location_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, v_kind, v_assignee, v_location,\n p_starts_at, v_ends, 'scheduled', COALESCE(p_description, p_summary), v_meta)\n RETURNING id INTO v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_apply_event_patch(\n p_tenant_id uuid,\n p_event_id text,\n p_etag text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_summary text,\n p_cancelled boolean\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_appt uuid;\n v_curr_etag text;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_apply_event_patch: tenant and event id are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT b.id, b.metadata->>'gcalEtag'\n INTO v_appt, v_curr_etag\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_appt IS NULL THEN RETURN NULL; END IF;\n IF p_etag IS NOT NULL AND p_etag = v_curr_etag THEN\n RETURN NULL;\n END IF;\n\n IF COALESCE(p_cancelled, false) THEN\n UPDATE appointments b\n SET status = 'cancelled',\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google', 'gcalEtag', p_etag),\n updated_at = now()\n WHERE b.id = v_appt;\n ELSE\n UPDATE appointments b\n SET starts_at = COALESCE(p_starts_at, b.starts_at),\n ends_at = COALESCE(p_ends_at, b.ends_at),\n notes = COALESCE(p_summary, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google',\n 'gcalEtag', p_etag,\n 'title', COALESCE(p_summary, b.metadata->>'title')),\n updated_at = now()\n WHERE b.id = v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_stamp_outbound(\n p_tenant_id uuid,\n p_booking_id uuid,\n p_event_id text,\n p_etag text DEFAULT NULL,\n p_calendar_id text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_booking_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_stamp_outbound: tenant, booking and event id are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n UPDATE appointments b\n SET metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalSyncedAt', now())\n || CASE WHEN p_calendar_id IS NULL THEN '{}'::jsonb\n ELSE jsonb_build_object('gcalCalendarId', p_calendar_id) END,\n updated_at = now()\n WHERE b.id = p_booking_id AND b.tenant_id = p_tenant_id\n RETURNING b.id INTO v_id;\n RETURN v_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_unlink_channel(\n p_channel_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n UPDATE plg_calendar_channels c\n SET sync_token = NULL,\n channel_id = NULL,\n resource_id = NULL,\n channel_expires_at = NULL,\n updated_at = now()\n WHERE c.id = p_channel_id\n RETURNING c.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- Re-assert the service_role-only lock (idempotent; matches 002 §4).\nDO $$\nDECLARE fn text;\nBEGIN\n FOR fn IN SELECT unnest(ARRAY[\n 'public.gcal_import_event(uuid, uuid, text, text, text, timestamptz, timestamptz, boolean, text)',\n 'public.gcal_apply_event_patch(uuid, text, text, timestamptz, timestamptz, text, boolean)',\n 'public.gcal_stamp_outbound(uuid, uuid, text, text, text)',\n 'public.gcal_unlink_channel(uuid)'\n ])\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION %s FROM public, anon, authenticated', fn);\n EXECUTE format('GRANT EXECUTE ON FUNCTION %s TO service_role', fn);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_004_DROP_OAUTH_TOKENS = `-- ============================================================================\n-- Google Calendar 004: the credential leaves the tenant database, and the\n-- outbound trigger stops being able to break a booking write.\n--\n-- §1 credential drop oauth_refresh_token + oauth_access_token\n-- §2 outbound anti-loop, safe no-op, delete context, correlation id\n-- §3 realtime publish public.appointments so the calendar repaints\n--\n-- Additive and idempotent: no table is created, no policy is rewritten, and the\n-- tenant RLS from 001 already covers everything touched here.\n-- ============================================================================\n\n-- §1 ── credential ───────────────────────────────────────────────────────────\n-- THE EXPOSURE THIS CLOSES: 001 stored \\`oauth_refresh_token text\\` and\n-- \\`oauth_access_token text\\` on public.plg_calendar_integrations. That table is\n-- read from the browser with the publishable key under tenant RLS — and the\n-- connector read it with \\`select('*')\\` — so a Google refresh token was readable\n-- by ANY authenticated member of the tenant, reception included. A refresh token\n-- is not a session: it is durable access to the owner's entire calendar, mail-\n-- adjacent metadata and every calendar shared with them. And a pool is one\n-- Supabase project serving N tenants, so anything running there with\n-- service_role read every clinic's Google grant at once.\n--\n-- This is the third connector to make the same move, and the worst of the three.\n-- RankLayer had nothing to replace its key with (it pushes IN and authenticates\n-- against the platform); PlugBank's credential is meant to move to the platform\n-- (FAY-1360 — as of 2026-08-12 its api_token is still a plaintext pool column).\n-- Google Calendar is PlugBank's case: the grant still has to exist, it just must\n-- not exist HERE. The destination is the platform's ConnectorConnection store\n-- (encrypted; exists, unused), with the sync function redeeming per call — that\n-- is FAY-1359, and it has NOT happened.\n--\n-- ⚠ REPO AHEAD OF POOL (verified 2026-08-12, FAY-1379): this file has NOT been\n-- applied to the live salon pool. plg_calendar_integrations there still carries\n-- both token columns with a real clinic's grant, and the DEPLOYED\n-- google-calendar-sync (v16) still reads and writes them. Applying this drop\n-- before FAY-1359's ordered rollout (function reads both homes → data migrated\n-- → function reads only the new home → drop) severs the clinic's sync. Do not\n-- \\`db apply\\` this to a pool outside that sequence.\n--\n-- \\`token_expires_at\\` deliberately stays. It is a timestamp, not a credential,\n-- and it is the only non-secret signal that a grant exists — which is what the\n-- browser needs in order to draw a connected/disconnected badge without ever\n-- being handed the thing it is reporting on. See ../credentials.ts.\n--\n-- ROTATE any token a pool already stored. Nothing is live on this connector yet,\n-- but DROP COLUMN is a catalog change: the old values stay in the heap until the\n-- next table rewrite, so a grant that ever reached a pool must be revoked at\n-- Google rather than assumed gone.\n\nDO $$\nBEGIN\n IF to_regclass('public.plg_calendar_integrations') IS NOT NULL THEN\n ALTER TABLE public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n END IF;\n -- Pools converted before 003 renamed the tables carry the legacy name.\n IF to_regclass('public.calendar_integrations') IS NOT NULL THEN\n ALTER TABLE public.calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE public.calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n END IF;\nEND $$;\n\n-- §2 ── outbound trigger ─────────────────────────────────────────────────────\n-- Three defects in 001's fn_gcal_push_booking, in order of how badly they hurt:\n--\n-- 1. NO ANTI-LOOP. An inbound Google event is written to public.appointments by\n-- the sync function, which fires this trigger, which pushes the same change\n-- back to Google, which changes the event, which the next pull reads as new.\n-- The symptom a customer reports is an appointment that will not stop moving.\n-- The sync function sets \\`app.booking_origin = 'google'\\` for the duration of\n-- its transaction; a write carrying that marker is never echoed back.\n--\n-- 2. A MISSING PREREQUISITE COULD BREAK THE BOOKING. 001 returned early on an\n-- empty URL but not on an empty key, so a half-configured pool sent an\n-- unauthenticated pg_net request; and any error raised in here aborts the\n-- INSERT that fired it. An integration that is not set up must degrade to\n-- \"Google is not updated\", never to \"the appointment could not be saved\".\n-- Every exit path below returns the row.\n--\n-- 3. A DELETE ARRIVED WITH NOTHING TO DELETE. AFTER DELETE can still read OLD,\n-- but pg_net delivers asynchronously — by the time the function runs, the row\n-- is gone and it cannot look up which Google event to remove. The linked ids\n-- now travel in the payload.\n--\n-- The early returns are not enough on their own: on a pool where the settings\n-- are present but pg_net is not installed, the PERFORM itself raises \\`schema\n-- \"net\" does not exist\\` and takes the INSERT down with it. So the delivery is\n-- wrapped too. Swallowing a delivery error is safe here because pg_net only\n-- ENQUEUES — anything it could tell us is already visible as \"nothing has\n-- synced\" in plg_calendar_sync_log and in the connector's derived health.\n--\n-- The Supabase service-role key still reaches this trigger through the\n-- \\`app.gcal_service_key\\` database setting that 001 introduced. That is a lesser\n-- exposure than the one closed in §1 (a GUC is not reachable through PostgREST,\n-- so no browser can read it) but it is still a pool-wide credential in the\n-- database, and it is NOT fixed here. FAY-1372 shipped the RLS half (a\n-- tenant-scoped claim narrows user_tenant_ids); nothing mints such a token for\n-- this trigger yet, and the function still runs on service_role (FAY-1378).\n-- Left as a named debt rather than moved to a third hiding place.\n\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public, extensions, net\nAS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- (1) Inbound Google writes mark themselves. Never echo them back.\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n -- (2) Not configured is not an error. Diagnostics report the connector as\n -- incomplete; the appointment is saved either way.\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n BEGIN\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object(\n 'Content-Type', 'application/json',\n 'Authorization', 'Bearer ' || key\n ),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n -- (3) Carried so a delete can still be honoured after the row is gone.\n 'googleEventId', rec.metadata->>'googleCalendarEventId',\n 'calendarId', rec.metadata->>'gcalCalendarId',\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n EXCEPTION WHEN OTHERS THEN\n -- Missing pg_net, a bad URL, a full queue: the appointment is still saved.\n RAISE WARNING 'gcal push skipped for booking %: %', rec.id, SQLERRM;\n END;\n\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- §3 ── realtime ─────────────────────────────────────────────────────────────\n-- The calendar screen subscribes to public.appointments so a booking written by\n-- the sync function repaints the grid the manager is looking at, instead of\n-- waiting for them to reload the tab. Additive and guarded: a pool without the\n-- supabase_realtime publication is left alone, and re-running adds nothing.\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM pg_publication WHERE pubname = 'supabase_realtime')\n AND NOT EXISTS (\n SELECT 1 FROM pg_publication_tables\n WHERE pubname = 'supabase_realtime' AND schemaname = 'public' AND tablename = 'appointments'\n )\n THEN\n ALTER PUBLICATION supabase_realtime ADD TABLE public.appointments;\n END IF;\nEND $$;\n`\n\nexport const MIGRATION_005_OUTBOUND_VAULT_DELIVERY = `-- ============================================================================\n-- Google Calendar 005: the outbound credential moves to Vault, and stops being\n-- the service-role key. The Authorization header stays.\n--\n-- §1 trigger fn_gcal_push_booking reads Vault, falls back to the old GUCs\n-- §2 cleanup clear app.gcal_service_key ONLY where Vault already covers it\n--\n-- Additive and idempotent: a CREATE OR REPLACE plus a guarded, conditional\n-- catalog cleanup.\n--\n-- WRITTEN AGAINST THE DEPLOYED POOL, NOT AGAINST THIS FOLDER. The repo and\n-- cluster-salon-br-01 (gphxclpkbtbucoqclbco) had drifted: \\`004\\` here still reads\n-- \\`app.gcal_service_key\\`, while the pool has been on Vault since 2026-07-28 and\n-- the deployed function is four features ahead of \\`functions/\\`. Everything below\n-- was checked against the live database and the live function source, because\n-- the previous attempt at this file was derived from the repo alone and would\n-- have broken a real clinic. See FAY-1379 for the drift itself.\n-- ============================================================================\n\n-- §1 ── the credential ───────────────────────────────────────────────────────\n-- THE EXPOSURE THIS CLOSES, precisely: \\`001\\` told operators to run\n-- ALTER DATABASE postgres SET app.gcal_service_key = '<service-role-key>';\n-- and every version of this trigger in the repo since (\\`001\\`, \\`002 §2\\`,\n-- \\`004 §2\\`) reads it back with current_setting(). A pool is ONE Supabase project\n-- serving N tenants and service_role bypasses RLS by definition, so that setting\n-- is unrestricted read/write over every tenant in the cluster, in plain text in\n-- pg_db_role_setting and in every pg_dump taken since.\n--\n-- It is closed by making the credential BOTH narrow and encrypted, not by\n-- removing it: the header is the only thing authorising the push. The deployed\n-- function checks it (\\`isServiceRequest\\` compares the bearer against\n-- GCAL_OUTBOUND_SECRET, then against the service-role key) and \\`push_event\\` is a\n-- service action with no user path, so a request with no Authorization header is\n-- rejected with \\`400 Unknown action: push_event\\`. Because pg_net is\n-- fire-and-forget that rejection is INVISIBLE — the clinic would simply stop\n-- appearing in Google Calendar. Removing the header is therefore not a security\n-- improvement, it is a silent outage. It was tried and reverted.\n--\n-- So: \\`gcal_outbound_secret\\` in Vault. Encrypted at rest, outside pg_dump's\n-- plaintext, readable only by a definer function like this one, and — the part\n-- that matters — it authorises exactly one thing, calling this connector's edge\n-- function. Losing it does not hand anyone another tenant's data. This is the\n-- shape the pool has been running since 2026-07-28; \\`005\\` is the repo catching\n-- up, so a pool provisioned fresh from this folder is born with it instead of\n-- being told to paste a service-role key into a database setting.\n--\n-- THE FALLBACK IS DELIBERATE. A pool that followed \\`001\\` and has no Vault secret\n-- keeps working off the old GUCs, loudly. The alternative — read Vault only —\n-- silently disarms the push on exactly the pools that did what the docs told\n-- them to, which is the failure this file exists to avoid.\n--\n-- WHAT THIS DOES NOT FIX: the edge function still builds its Supabase client\n-- with SUPABASE_SERVICE_ROLE_KEY, so the FUNCTION still reads every tenant in\n-- the pool. That is not reachable from SQL and does not close here: it closes\n-- when the platform mints a short-lived tenant-scoped token (FAY-1353) that\n-- packages/db/migrations/028_tenant_scoped_token.sql already teaches every\n-- policy to honour through user_tenant_ids(). See docs/platform/DECISIONS.md,\n-- 2026-08-11 — \"a connector's privilege comes from its token\".\n--\n-- ROTATE the service-role key of any pool that ever ran \\`001\\`'s setup line: it\n-- was plain text at rest and in every backup taken since, so §2 clearing it is\n-- not the same as it never having been there.\n\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public, extensions, net, vault\nAS $$\nDECLARE\n url text;\n key text;\n legacy boolean := false;\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- Unchanged from 004: inbound Google writes mark themselves, and a write\n -- carrying that marker is never echoed back.\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n -- Vault first. Wrapped because a pool without the vault extension must\n -- degrade to the fallback, not abort the booking write.\n BEGIN\n SELECT decrypted_secret INTO url\n FROM vault.decrypted_secrets WHERE name = 'gcal_sync_url'\n ORDER BY created_at DESC LIMIT 1;\n SELECT decrypted_secret INTO key\n FROM vault.decrypted_secrets WHERE name = 'gcal_outbound_secret'\n ORDER BY created_at DESC LIMIT 1;\n EXCEPTION WHEN OTHERS THEN\n url := NULL;\n key := NULL;\n END;\n\n -- Legacy pools provisioned per 001's header keep working, and say so.\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n url := COALESCE(NULLIF(url, ''), current_setting('app.gcal_sync_url', true));\n key := COALESCE(NULLIF(key, ''), current_setting('app.gcal_service_key', true));\n legacy := NULLIF(key, '') IS NOT NULL;\n END IF;\n\n -- Not configured is not an error: an unconfigured pool degrades to \"Google is\n -- not updated\", never to \"the appointment could not be saved\".\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n IF legacy THEN\n RAISE WARNING 'gcal outbound is still using app.gcal_service_key; move it to the vault secret gcal_outbound_secret and rotate the service-role key';\n END IF;\n\n BEGIN\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object(\n 'Content-Type', 'application/json',\n -- REQUIRED. The deployed function authorises push_event on this header\n -- alone; without it every push 400s, silently, forever.\n 'Authorization', 'Bearer ' || key\n ),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n -- Carried so a delete can still be honoured after the row is gone.\n 'googleEventId', rec.metadata->>'googleCalendarEventId',\n 'calendarId', rec.metadata->>'gcalCalendarId',\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n EXCEPTION WHEN OTHERS THEN\n -- Missing pg_net, a bad URL, a full queue: the appointment is still saved.\n -- The deployed trigger lacks this wrapper; 004 added it here after a pool\n -- with the settings present but the extension missing took an INSERT down.\n RAISE WARNING 'gcal push skipped for booking %: %', rec.id, SQLERRM;\n END;\n\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- §2 ── cleanup ──────────────────────────────────────────────────────────────\n-- Redefining the function stops the key being PREFERRED; it does not stop it\n-- being STORED. Settings live in pg_db_role_setting per (database, role), so the\n-- sweep is driven off the catalog rather than off the one ALTER DATABASE form\n-- \\`001\\` happened to show.\n--\n-- CONDITIONAL ON PURPOSE: the setting is cleared only where Vault already\n-- supplies \\`gcal_outbound_secret\\`, i.e. only where §1 provably never needs the\n-- fallback. Anywhere else it is left in place and reported, because clearing it\n-- there would disarm the push with no error anyone can see. On the live pool\n-- this loop finds nothing — the setting is not present on any role or database —\n-- and that is the expected result, not a failure.\nDO $$\nDECLARE\n r record;\n has_vault boolean := false;\nBEGIN\n BEGIN\n SELECT EXISTS (\n SELECT 1 FROM vault.decrypted_secrets\n WHERE name = 'gcal_outbound_secret' AND NULLIF(decrypted_secret, '') IS NOT NULL\n ) INTO has_vault;\n EXCEPTION WHEN OTHERS THEN\n has_vault := false;\n END;\n\n FOR r IN\n SELECT d.datname, a.rolname\n FROM pg_db_role_setting s\n LEFT JOIN pg_database d ON d.oid = s.setdatabase\n LEFT JOIN pg_roles a ON a.oid = s.setrole\n WHERE EXISTS (\n SELECT 1 FROM unnest(s.setconfig) AS c WHERE c LIKE 'app.gcal_service_key=%'\n )\n LOOP\n IF NOT has_vault THEN\n RAISE WARNING 'app.gcal_service_key is still set (database %, role %) and is the ONLY outbound credential — create the vault secret gcal_outbound_secret first, then re-run this migration',\n r.datname, r.rolname;\n CONTINUE;\n END IF;\n BEGIN\n IF r.rolname IS NULL THEN\n EXECUTE format('ALTER DATABASE %I RESET app.gcal_service_key', r.datname);\n ELSIF r.datname IS NULL THEN\n EXECUTE format('ALTER ROLE %I RESET app.gcal_service_key', r.rolname);\n ELSE\n EXECUTE format('ALTER ROLE %I IN DATABASE %I RESET app.gcal_service_key', r.rolname, r.datname);\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RAISE WARNING 'could not clear app.gcal_service_key (database %, role %): % — clear it by hand, and rotate the key either way',\n r.datname, r.rolname, SQLERRM;\n END;\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX = `-- ---------------------------------------------------------------------------\n-- Google Calendar WEBHOOK INTAKE — delivery ledger + automation outbox\n-- ---------------------------------------------------------------------------\n-- RECONSTRUCTED FROM THE LIVE SCHEMA on 2026-08-12 (FAY-1379). These objects\n-- existed in pool gphxclpkbtbucoqclbco and in NO migration in any repo: they\n-- were applied by hand alongside the google-calendar-webhook deployment. A pool\n-- provisioned from this repo could not run that function — the SELECT of\n-- plg_calendar_channels.webhook_token_hash failed before any gate ran, and both\n-- INSERT targets were missing. This file closes that hole.\n--\n-- Written to be applied to a pool that ALREADY has them: every statement is\n-- IF NOT EXISTS / DROP-then-CREATE, and re-running it must be a no-op.\n--\n-- §1 plg_calendar_channels — the three webhook columns\n-- §2 plg_calendar_webhook_deliveries — one row per Google notification\n-- §3 plg_calendar_automation_outbox — domain events for the automations lane\n--\n-- Read by: functions/google-calendar-webhook/index.ts (§1 gate, §2 idempotency,\n-- §3 emit) and functions/google-calendar-sync/index.ts (§1 watch bookkeeping,\n-- §3 emit on inbound import/patch).\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — Watch-channel authentication state on plg_calendar_channels.\n-- Added by ALTER in the pool (they sit after created_at/updated_at), so they\n-- are added the same way here rather than folded into 002's CREATE TABLE —\n-- 002 has already run everywhere and its checksum must not move.\n--\n-- webhook_token_hash: SHA-256 of the token handed to Google at watch_start. The\n-- token itself is never stored, so a dump of this table does not let anyone\n-- forge a notification. The webhook re-hashes what arrives and compares in\n-- constant time.\n-- last_webhook_message_number: high-water mark of Google's monotonic per-channel\n-- counter — the replay guard. bigint because it outgrows int4.\n-- ===========================================================================\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS webhook_token_hash text;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_message_number bigint;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_at timestamptz;\n\n-- ===========================================================================\n-- §2 — plg_calendar_webhook_deliveries: one row per accepted notification.\n--\n-- The row IS the idempotency mechanism, not a log of one: the webhook inserts\n-- before doing any work and reads 23505 as \"already handled\", returning 204.\n-- Hence two unique keys, both present in the pool and both reproduced —\n-- (channel_ref, message_number) is the constraint the FK cascade protects, and\n-- (google_channel_id, message_number) catches a replay arriving after the\n-- channel row was recreated with the same Google channel id.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_webhook_deliveries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n channel_ref uuid NOT NULL REFERENCES public.plg_calendar_channels(id) ON DELETE CASCADE,\n google_channel_id text NOT NULL,\n resource_id text,\n message_number bigint NOT NULL,\n resource_state text,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n error text,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n created_at timestamptz DEFAULT now(),\n UNIQUE (channel_ref, message_number)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_webhook_delivery_message\n ON public.plg_calendar_webhook_deliveries (google_channel_id, message_number);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_tenant_created\n ON public.plg_calendar_webhook_deliveries (tenant_id, created_at DESC);\n\n-- Two partial indexes over the same predicate on different sort columns. Both\n-- are in the pool (evidence of two overlapping hand-applied scripts) and both\n-- are reproduced so this file matches the live schema exactly; consolidating\n-- them is a separate change with its own reasoning.\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_pending\n ON public.plg_calendar_webhook_deliveries (status, received_at)\n WHERE status IN ('pending','failed');\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_pending\n ON public.plg_calendar_webhook_deliveries (status, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_webhook_deliveries ENABLE ROW LEVEL SECURITY;\n\n-- Read-only for the app. Every write comes from the webhook function running as\n-- service_role, which bypasses RLS — there is no authenticated INSERT/UPDATE\n-- grant, so a browser cannot forge or retire a delivery.\nGRANT SELECT ON public.plg_calendar_webhook_deliveries TO authenticated;\nGRANT ALL ON public.plg_calendar_webhook_deliveries TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries;\nCREATE POLICY plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\n-- ===========================================================================\n-- §3 — plg_calendar_automation_outbox: calendar facts, for the automations lane.\n--\n-- Transactional outbox: the sync/webhook functions record WHAT happened and\n-- return; a consumer drains it. idempotency_key is unique per tenant so a\n-- replayed Google delivery or a re-run pull upserts onto the same row instead\n-- of firing an automation twice — that key is what the functions pass as\n-- onConflict, so it is load-bearing and not merely a hygiene constraint.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_automation_outbox (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n source text NOT NULL DEFAULT 'google_calendar',\n event_type text NOT NULL,\n aggregate_type text NOT NULL,\n aggregate_id text,\n idempotency_key text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n attempts integer NOT NULL DEFAULT 0,\n last_error text,\n occurred_at timestamptz NOT NULL DEFAULT now(),\n -- available_at is the retry clock: a failed row is re-eligible once it passes.\n available_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n error text,\n created_at timestamptz DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\n-- Redundant with the UNIQUE constraint's own index, and present in the pool for\n-- the same overlapping-scripts reason as §2. Reproduced, not tidied.\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_automation_outbox_idempotency\n ON public.plg_calendar_automation_outbox (tenant_id, idempotency_key);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_pending\n ON public.plg_calendar_automation_outbox (status, available_at)\n WHERE status IN ('pending','failed');\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_outbox_pending\n ON public.plg_calendar_automation_outbox (status, available_at, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_automation_outbox ENABLE ROW LEVEL SECURITY;\n\nGRANT SELECT ON public.plg_calendar_automation_outbox TO authenticated;\nGRANT ALL ON public.plg_calendar_automation_outbox TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox;\nCREATE POLICY plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n`\n\nexport const MIGRATION_007_CREDENTIAL_FREE_INSTALL = `-- ---------------------------------------------------------------------------\n-- Google Calendar — a credential-free install, from zero\n-- ---------------------------------------------------------------------------\n-- FAY-1359/1360. On 2026-08-12 the five plg_calendar_* tables were DROPPED from\n-- the beauty pool (gphxclpkbtbucoqclbco) together with both edge functions,\n-- because plg_calendar_integrations held the tenant's Google refresh token in an\n-- open column. A pool is one database for N clinics, so that column was one\n-- backup, one dump or one service_role key away from being every clinic's\n-- calendar.\n--\n-- This file is what a pool runs to have the connector back. It is deliberately\n-- SELF-CONTAINED rather than \"001 through 006 again\":\n--\n-- * 001 CREATEs the credential columns and 004 drops them. A pool restored by\n-- replaying the chain therefore holds a refresh-token column for the length\n-- of that replay, and holds it forever if the replay stops early — which is\n-- exactly what a half-applied ledger does. There is no ordering of those\n-- files in which the column never exists; there is this file, in which it\n-- never exists.\n-- * The beauty pool's ledger and its schema had already parted company (it\n-- recorded shop/0006b while tables up to 0043 were applied by hand). A\n-- recovery that depends on the ledger being right is not a recovery.\n--\n-- Re-runnable, and a near no-op on a pool that ran 001–006: every statement is\n-- IF NOT EXISTS / DROP-then-CREATE, and §5 drops the credential columns if it\n-- finds them rather than assuming 004 ran.\n--\n-- §1 plg_calendar_integrations — per-tenant sync state. NO credential.\n-- §2 plg_calendar_channels — the de-para, incl. the webhook columns\n-- §3 plg_calendar_sync_log — run history\n-- §4 plg_calendar_webhook_deliveries + plg_calendar_automation_outbox\n-- §5 the gate: this schema must not be able to hold a Google grant\n--\n-- WHAT OWNS WHAT, after this file (FAY-1388):\n-- the PLATFORM owns the credential — which Google account, authorized by\n-- whom, and the refresh token, in the vault, reachable only by redemption;\n-- plg_connections owns \"is this connector on for this tenant\", written by the\n-- app when consent comes back;\n-- these tables own the SYNC STATE — which calendars map to what, how far the\n-- cursor got, what Google last told us. Nothing here is a secret, and\n-- nothing here can be traded for access to anyone's calendar.\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — plg_calendar_integrations: one row per tenant, sync state only.\n--\n-- Same shape as 001 MINUS oauth_refresh_token, oauth_access_token and\n-- token_expires_at. There is no column here to put a token in, which is the\n-- property this migration exists to establish — see §5, which enforces it.\n--\n-- No FK to plg_connections on purpose. That table is the connector framework's\n-- and this one is the calendar's; a FK would make the connector's row a\n-- prerequisite for reading a cursor, and the two planes are meant to be able to\n-- fail independently.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_integrations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n provider text NOT NULL DEFAULT 'google',\n calendar_id text NOT NULL DEFAULT 'primary',\n -- Incremental pull cursor + legacy single-calendar watch bookkeeping.\n sync_token text,\n channel_id text,\n channel_resource_id text,\n channel_expires_at timestamptz,\n active boolean NOT NULL DEFAULT true,\n last_sync_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, provider)\n);\nALTER TABLE public.plg_calendar_integrations ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_integrations_tenant\n ON public.plg_calendar_integrations(tenant_id);\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_integrations TO authenticated;\nGRANT ALL ON public.plg_calendar_integrations TO service_role;\n\n-- ===========================================================================\n-- §2 — plg_calendar_channels: the de-para, with 006's webhook columns folded in.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_channels (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n integration_id uuid NOT NULL REFERENCES public.plg_calendar_integrations(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL,\n google_calendar_id text NOT NULL,\n summary text,\n color text,\n direction text NOT NULL DEFAULT 'bidirectional'\n CHECK (direction IN ('inbound','outbound','bidirectional','off')),\n target_kind text CHECK (target_kind IN ('assignee','service','location')),\n target_id uuid,\n import_mode text NOT NULL DEFAULT 'block'\n CHECK (import_mode IN ('block','appointment')),\n sync_token text,\n channel_id text,\n resource_id text,\n channel_expires_at timestamptz,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (integration_id, google_calendar_id)\n);\n\n-- The webhook's authentication state. \\`webhook_token_hash\\` is a SHA-256 of the\n-- token handed to Google — the token itself is never stored, so reading this\n-- table does not let anyone forge a notification. Added by ALTER as well as in\n-- the CREATE above, for the pool that already has the table from 002.\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS webhook_token_hash text;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_message_number bigint;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_at timestamptz;\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_tenant\n ON public.plg_calendar_channels(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_integration\n ON public.plg_calendar_channels(integration_id);\n\nALTER TABLE public.plg_calendar_channels ENABLE ROW LEVEL SECURITY;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_channels TO authenticated;\nGRANT ALL ON public.plg_calendar_channels TO service_role;\n\nDROP TRIGGER IF EXISTS plg_calendar_channels_updated_at ON public.plg_calendar_channels;\nCREATE TRIGGER plg_calendar_channels_updated_at BEFORE UPDATE ON public.plg_calendar_channels\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\n-- ===========================================================================\n-- §3 — plg_calendar_sync_log: what already happened, per run.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_sync_log (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n direction text NOT NULL, -- inbound | outbound\n trigger text, -- on-write | scheduled | webhook | manual\n status text NOT NULL DEFAULT 'success', -- success | partial | error\n fetched integer NOT NULL DEFAULT 0,\n written integer NOT NULL DEFAULT 0,\n error text,\n correlation_id uuid,\n channel_id_ref uuid,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_calendar_sync_log ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_calendar_sync_log ADD COLUMN IF NOT EXISTS correlation_id uuid;\nALTER TABLE public.plg_calendar_sync_log ADD COLUMN IF NOT EXISTS channel_id_ref uuid;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_sync_log TO authenticated;\nGRANT ALL ON public.plg_calendar_sync_log TO service_role;\n\n-- RLS: tenant isolation for the three tables the app reads and writes.\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY[\n 'plg_calendar_integrations',\n 'plg_calendar_channels',\n 'plg_calendar_sync_log'\n ])\n LOOP\n IF NOT EXISTS (\n SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_rls'\n ) THEN\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR ALL TO authenticated '\n 'USING (tenant_id IN (SELECT public.user_tenant_ids())) '\n 'WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))',\n t||'_rls', t);\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_service'\n ) THEN\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR ALL TO service_role USING (true) WITH CHECK (true)',\n t||'_service', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- ===========================================================================\n-- §4 — Webhook intake: the delivery ledger and the automation outbox.\n--\n-- The delivery row IS the idempotency mechanism: the webhook inserts before\n-- doing any work and reads a 23505 as \"already handled\". Google retries hard,\n-- so this is what stops one notification becoming two appointments.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_webhook_deliveries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n channel_ref uuid NOT NULL REFERENCES public.plg_calendar_channels(id) ON DELETE CASCADE,\n google_channel_id text NOT NULL,\n resource_id text,\n message_number bigint NOT NULL,\n resource_state text,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n error text,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n created_at timestamptz DEFAULT now(),\n UNIQUE (channel_ref, message_number)\n);\n\n-- Catches a replay that arrives after the channel row was recreated with the\n-- same Google channel id — the FK-scoped constraint above cannot see that.\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_webhook_delivery_message\n ON public.plg_calendar_webhook_deliveries (google_channel_id, message_number);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_tenant_created\n ON public.plg_calendar_webhook_deliveries (tenant_id, created_at DESC);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_pending\n ON public.plg_calendar_webhook_deliveries (status, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_webhook_deliveries ENABLE ROW LEVEL SECURITY;\n-- Read-only for the app: every write comes from the webhook function as\n-- service_role, so a browser cannot forge or retire a delivery.\nGRANT SELECT ON public.plg_calendar_webhook_deliveries TO authenticated;\nGRANT ALL ON public.plg_calendar_webhook_deliveries TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries;\nCREATE POLICY plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\nCREATE TABLE IF NOT EXISTS public.plg_calendar_automation_outbox (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n source text NOT NULL DEFAULT 'google_calendar',\n event_type text NOT NULL,\n aggregate_type text NOT NULL,\n aggregate_id text,\n idempotency_key text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n attempts integer NOT NULL DEFAULT 0,\n last_error text,\n occurred_at timestamptz NOT NULL DEFAULT now(),\n -- available_at is the retry clock: a failed row is re-eligible once it passes.\n available_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n error text,\n created_at timestamptz DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_outbox_pending\n ON public.plg_calendar_automation_outbox (status, available_at, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_automation_outbox ENABLE ROW LEVEL SECURITY;\nGRANT SELECT ON public.plg_calendar_automation_outbox TO authenticated;\nGRANT ALL ON public.plg_calendar_automation_outbox TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox;\nCREATE POLICY plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\n-- ===========================================================================\n-- §5 — The gate.\n--\n-- Everything above is a CREATE, and a CREATE says nothing about a pool that\n-- already has the old shape. This block is the part that actually removes the\n-- hole: it drops the three credential columns wherever it finds them — the\n-- pool 004 never reached, the pool restored from an old backup, the pool\n-- someone re-provisioned from 001 — and then refuses to finish if any survived.\n--\n-- The RAISE matters more than the DROP. A migration that silently tolerated a\n-- token column is how this schema kept one for months.\n-- ===========================================================================\nDO $$\nDECLARE\n leftover text;\nBEGIN\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS token_expires_at;\n\n SELECT string_agg(table_name || '.' || column_name, ', ')\n INTO leftover\n FROM information_schema.columns\n WHERE table_schema = 'public'\n AND table_name LIKE 'plg_calendar%'\n AND (\n column_name LIKE '%refresh_token%'\n OR column_name LIKE '%access_token%'\n OR column_name IN ('oauth_token', 'client_secret', 'api_key')\n );\n\n IF leftover IS NOT NULL THEN\n RAISE EXCEPTION\n 'Google Calendar schema still holds credential columns: %. The grant belongs in the platform vault (FAY-1359); redeem it at run time instead.',\n leftover;\n END IF;\nEND $$;\n\n-- Dropping the columns does not erase what was in them: Postgres leaves the old\n-- values in the heap until the next table rewrite. Any grant that ever reached a\n-- pool must be REVOKED AT GOOGLE, not assumed gone — which is also why every\n-- tenant re-consents after this file runs.\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"001_google_calendar\", sql: MIGRATION_001_GOOGLE_CALENDAR },\n { id: \"002_smart_sync\", sql: MIGRATION_002_SMART_SYNC },\n { id: \"003_plg_rename\", sql: MIGRATION_003_PLG_RENAME },\n { id: \"004_drop_oauth_tokens\", sql: MIGRATION_004_DROP_OAUTH_TOKENS },\n { id: \"005_outbound_vault_delivery\", sql: MIGRATION_005_OUTBOUND_VAULT_DELIVERY },\n { id: \"006_webhook_deliveries_outbox\", sql: MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX },\n { id: \"007_credential_free_install\", sql: MIGRATION_007_CREDENTIAL_FREE_INSTALL },\n]\n","// Google Calendar connector descriptor (control-plane metadata).\n//\n// Declares the connector against the SDK integration spine so the platform can\n// reason about what it syncs. The actual data-plane verbs run in the\n// google-calendar-sync edge function; this is the typed contract + capabilities.\nimport type { Connector } from '@fayz-ai/core'\n\nexport const googleCalendarConnector: Connector = {\n id: 'google-calendar',\n provider: 'google',\n pluginId: 'agenda',\n authKind: 'oauth',\n capabilities: [\n {\n entity: 'booking',\n direction: 'bidirectional',\n triggers: ['on-write', 'scheduled', 'webhook'],\n },\n ],\n}\n","// Google Calendar integration — official (in-SDK) addon for plugin-agenda.\n//\n// Settings-only PluginManifest: contributes a \"Google Calendar\" tab to /settings\n// for connecting an account and running a manual sync. Outbound (booking →\n// Google) is automatic via a DB trigger; inbound (Google → booking) via pg_cron\n// or a Google watch webhook. The data plane is the google-calendar-sync edge\n// function (see ./functions/google-calendar-sync). The booking↔event link lives\n// on public.appointments.metadata.googleCalendarEventId.\n//\n// Graduation path: extract to its own `@fayz-ai/plugin-google-calendar` package.\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { googleCalendarConnectorDef } from './connectorDef'\nimport {\n MIGRATION_001_GOOGLE_CALENDAR,\n MIGRATION_002_SMART_SYNC,\n MIGRATION_003_PLG_RENAME,\n MIGRATION_004_DROP_OAUTH_TOKENS,\n MIGRATION_005_OUTBOUND_VAULT_DELIVERY,\n MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX,\n MIGRATION_007_CREDENTIAL_FREE_INSTALL,\n} from './migrations'\n\nexport { createGoogleCalendarProvider } from './data/supabase'\nexport { googleCalendarConnector } from './connector'\nexport { googleCalendarConnectorDef } from './connectorDef'\nexport { deriveGoogleCalendarHealth } from './health'\nexport type { GoogleCalendarHealth, GoogleCalendarHealthIssue, GoogleCalendarHealthIssueCode, GoogleCalendarHealthStatus } from './health'\nexport { resolveBookingConflict, CONFLICT_SKEW_TOLERANCE_MS } from './conflict'\nexport type { BookingConflictInput, BookingConflictDecision, ConflictWinner } from './conflict'\nexport { CONNECTION_COLUMNS, isIntegrationActive, disconnectPatch } from './credentials'\nexport { googleCalendarConnectionStore, GOOGLE_CALENDAR_CONNECTOR_ID } from './connectorDef'\nexport {\n bookingToEvent,\n eventToBookingPatch,\n bookingSummary,\n appointmentRowToEvent,\n eventToAppointmentPatch,\n eventTimes,\n resolveTargetChannel,\n channelRowToChannel,\n} from './mapping'\nexport * from './types'\n\n// Addon plugin: contributes the Google Calendar connector into its host\n// (plugin-agenda). It appears in Agenda settings → Integrations — no top-level\n// settings tab of its own. See packages/saas ConnectorsHub.\nexport function createGoogleCalendarPlugin(): PluginManifest {\n return {\n id: 'google-calendar',\n name: 'Google Calendar',\n icon: 'Calendar',\n version: '0.1.0',\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['agenda'],\n navigation: [],\n routes: [],\n connectors: [googleCalendarConnectorDef],\n functions: [\n {\n slug: 'google-calendar-sync',\n // Not reached through the Fayz ingress: it is called from the browser\n // (calendar list, sync now, import), from the appointments trigger and\n // from the webhook function. Consent is NOT in that list any more — it\n // moved to the platform (FAY-1359/1360), which is also why this function\n // no longer answers GET.\n ingress: 'none',\n // FALSE, and here it is a decision rather than a gap: two of its callers\n // cannot present a JWT — the DB trigger sends a Vault secret as bearer\n // and pg_cron/the webhook send the service-role key. The gateway would\n // reject both before a line of the function runs. Authorization lives one\n // level in: `isServiceRequest` for the service actions, a Supabase user\n // plus tenant membership for the rest, and `tenantId` is required on both.\n verifyJwt: false,\n // NAMES only — and no Google client pair among them any more. The client\n // secret and the tenant's grant are both the platform's; this function\n // redeems a short-lived access token per call with the three names below.\n // SUPABASE_SERVICE_ROLE_KEY is listed because the function reads it\n // TODAY — it is the pool-wide privilege the 2026-08-11 ADR is written\n // to remove, and hiding it from the manifest would hide the debt.\n secrets: [\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n 'GCAL_OUTBOUND_SECRET',\n 'SUPABASE_URL',\n 'SUPABASE_SERVICE_ROLE_KEY',\n ],\n // The RPCs the function's credential should be allowed to call once it\n // stops holding service_role. Both already exist (002/003) and are\n // already how the inbound writes are applied; what is missing is the\n // credential that can call these and nothing else.\n grants: ['gcal_import_event', 'gcal_apply_event_patch'],\n },\n {\n // Declared for the first time (FAY-1379). It had been ACTIVE in the live\n // pool since 2026-05 with no source in any repo — the manifest could not\n // name what nobody could read.\n slug: 'google-calendar-webhook',\n // Google POSTs here directly; there is no ingress to put in front of it.\n ingress: 'none',\n // FALSE, and here it is a correct decision rather than a gap: Google\n // sends no Authorization header at all. The credential is the per-channel\n // token, checked against a stored SHA-256 in constant time, with the\n // resource id and a monotonic message number as the replay guard.\n verifyJwt: false,\n // NAMES only. GCAL_OUTBOUND_SECRET is the shared secret this function\n // presents when it asks google-calendar-sync to pull — the same secret\n // the DB trigger uses. SUPABASE_SERVICE_ROLE_KEY is listed because the\n // function reads it TODAY, same declared debt as the sync function.\n secrets: [\n 'SUPABASE_URL',\n 'SUPABASE_SERVICE_ROLE_KEY',\n 'GCAL_OUTBOUND_SECRET',\n 'GCAL_SYNC_FUNCTION_URL',\n 'GCAL_WEBHOOK_AUTO_PULL',\n ],\n // It calls no RPC: it writes the delivery row and the outbox, and\n // delegates every appointment write to google-calendar-sync.\n grants: [],\n },\n ],\n // Declared for the first time. Without this the connector's SQL was\n // reachable only by whoever remembered the folder — which is how a table\n // holding plaintext OAuth tokens shipped with nothing to gate it.\n migrations: [\n {\n id: 'google-calendar-001_google_calendar',\n version: '0.1.0',\n sql: MIGRATION_001_GOOGLE_CALENDAR,\n description: 'plg_calendar_integrations + plg_calendar_sync_log with tenant RLS, and the outbound appointments trigger',\n },\n {\n id: 'google-calendar-002_smart_sync',\n version: '0.1.0',\n sql: MIGRATION_002_SMART_SYNC,\n description: 'plg_calendar_channels (per-calendar de-para) + gcal_import_event / gcal_apply_event_patch',\n },\n {\n id: 'google-calendar-003_plg_rename',\n version: '0.1.0',\n sql: MIGRATION_003_PLG_RENAME,\n description: 'Rename legacy calendar_* tables to the plg_calendar_* prefix and repoint the RPCs',\n },\n {\n id: 'google-calendar-004_drop_oauth_tokens',\n version: '0.9.1',\n sql: MIGRATION_004_DROP_OAUTH_TOKENS,\n description:\n 'Drop plg_calendar_integrations.oauth_refresh_token/oauth_access_token (destination: the Fayz platform credential store — only inside FAY-1359 ordered rollout), give the outbound trigger an anti-loop guard and a safe no-op, and publish appointments for realtime',\n },\n {\n id: 'google-calendar-005_outbound_vault_delivery',\n version: '0.9.2',\n sql: MIGRATION_005_OUTBOUND_VAULT_DELIVERY,\n description:\n \"Take the outbound credential from the vault secret gcal_outbound_secret instead of the service-role key in app.gcal_service_key, keeping the Authorization header the sync function authorises on, and falling back to the old setting so a legacy pool is never silently disarmed\",\n },\n {\n id: 'google-calendar-006_webhook_deliveries_outbox',\n version: '0.9.2',\n sql: MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX,\n description:\n 'Reconstructed from the live pool (FAY-1379): the webhook columns on plg_calendar_channels plus plg_calendar_webhook_deliveries and plg_calendar_automation_outbox with RLS. Both deployed functions write these and no migration created them, so a fresh pool could not run the webhook at all',\n },\n {\n id: 'google-calendar-007_credential_free_install',\n version: '0.9.3',\n sql: MIGRATION_007_CREDENTIAL_FREE_INSTALL,\n description:\n 'Install the whole connector schema in its post-FAY-1359 shape, from zero, with no credential column at any point — the five tables the beauty pool had dropped, plus a gate that drops a token column wherever it is still found and refuses to finish if one survives',\n },\n ],\n }\n}\n","import React from 'react'\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { createSafeDataProvider, registerTranslations, registerMessageDefaults } from '@fayz-ai/core'\nimport { buildAgendaDomainEvents, buildAgendaMessageDefaults } from './lib/message-events'\nimport type { AgendaPluginOptions } from './config'\nimport { resolveConfig } from './config'\nimport { AgendaPage } from './views/AgendaPage'\nimport { createSupabaseAgendaProvider } from './data/supabase'\nimport { createMockAgendaProvider } from './data/mock'\nimport { setAgendaTenantId } from './lib/tenant'\nimport { createAgendaStore } from './store'\nimport { agendaRegistries } from './data/registries'\nimport { AgendaGeneralSettings } from './components/AgendaGeneralSettings'\nimport { agendaLocales } from './locales'\nimport { MIGRATION_001_PUBLIC_BOOKING } from './migrations'\nimport { setScheduleBlockConfig, getScheduleBlockConfig, PluginSettingsPanel } from '@fayz-ai/admin'\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAgendaPlugin(options?: AgendaPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n registerTranslations(agendaLocales)\n // O texto sugerido para cada fato da agenda. Os FATOS vão no manifesto\n // (`events`), de onde automações, integrações e auditoria leem o mesmo\n // contrato.\n registerMessageDefaults(buildAgendaMessageDefaults())\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseAgendaProvider({ professionalKind: config.professionalKind }),\n () => createMockAgendaProvider(),\n )\n const store = createAgendaStore(provider, options?.financialBridge)\n const registries = [...agendaRegistries, ...(options?.settingsRegistries ?? [])]\n\n // Register schedule block config globally so ScheduleEditor can read it\n setScheduleBlockConfig({\n defaults: config.scheduleBlockDefaults,\n showServices: !!config.serviceLookup,\n showConcurrent: true,\n showBookingWindow: true,\n showLocations: config.modules.locationSelection,\n locations: config.locations.map((l) => ({ id: l.id, name: l.name })),\n // Lazy fetcher — called by ScheduleEditor when locations are needed but empty\n fetchLocations: config.modules.locationSelection && provider.getLocations\n ? async () => {\n const locations = await provider.getLocations!()\n const current = getScheduleBlockConfig()\n if (current) setScheduleBlockConfig({ ...current, locations })\n return locations\n }\n : undefined,\n })\n\n const PageComponent: React.FC<any> = () =>\n React.createElement(AgendaPage, { config, provider, store })\n\n return {\n id: 'agenda',\n defaultAgentRole: 'frontdesk',\n name: config.labels.pageTitle,\n icon: 'Calendar',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n // Booking/scheduling is business-ops (clinic, salon, services) — targets\n // the saas/admin Panel world, not the ecommerce storefront.\n scaffolds: ['saas'],\n defaultEnabled: true,\n // The parts a plan can permit separately (#281, ADR 0025). This is the\n // plugin ADR 0018 named: it ships open with the \"suggest a slot\" button,\n // and the intelligence behind that button is a service we host — so the\n // facet is what says whether this tenant contracted it.\n facets: [\n { id: 'scheduling', label: 'Agenda', description: 'Horários, profissionais e reservas.', includedWithPlugin: true },\n { id: 'public_booking', label: 'Agendamento online', description: 'A página pública onde o cliente marca sozinho.' },\n { id: 'smart_fit', label: 'Encaixe inteligente', description: 'Sugere o melhor horário lendo a agenda inteira.' },\n ],\n dependencies: [],\n // Os FATOS da agenda — só expostos enquanto o módulo está ATIVO.\n events: buildAgendaDomainEvents(),\n declaredFeatures: [\n { id: 'appointments', label: config.labels.pageTitle, group: config.labels.pageTitle },\n { id: 'agenda.schedules', label: 'Schedule Management', group: config.labels.pageTitle },\n ],\n // Recurring monthly quota — counts appointment rows created this month.\n // (Clients/patients are the app's CRUD entity, so their cap is declared by\n // the app's EntityDef.limitKey, not here.)\n declaredLimits: [\n { key: 'bookings_month', label: 'Appointments this month', table: 'appointments', period: 'month' },\n ],\n queryEntities: [\n {\n key: 'agenda:appointments',\n entity: {\n name: 'Appointment',\n namePlural: 'Appointments',\n icon: 'Calendar',\n permission: { feature: 'appointments', action: 'read' },\n // Keys are the PROVIDER's output shape (camelCase) — what filters/\n // dateField/groupBy match against, not the raw DB columns.\n fields: [\n { key: 'startsAt', label: 'Starts at', type: 'text' },\n { key: 'endsAt', label: 'Ends at', type: 'text' },\n { key: 'status', label: 'Status', type: 'text' },\n { key: 'clientName', label: 'Client', type: 'text', searchable: true },\n { key: 'professionalName', label: 'Professional', type: 'text', searchable: true },\n { key: 'orderTotal', label: 'Order total', type: 'number' },\n { key: 'totalDurationMinutes', label: 'Duration (min)', type: 'number' },\n { key: 'createdAt', label: 'Created at', type: 'text' },\n ],\n data: {\n table: 'v_appointments',\n tenantScoped: true,\n searchColumns: ['client_name', 'professional_name'],\n },\n },\n },\n ],\n declaredRpcs: [\n {\n name: 'agent_agenda_create_appointment',\n kind: 'write' as const,\n description:\n 'Guarded appointment create: agent_guard (role→plan→bookings_month cap), working hours, race-safe conflict check, audited.',\n audits: true,\n },\n {\n name: 'agent_agenda_update_appointment',\n kind: 'write' as const,\n description:\n 'Guarded appointment reschedule/reassign/cancel: agent_guard (role→plan, no cap), working hours, race-safe conflict check that skips the appointment itself, audited.',\n audits: true,\n },\n ],\n\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 2,\n label: config.labels.pageTitle,\n route: '/agenda',\n icon: 'Calendar',\n permission: { feature: 'appointments', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/agenda',\n component: PageComponent,\n permission: { feature: 'appointments', action: 'read' as const },\n // Matches the ref agent_agenda_create_appointment returns.\n entityRoutes: ['schedule:appointment'],\n },\n ],\n\n widgets: [],\n\n aiTools: [\n {\n id: 'agenda.list-appointments',\n name: 'listAppointments',\n description: 'Lists upcoming appointments for a given date or date range, optionally filtered by professional.',\n icon: 'Calendar',\n mode: 'read' as const,\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n date: { type: 'string' as const, description: 'Date (YYYY-MM-DD) or \"today\", \"tomorrow\", \"this week\"' },\n professional: { type: 'string' as const, description: 'Professional name to filter by' },\n },\n },\n suggestions: [\n { label: \"What's on the agenda today?\" },\n { label: 'Show me tomorrow\\'s appointments' },\n { label: 'Who has the most bookings this week?' },\n ],\n permission: { feature: 'appointments', action: 'read' as const },\n },\n {\n id: 'agenda.create-appointment',\n name: 'createAppointment',\n description:\n 'Creates a new appointment. Takes IDS, not names: resolve the client/service/professional ids first via findAnything/searchRecords, then call this with an ISO start time in the tenant timezone. The user confirms before booking.',\n icon: 'CalendarPlus',\n mode: 'persist' as const,\n limitKey: 'bookings_month',\n execution: { plane: 'server' as const, kind: 'rpc' as const, rpc: 'agent_agenda_create_appointment' },\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n client_id: { type: 'string' as const, description: 'Client id (from a search)' },\n service_id: { type: 'string' as const, description: 'Service id (from a search)' },\n professional_id: { type: 'string' as const, description: 'Professional id (optional — auto-assigned when omitted)' },\n starts_at: { type: 'string' as const, description: \"LOCAL date-time of the business, NO timezone suffix — e.g. '2026-07-27T10:00' for 10h. The system applies the tenant timezone.\" },\n notes: { type: 'string' as const, description: 'Optional notes' },\n },\n required: ['client_id', 'service_id', 'starts_at'],\n },\n suggestions: [\n { label: 'Book a haircut for Sarah tomorrow at 10am' },\n ],\n permission: { feature: 'appointments', action: 'create' as const },\n },\n {\n id: 'agenda.update-appointment',\n name: 'updateAppointment',\n description:\n 'Changes an appointment that ALREADY EXISTS: reschedule (starts_at), reassign (professional_id), cancel or confirm (status), or annotate (notes). ' +\n 'This is the ONLY way to change an appointment — the appointments entity is a read-only view, so updateRecord cannot touch it. ' +\n 'NEVER answer a reschedule or a cancellation by creating a new appointment: that leaves the original standing and double-books the professional. ' +\n 'Takes the appointment id from a previous search. The duration is preserved automatically. The user confirms before anything changes.',\n icon: 'CalendarClock',\n mode: 'persist' as const,\n execution: { plane: 'server' as const, kind: 'rpc' as const, rpc: 'agent_agenda_update_appointment' },\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n appointment_id: { type: 'string' as const, description: 'Id of the appointment to change (from a search)' },\n starts_at: { type: 'string' as const, description: \"New LOCAL date-time of the business, NO timezone suffix — e.g. '2026-07-27T16:30'. Omit to keep the current time.\" },\n professional_id: { type: 'string' as const, description: 'Move to another professional (optional)' },\n status: {\n type: 'string' as const,\n description: 'New status — use \"cancelled\" to cancel',\n enum: ['scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show'],\n },\n notes: { type: 'string' as const, description: 'Optional notes' },\n },\n required: ['appointment_id'],\n },\n suggestions: [\n { label: 'Remarca o Gustavo para 16:30' },\n { label: 'Cancela o atendimento das 10h' },\n ],\n permission: { feature: 'appointments', action: 'edit' as const },\n },\n {\n id: 'agenda.check-availability',\n name: 'checkAvailability',\n description: 'Checks available time slots for a professional on a given date.',\n icon: 'Clock',\n mode: 'read' as const,\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n professional: { type: 'string' as const, description: 'Professional name' },\n date: { type: 'string' as const, description: 'Date (YYYY-MM-DD) or \"today\", \"tomorrow\"' },\n duration: { type: 'number' as const, description: 'Required duration in minutes' },\n },\n required: ['professional', 'date'],\n },\n suggestions: [\n { label: 'When is Ana available tomorrow?' },\n { label: 'Find a 90-minute slot for Carlos this week' },\n ],\n permission: { feature: 'appointments', action: 'read' as const },\n },\n ],\n\n registries,\n\n settings: [\n {\n id: 'agenda',\n label: 'Agenda',\n icon: 'Calendar',\n // Standard layout: General | Integrations (Google Calendar addon) | Properties.\n component: (() => {\n const AgendaSettingsTab: React.FC = () => React.createElement(PluginSettingsPanel, {\n title: 'Agenda',\n generalSettings: React.createElement(AgendaGeneralSettings),\n registries,\n hostPluginId: 'agenda',\n routeBase: '/settings/agenda',\n })\n AgendaSettingsTab.displayName = 'AgendaSettingsTab'\n return AgendaSettingsTab as unknown as React.ComponentType<unknown>\n })(),\n order: 5,\n permission: { feature: 'appointments', action: 'read' as const },\n },\n ],\n migrations: [\n {\n id: 'agenda-001-public-booking',\n version: '0.3.0',\n sql: MIGRATION_001_PUBLIC_BOOKING,\n description:\n 'Booking read model (v_appointments) + anon public booking surface (v_public_services, get_available_slots, create_public_booking) + order_items duration/assignee columns',\n },\n ],\n\n // Google Calendar is the connector this module's addon already ships;\n // Calendly and WhatsApp are the two the Fayz plugin page has been\n // promising since the catalogue was written.\n integrations: ['google-calendar', 'calendly', 'whatsapp'],\n locales: agendaLocales,\n }\n}\n\n// Re-export types for consumers\nexport type { AgendaPluginOptions } from './config'\nexport type { ResolvedAgendaConfig } from './config'\nexport type { AgendaDataProvider } from './data/types'\n// Seedable in-memory provider — apps pass a seed to render the calendar with\n// app-specific events instead of the built-in salon sample.\nexport { createMockAgendaProvider } from './data/mock'\nexport type { MockAgendaSeed, MockAgendaProviderOptions } from './data/mock'\nexport type { AgendaFinancialBridge, BookingPaymentStatus, BookingPaymentSummary, BookingPaymentDetail } from './bridges/financial-bridge'\nexport { createFinancialBridge, computeCommissionAmount } from './bridges/create-financial-bridge'\n\n// Google Calendar integration (official addon) — settings-only plugin + helpers\nexport { createGoogleCalendarPlugin, createGoogleCalendarProvider, googleCalendarConnector, bookingToEvent, eventToBookingPatch } from './integrations/google-calendar'\n\n// O catálogo de fatos da agenda — exposto para quem quiser ler o contrato sem\n// instalar o módulo (documentação, testes, um consumidor de webhook).\nexport { buildAgendaDomainEvents, buildAgendaMessageDefaults } from './lib/message-events'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/message-events.ts","../src/config.ts","../src/context.tsx","../src/styles/calendar-styles.ts","../src/hooks/useAgendaSettings.ts","../src/components/FilterRail.tsx","../src/components/BookingPaymentPanel.tsx","../src/types.ts","../src/components/AppointmentModal.tsx","../src/components/FloatingPanel.tsx","../src/components/AppointmentPopover.tsx","../src/components/EventContextMenu.tsx","../src/components/AgendaMobileList.tsx","../src/lib/calendar-events.ts","../src/views/CalendarView.tsx","../src/lib/tenant.ts","../src/views/AgendaPage.tsx","../src/components/CheckinDialog.tsx","../src/components/PaymentStatusBadge.tsx","../src/views/CheckinView.tsx","../src/views/CheckinPage.tsx","../src/data/supabase.ts","../src/lib/booking-events.ts","../src/store.ts","../src/data/registries.ts","../src/components/AgendaGeneralSettings.tsx","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/migrations/index.ts","../src/bridges/create-financial-bridge.ts","../src/integrations/google-calendar/mapping.ts","../src/integrations/google-calendar/credentials.ts","../src/integrations/google-calendar/data/tables.ts","../src/integrations/google-calendar/data/supabase.ts","../src/integrations/google-calendar/health.ts","../src/integrations/google-calendar/panel-data.ts","../src/integrations/google-calendar/components/CalendarColorDot.tsx","../src/integrations/google-calendar/components/useAgendaLookups.ts","../src/integrations/google-calendar/components/ChannelMappingList.tsx","../src/integrations/google-calendar/components/ImportEventsWizard.tsx","../src/integrations/google-calendar/connectorDef.tsx","../src/integrations/google-calendar/migrations/index.ts","../src/integrations/google-calendar/connector.ts","../src/integrations/google-calendar/index.ts","../src/index.ts"],"names":["formatCurrency","t","jsxs","jsx","Fragment","useState","useEffect","createPortal","useTranslation","provider","getSupabaseClientOptional","X","Check","STYLE_ID","useRef","fmtCurrency","Clock","User","MapPin","FileText","HandCoins","DollarSign","AlertTriangle","Tooltip","Pencil","Trash2","getCurrentLocale","useMemo","usePluginPrefs","useCallback","booking","t2","PersonLink","Plus","Button","React","RightRailPage","SharedPaymentStatusBadge","CheckCircle2","usePluginRuntimeOptional","getActiveTenantId","statuses","toast","bookingToEvent","localTimeZone","Loader2","AlertCircle","RefreshCw","Checkbox","Badge","setScheduleBlockConfig","getScheduleBlockConfig"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAk2C/B,IAAM,uDAAA,GAA0D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAkDhE,IAAM,4CAAA,GAA+C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iFAAA,CAAA;AAuDrD,IAAM,oDAAA,GAAuD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA2B7D,IAAM,8CAAA,GAAiD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA8CvD,IAAM,iDAAA,GAAoD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmD1D,IAAM,oDAAA,GAAuD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAqH7D,IAAM,UAAA,GAAiD;AAAA,EAC5D,EAAE,EAAA,EAAI,cAAA,EAAgB,GAAA,EAAK,sBAAA,EAAuB;AAAA,EAClD,EAAE,EAAA,EAAI,+CAAA,EAAiD,GAAA,EAAK,uDAAA,EAAwD;AAAA,EACpH,EAAE,EAAA,EAAI,oCAAA,EAAsC,GAAA,EAAK,4CAAA,EAA6C;AAAA,EAC9F,EAAE,EAAA,EAAI,4CAAA,EAA8C,GAAA,EAAK,oDAAA,EAAqD;AAAA,EAC9G,EAAE,EAAA,EAAI,sCAAA,EAAwC,GAAA,EAAK,8CAAA,EAA+C;AAAA,EAClG,EAAE,EAAA,EAAI,yCAAA,EAA2C,GAAA,EAAK,iDAAA,EAAkD;AAAA,EACxG,EAAE,EAAA,EAAI,4CAAA,EAA8C,GAAA,EAAK,oDAAA;AAC3D,CAAA;AC1rDO,SAAS,uBAAA,CAAwB,OAAe,WAAA,EAA6B;AAClF,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAK,CAAA,IAAK,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,WAAW,CAAA,IAAK,CAAA;AACpC,EAAA,IAAI,IAAA,IAAQ,CAAA,IAAK,IAAA,IAAQ,CAAA,EAAG,OAAO,CAAA;AACnC,EAAA,OAAO,KAAK,KAAA,CAAM,IAAA,IAAQ,IAAA,GAAO,GAAA,CAAA,GAAO,GAAG,CAAA,GAAI,GAAA;AACjD;AAwBO,SAAS,sBAAsBQ,SAAAA,EAAwD;AAC5F,EAAA,OAAO;AAAA,IACL,MAAM,uBAAuB,QAAA,EAAiE;AAC5F,MAAA,MAAM,MAAA,uBAAa,GAAA,EAAmC;AACtD,MAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAGlC,MAAA,MAAM,WAAWC,yBAAAA,EAA0B;AAC3C,MAAA,IAAI,CAAC,UAAU,OAAO,MAAA;AAMtB,MAAA,IAAI;AACF,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,MAAM,QAAA,CAC1B,IAAA,CAAK,wBAAwB,CAAA,CAC7B,MAAA,CAAO,6EAA6E,CAAA,CACpF,EAAA,CAAG,YAAY,QAAQ,CAAA;AAE1B,QAAA,KAAA,MAAW,GAAA,IAAO,IAAA,IAAQ,EAAC,EAAG;AAC5B,UAAA,MAAA,CAAO,GAAA,CAAI,IAAI,QAAA,EAAoB;AAAA,YACjC,WAAW,GAAA,CAAI,QAAA;AAAA,YACf,iBAAiB,GAAA,CAAI,gBAAA;AAAA,YACrB,MAAA,EAAS,IAAI,MAAA,KAAsB,MAAA,GAC/B,iBAAiB,GAAA,CAAI,YAAsB,IAC1C,GAAA,CAAI,MAAA;AAAA,YACT,WAAA,EAAa,MAAA,CAAO,GAAA,CAAI,YAAY,CAAA,IAAK,CAAA;AAAA,YACzC,UAAA,EAAY,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA,IAAK;AAAA,WACxC,CAAA;AAAA,QACH;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAAqB;AAE7B,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,iBAAiB,OAAA,EAAuD;AAC5E,MAAA,MAAM,WAAWA,yBAAAA,EAA0B;AAC3C,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAItB,MAAA,MAAM,CAAC,OAAA,EAAS,MAAM,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,QAC1C,QAAA,CACG,IAAA,CAAK,wBAAwB,CAAA,CAC7B,MAAA,CAAO,6EAA6E,CAAA,CACpF,EAAA,CAAG,UAAA,EAAY,OAAO,CAAA,CACtB,MAAA,EAAO;AAAA,QACV,QAAA,CAAS,IAAA,CAAK,yBAAyB,CAAA,CAAE,MAAA,CAAO,GAAG,CAAA,CAAE,EAAA,CAAG,YAAA,EAAc,OAAO,CAAA,CAAE,KAAA,CAAM,UAAU;AAAA,OAChG,CAAA;AAED,MAAA,MAAM,QAAQ,OAAA,CAAQ,IAAA;AACtB,MAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAGnB,MAAA,MAAM,UAAU,CAAC,GAAG,IAAI,GAAA,CAAA,CAAK,MAAA,CAAO,QAAQ,EAAC,EAAG,GAAA,CAAI,CAAC,MAAW,CAAA,CAAE,sBAAsB,EAAE,MAAA,CAAO,OAAO,CAAC,CAAC,CAAA;AAC1G,MAAA,IAAI,YAAoC,EAAC;AACzC,MAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,QAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,QAAA,CAAS,IAAA,CAAK,oCAAoC,CAAA,CAAE,MAAA,CAAO,UAAU,CAAA,CAAE,EAAA,CAAG,MAAM,OAAO,CAAA;AACrH,QAAA,SAAA,GAAY,MAAA,CAAO,WAAA,CAAA,CAAa,KAAA,IAAS,IAAI,GAAA,CAAI,CAACT,EAAAA,KAAW,CAACA,EAAAA,CAAE,EAAA,EAAIA,EAAAA,CAAE,IAAI,CAAC,CAAC,CAAA;AAAA,MAC9E;AAEA,MAAA,MAAM,aAAa,MAAA,CAAO,IAAA,IAAQ,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,MAAgC;AAAA,QACzE,EAAA,EAAI,MAAA,CAAO,CAAA,CAAE,EAAE,CAAA;AAAA,QACf,MAAA,EAAQ,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA,IAAK,CAAA;AAAA,QAC5B,UAAA,EAAY,MAAA,CAAO,CAAA,CAAE,WAAW,CAAA,IAAK,CAAA;AAAA,QACrC,MAAA,EAAQ,MAAA,CAAO,CAAA,CAAE,MAAA,IAAU,SAAS,CAAA;AAAA,QACpC,OAAA,EAAS,MAAA,CAAO,CAAA,CAAE,QAAA,IAAY,EAAE,CAAA;AAAA,QAChC,mBAAmB,CAAA,CAAE,kBAAA,IAAsB,OAAO,MAAA,CAAO,CAAA,CAAE,kBAAkB,CAAA,GAAI,MAAA;AAAA,QACjF,aAAa,CAAA,CAAE,YAAA,GAAe,MAAA,CAAO,CAAA,CAAE,YAAY,CAAA,GAAI,MAAA;AAAA,QACvD,qBAAA,EAAuB,EAAE,sBAAA,GAAyB,SAAA,CAAU,OAAO,CAAA,CAAE,sBAAsB,CAAC,CAAA,GAAI,MAAA;AAAA,QAChG,WAAW,CAAA,CAAE,UAAA,GAAa,MAAA,CAAO,CAAA,CAAE,UAAU,CAAA,GAAI,MAAA;AAAA,QACjD,kBAAkB,CAAA,CAAE,iBAAA,GAAoB,MAAA,CAAO,CAAA,CAAE,iBAAiB,CAAA,GAAI;AAAA,OACxE,CAAE,CAAA;AAEF,MAAA,OAAO;AAAA,QACL,WAAW,KAAA,CAAM,QAAA;AAAA,QACjB,iBAAiB,KAAA,CAAM,gBAAA;AAAA,QACvB,MAAA,EAAS,MAAM,MAAA,KAAsB,MAAA,GACjC,iBAAiB,KAAA,CAAM,YAAsB,IAC5C,KAAA,CAAM,MAAA;AAAA,QACX,WAAA,EAAa,MAAA,CAAO,KAAA,CAAM,YAAY,CAAA,IAAK,CAAA;AAAA,QAC3C,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA,IAAK,CAAA;AAAA,QACzC;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,sBAAA,CAAuB,OAAA,EAAiB,OAAA,EAI1B;AAIlB,MAAA,MAAM,WAAWS,yBAAAA,EAA0B;AAC3C,MAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,MAAM,wBAAwB,CAAA;AACvD,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,QAAA,CAAS,IAAI,uBAAA,EAAyB;AAAA,QAC5D,UAAA,EAAY,OAAA;AAAA,QACZ,UAAA,EAAY,SAAS,OAAA,IAAW,IAAA;AAAA,QAChC,QAAA,EAAU,UAAA;AAAA,QACV,cAAA,EAAgB,SAAS,YAAA,IAAgB,CAAA;AAAA,QACzC,WAAA,EAAa;AAAA,OACd,CAAA;AACD,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AACxC,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,YAAY,KAAA,EAAO;AACvB,MAAA,MAAMD,UAAS,WAAA,CAAY;AAAA,QACzB,YAAY,KAAA,CAAM,UAAA;AAAA,QAClB,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,aAAa,KAAA,CAAM,WAAA;AAAA,QACnB,qBAAqB,KAAA,CAAM,mBAAA;AAAA,QAC3B,iBAAiB,KAAA,CAAM,eAAA;AAAA,QACvB,eAAe,KAAA,CAAM,aAAA;AAAA,QACrB,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,kBAAkB,KAAA,CAAM;AAAA,OACzB,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,wBAAA,CAAyB,OAAA,EAAS,OAAA,EAAS;AAC/C,MAAA,MAAM,WAAWC,yBAAAA,EAA0B;AAC3C,MAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAKtB,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,KAAU,MAAM,QAAA,CAC3B,KAAK,gBAAgB,CAAA,CACrB,OAAO,mDAAmD,CAAA,CAC1D,GAAG,UAAA,EAAY,OAAO,EACtB,KAAA,CAAM,CAAC,EACP,WAAA,EAAY;AACf,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,CAAM,iBAAiB,OAAO,IAAA;AAK7C,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,SAC3B,IAAA,CAAK,sBAAsB,CAAA,CAC3B,MAAA,CAAO,iBAAiB,CAAA,CACxB,EAAA,CAAG,MAAM,KAAA,CAAM,eAAe,EAC9B,MAAA,EAAO;AAEV,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,EAAO,eAAe,CAAA,IAAK,CAAA;AAC/C,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA,IAAK,CAAA;AAC1C,MAAA,MAAM,MAAA,GAAS,uBAAA,CAAwB,IAAA,EAAM,IAAI,CAAA;AACjD,MAAA,IAAI,MAAA,IAAU,GAAG,OAAO,IAAA;AAGxB,MAAA,MAAM,EAAE,MAAM,QAAA,EAAS,GAAI,MAAM,QAAA,CAC9B,IAAA,CAAK,yBAAyB,CAAA,CAC9B,MAAA,CAAO,IAAI,CAAA,CACX,EAAA,CAAG,cAAc,OAAO,CAAA,CACxB,GAAG,eAAA,EAAiB,YAAY,CAAA,CAChC,KAAA,CAAM,CAAC,CAAA;AACV,MAAA,IAAI,YAAY,QAAA,CAAS,MAAA,GAAS,GAAG,OAAO,QAAA,CAAS,CAAC,CAAA,CAAE,EAAA;AAExD,MAAA,MAAM,OAAA,GAAU,OAAA,EAAS,OAAA,IAAA,iBAAW,IAAI,IAAA,IAAO,WAAA,EAAY,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAExE,MAAA,MAAM,EAAE,MAAM,QAAA,EAAS,GAAI,MAAM,QAAA,CAC9B,IAAA,CAAK,yBAAyB,CAAA,CAC9B,MAAA,CAAO;AAAA,QACN,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,UAAA,EAAY,OAAA;AAAA,QACZ,SAAA,EAAW,OAAA;AAAA;AAAA,QACX,aAAA,EAAe,YAAA;AAAA,QACf,MAAA;AAAA,QACA,WAAA,EAAa,CAAA;AAAA,QACb,MAAA,EAAQ,SAAA;AAAA,QACR,QAAA,EAAU,OAAA;AAAA,QACV,QAAA,EAAU;AAAA,UACR,MAAA,EAAQ,QAAA;AAAA,UACR,IAAA,EAAM,YAAA;AAAA,UACN,gBAAgB,KAAA,CAAM,eAAA;AAAA,UACtB,cAAA,EAAgB,IAAA;AAAA,UAChB,UAAA,EAAY;AAAA;AACd,OACD,CAAA,CACA,MAAA,CAAO,IAAI,EACX,MAAA,EAAO;AAEV,MAAA,OAAQ,UAAU,EAAA,IAA6B,IAAA;AAAA,IACjD,CAAA;AAAA,IAEA,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAO;AAE7B,MAAA,MAAM,KAAA,GAAA,qBAAY,IAAA,EAAK,EAAE,aAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAClD,MAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,sBAAA,CAAuB,OAAA,EAAS,EAAE,YAAA,EAAc,CAAA,EAAG,OAAA,EAAS,KAAA,EAAO,CAAA;AAGhG,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAS,CAAA;AACpD,MAAA,IAAI,CAAC,UAAU,MAAA,CAAO,SAAA,CAAU,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,qBAAqB,CAAA;AAEnF,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA;AAGnC,MAAA,MAAM,KAAK,WAAA,CAAY;AAAA,QACrB,YAAY,QAAA,CAAS,EAAA;AAAA,QACrB,QAAQ,QAAA,CAAS,MAAA;AAAA,QACjB,WAAA,EAAa,KAAA;AAAA,QACb,qBAAqB,KAAA,CAAM,mBAAA;AAAA,QAC3B,iBAAiB,KAAA,CAAM,eAAA;AAAA,QACvB,eAAe,KAAA,CAAM,aAAA;AAAA,QACrB,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,kBAAkB,KAAA,CAAM;AAAA,OACzB,CAAA;AAGD,MAAA,OAAQ,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAS,CAAA;AAAA,IAC/C,CAAA;AAAA,IAEA,MAAM,qBAAA,GAAwB;AAC5B,MAAA,MAAM,KAAA,GAAQ,MAAMD,SAAAA,CAAS,qBAAA,EAAsB;AACnD,MAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAACR,EAAAA,MAAY,EAAE,EAAA,EAAIA,EAAAA,CAAE,EAAA,EAAI,IAAA,EAAMA,EAAAA,CAAE,IAAA,EAAM,eAAA,EAAiBA,EAAAA,CAAE,iBAAgB,CAAE,CAAA;AAAA,IAC/F,CAAA;AAAA,IAEA,MAAM,eAAA,GAAkB;AACtB,MAAA,MAAM,QAAA,GAAW,MAAMQ,SAAAA,CAAS,eAAA,EAAgB;AAChD,MAAA,OAAO,QAAA,CACJ,OAAO,CAAC,CAAA,KAAW,EAAE,QAAQ,CAAA,CAC7B,IAAI,CAAC,CAAA,MAAY,EAAE,EAAA,EAAI,CAAA,CAAE,IAAI,IAAA,EAAM,CAAA,CAAE,MAAM,WAAA,EAAa,CAAA,CAAE,aAAY,CAAE,CAAA;AAAA,IAC7E,CAAA;AAAA,IAEA,MAAM,kBAAkB,mBAAA,EAA6B;AACnD,MAAA,MAAM,OAAA,GAAU,MAAMA,SAAAA,CAAS,iBAAA,EAAkB;AACjD,MAAA,OAAO,OAAA,CACJ,OAAO,CAAC,CAAA,KAAW,EAAE,mBAAA,KAAwB,mBAAA,IAAuB,EAAE,QAAQ,CAAA,CAC9E,IAAI,CAAC,CAAA,MAAY,EAAE,EAAA,EAAI,CAAA,CAAE,IAAI,IAAA,EAAM,CAAA,CAAE,MAAK,CAAE,CAAA;AAAA,IACjD;AAAA,GACF;AACF;AAEA,SAAS,iBAAiB,MAAA,EAAsC;AAC9D,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AAAQ,MAAA,OAAO,MAAA;AAAA,IACpB,KAAK,SAAA;AAAW,MAAA,OAAO,SAAA;AAAA,IACvB,KAAK,SAAA;AAAW,MAAA,OAAO,SAAA;AAAA,IACvB,KAAK,WAAA;AAAa,MAAA,OAAO,WAAA;AAAA,IACzB,KAAK,UAAA;AAAY,MAAA,OAAO,SAAA;AAAA,IACxB,KAAK,SAAA;AAAW,MAAA,OAAO,SAAA;AAAA,IACvB,KAAK,WAAA;AAAa,MAAA,OAAO,MAAA;AAAA,IACzB,KAAK,WAAA;AAAa,MAAA,OAAO,MAAA;AAAA,IACzB,KAAK,aAAA;AAAe,MAAA,OAAO,MAAA;AAAA,IAC3B,KAAK,WAAA;AAAa,MAAA,OAAO,MAAA;AAAA,IACzB,KAAK,SAAA;AAAW,MAAA,OAAO,MAAA;AAAA,IACvB,KAAK,QAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB;AAAS,MAAA,OAAO,SAAA;AAAA;AAEpB;;;ACjQO,SAAS,eAAe,CAAA,EAA6D;AAC1F,EAAA,MAAM,QAAA,GAAA,CAAY,CAAA,CAAE,QAAA,IAAY,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,IAAI,CAAA;AAChF,EAAA,MAAM,GAAA,GAAM,EAAE,UAAA,IAAc,EAAA;AAC5B,EAAA,IAAI,YAAY,GAAA,EAAK,OAAO,CAAA,EAAG,QAAQ,WAAM,GAAG,CAAA,CAAA;AAChD,EAAA,OAAO,YAAY,GAAA,IAAO,aAAA;AAC5B;AAGO,SAASkC,eAAAA,CAAe,GAAoB,QAAA,EAA0C;AAC3F,EAAA,IAAI,CAAC,CAAA,CAAE,QAAA,IAAY,CAAC,CAAA,CAAE,QAAQ,OAAO,IAAA;AACrC,EAAA,MAAM,QAAQ,CAAC,CAAA,CAAE,OAAO,CAAA,CAAE,gBAAA,GAAmB,QAAQ,CAAA,CAAE,gBAAgB,KAAK,EAAA,EAAI,CAAA,CAAE,gBAAgB,EAAE,CAAA,CACjG,OAAO,OAAO,CAAA,CAAE,KAAK,IAAI,CAAA;AAC5B,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,eAAe,CAAC,CAAA;AAAA,IACzB,aAAa,KAAA,IAAS,MAAA;AAAA,IACtB,KAAA,EAAO,EAAE,QAAA,EAAU,CAAA,CAAE,UAAU,QAAA,EAAS;AAAA,IACxC,GAAA,EAAK,EAAE,QAAA,EAAU,CAAA,CAAE,QAAQ,QAAA;AAAS,GACtC;AACF;AAGO,SAAS,oBAAoB,EAAA,EAA6E;AAC/G,EAAA,IAAI,GAAG,MAAA,KAAW,WAAA,EAAa,OAAO,EAAE,QAAQ,WAAA,EAAY;AAC5D,EAAA,MAAM1C,EAAAA,GAAI,WAAW,EAAE,CAAA;AACvB,EAAA,OAAO,EAAE,QAAA,EAAUA,EAAAA,CAAE,QAAA,EAAU,MAAA,EAAQA,GAAE,MAAA,EAAO;AAClD;AAoDO,SAAS,WAAW,EAAA,EAA2B;AACpD,EAAA,MAAM,MAAA,GAAS,CAAC,EAAA,CAAG,KAAA,EAAO,YAAY,CAAC,CAAC,GAAG,KAAA,EAAO,IAAA;AAClD,EAAA,MAAM,WAAW,EAAA,CAAG,KAAA,EAAO,QAAA,IAAY,EAAA,CAAG,OAAO,IAAA,IAAQ,EAAA;AACzD,EAAA,MAAM,SAAS,EAAA,CAAG,GAAA,EAAK,QAAA,IAAY,EAAA,CAAG,KAAK,IAAA,IAAQ,QAAA;AACnD,EAAA,OAAO,EAAE,QAAA,EAAU,MAAA,EAAQ,MAAA,EAAO;AACpC;AAKO,SAAS,oBAAoB,CAAA,EAAwC;AAC1E,EAAA,OAAO;AAAA,IACL,IAAI,CAAA,CAAE,EAAA;AAAA,IACN,eAAe,CAAA,CAAE,cAAA;AAAA,IACjB,UAAU,CAAA,CAAE,SAAA;AAAA,IACZ,kBAAkB,CAAA,CAAE,kBAAA;AAAA,IACpB,OAAA,EAAS,EAAE,OAAA,IAAW,IAAA;AAAA,IACtB,KAAA,EAAO,EAAE,KAAA,IAAS,IAAA;AAAA,IAClB,WAAW,CAAA,CAAE,SAAA;AAAA,IACb,UAAA,EAAY,EAAE,WAAA,IAAe,IAAA;AAAA,IAC7B,QAAA,EAAU,EAAE,SAAA,IAAa,IAAA;AAAA,IACzB,UAAA,EAAY,EAAE,WAAA,IAAe,aAAA;AAAA,IAC7B,SAAA,EAAW,EAAE,UAAA,IAAc,IAAA;AAAA,IAC3B,SAAA,EAAW,EAAE,UAAA,IAAc,IAAA;AAAA,IAC3B,UAAA,EAAY,EAAE,WAAA,IAAe,IAAA;AAAA,IAC7B,gBAAA,EAAkB,EAAE,kBAAA,IAAsB,IAAA;AAAA,IAC1C,QAAA,EAAU,EAAE,SAAA,IAAa,IAAA;AAAA,IACzB,SAAA,EAAW,EAAE,UAAA,IAAc,EAAA;AAAA,IAC3B,SAAA,EAAW,EAAE,UAAA,IAAc;AAAA,GAC7B;AACF;;;ACxHO,IAAM,kBAAA,GAAqB,iDAAA;AAU3B,SAAS,oBACd,GAAA,EACS;AACT,EAAA,OAAO,CAAC,CAAC,GAAA,IAAO,GAAA,CAAI,MAAA,KAAW,KAAA;AACjC;AAQO,SAAS,eAAA,GAA2C;AACzD,EAAA,OAAO,EAAE,QAAQ,KAAA,EAAO,UAAA,EAAA,qBAAgB,IAAA,EAAK,EAAE,aAAY,EAAE;AAC/D;;;ACrCO,IAAM,WAAA,GAAc;AAAA,EACzB,YAAA,EAAc,2BAAA;AAAA,EACd,QAAA,EAAU,uBAAA;AAAA,EACV,OAAA,EAAS,uBAGX,CAAA;;;ACaA,IAAM,QAAA,GAAW,sBAAA;AAEjB,SAAS,EAAA,GAAK;AACZ,EAAA,MAAM,WAAWS,yBAAAA,EAA0B;AAC3C,EAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,MAAM,0BAA0B,CAAA;AACzD,EAAA,OAAO,QAAA;AACT;AAWA,eAAe,OAAU,IAAA,EAA2C;AAClE,EAAA,MAAM,WAAW8B,iBAAAA,EAAkB;AACnC,EAAA,MAAM,YAAA,GAAe,MAAM,qBAAA,CAAsB,EAAE,UAAU,CAAA;AAE7D,EAAA,MAAM,EAAE,MAAM,KAAA,EAAM,GAAI,MAAM,EAAA,EAAG,CAAE,SAAA,CAAU,MAAA,CAAO,QAAA,EAAU;AAAA,IAC5D,IAAA,EAAM,EAAE,GAAG,IAAA,EAAM,QAAA,EAAS;AAAA,IAC1B,OAAA,EAAS,EAAE,CAAC,8BAA8B,GAAG,YAAA;AAAa,GAC3D,CAAA;AACD,EAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AACxC,EAAA,OAAO,IAAA;AACT;AAgDO,SAAS,4BAAA,GAAuD;AACrE,EAAA,OAAO;AAAA,IACL,MAAM,cAAA,GAAiB;AAErB,MAAA,MAAM,EAAE,MAAK,GAAI,MAAM,IAAG,CAAE,IAAA,CAAK,YAAY,YAAY,CAAA,CAAE,OAAO,kBAAkB,CAAA,CAAE,GAAG,UAAA,EAAY,QAAQ,EAAE,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AACpI,MAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,MAAA,OAAO;AAAA,QACL,IAAI,IAAA,CAAK,EAAA;AAAA,QACT,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,UAAA,EAAY,KAAK,WAAA,IAAe,SAAA;AAAA,QAChC,MAAA,EAAQ,oBAAoB,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA,QAIhC,SAAA,EAAW,oBAAoB,IAAI,CAAA;AAAA,QACnC,UAAA,EAAY,KAAK,YAAA,IAAgB;AAAA,OACnC;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,iBAAA,GAAoB;AACxB,MAAA,MAAM,EAAE,OAAM,GAAI,MAAM,IAAG,CACxB,IAAA,CAAK,WAAA,CAAY,YAAY,CAAA,CAC7B,MAAA;AAAA,QACC;AAAA,UACE,WAAWA,iBAAAA,EAAkB;AAAA,UAC7B,QAAA,EAAU,QAAA;AAAA,UACV,MAAA,EAAQ,IAAA;AAAA,UACR,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,SACrC;AAAA,QACA,EAAE,YAAY,oBAAA;AAAqB,OACrC;AACF,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,IAEA,MAAM,YAAY,UAAA,EAAY;AAC5B,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,WAAA,CAAY,YAAY,CAAA,CAAE,MAAA,CAAO,EAAE,WAAA,EAAa,UAAA,EAAY,6BAAY,IAAI,IAAA,IAAO,WAAA,EAAY,EAAG,CAAA,CAAE,EAAA,CAAG,YAAY,QAAQ,CAAA;AAAA,IAC7I,CAAA;AAAA,IAEA,MAAM,UAAA,GAAa;AAKjB,MAAA,MAAM,MAAA,CAAO,EAAE,MAAA,EAAQ,YAAA,EAAc,CAAA;AACrC,MAAA,MAAM,EAAA,EAAG,CAAE,IAAA,CAAK,WAAA,CAAY,YAAY,CAAA,CAAE,MAAA,CAAO,eAAA,EAAiB,CAAA,CAAE,EAAA,CAAG,UAAA,EAAY,QAAQ,CAAA;AAAA,IAC7F,CAAA;AAAA,IAEA,MAAM,OAAA,GAAU;AACd,MAAA,OAAO,MAAA,CAAkE;AAAA,QACvE,MAAA,EAAQ,aAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,UAAA,GAAa;AACjB,MAAA,MAAM,EAAE,MAAK,GAAI,MAAM,IAAG,CAAE,IAAA,CAAK,YAAY,OAAO,CAAA,CAAE,OAAO,GAAG,CAAA,CAAE,MAAM,YAAA,EAAc,EAAE,WAAW,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,EAAE,CAAA;AACpH,MAAA,OAAA,CAAQ,IAAA,IAAQ,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,MAAY;AAAA,QACnC,IAAI,CAAA,CAAE,EAAA;AAAA,QAAI,WAAW,CAAA,CAAE,SAAA;AAAA,QAAW,OAAA,EAAS,EAAE,OAAA,IAAW,MAAA;AAAA,QACxD,QAAQ,CAAA,CAAE,MAAA;AAAA,QAAQ,OAAA,EAAS,EAAE,OAAA,IAAW,CAAA;AAAA,QAAG,OAAA,EAAS,EAAE,OAAA,IAAW,CAAA;AAAA,QACjE,KAAA,EAAO,EAAE,KAAA,IAAS,MAAA;AAAA,QAAW,WAAW,CAAA,CAAE;AAAA,OAC5C,CAAE,CAAA;AAAA,IACJ,CAAA;AAAA,IAEA,MAAM,mBAAA,GAAsB;AAC1B,MAAA,MAAM,SAAS,MAAM,MAAA,CAAiD,EAAE,MAAA,EAAQ,kBAAkB,CAAA;AAClG,MAAA,OAAO,MAAA,CAAO,aAAa,EAAC;AAAA,IAC9B,CAAA;AAAA,IAEA,MAAM,YAAA,GAAe;AACnB,MAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,EAAA,EAAG,CAAE,KAAK,WAAA,CAAY,QAAQ,CAAA,CAAE,MAAA,CAAO,GAAG,CAAA,CAAE,KAAA,CAAM,cAAc,EAAE,SAAA,EAAW,MAAM,CAAA;AAC1G,MAAA,OAAA,CAAQ,IAAA,IAAQ,EAAC,EAAG,GAAA,CAAI,mBAAmB,CAAA;AAAA,IAC7C,CAAA;AAAA,IAEA,MAAM,YAAY,KAAA,EAAO;AACvB,MAAA,MAAM,WAAWA,iBAAAA,EAAkB;AAEnC,MAAA,IAAI,gBAAgB,KAAA,CAAM,aAAA;AAC1B,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA,MAAM,EAAE,MAAK,GAAI,MAAM,IAAG,CAAE,IAAA,CAAK,YAAY,YAAY,CAAA,CAAE,OAAO,IAAI,CAAA,CAAE,GAAG,UAAA,EAAY,QAAQ,EAAE,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AACtH,QAAA,aAAA,GAAgB,IAAA,EAAM,EAAA;AAAA,MACxB;AACA,MAAA,MAAM,GAAA,GAA+B;AAAA,QACnC,cAAA,EAAgB,aAAA;AAAA,QAChB,SAAA,EAAW,QAAA;AAAA,QACX,oBAAoB,KAAA,CAAM,gBAAA;AAAA,QAC1B,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC;AACA,MAAA,IAAI,KAAA,CAAM,EAAA,KAAO,MAAA,EAAW,GAAA,CAAI,KAAK,KAAA,CAAM,EAAA;AAC3C,MAAA,IAAI,KAAA,CAAM,OAAA,KAAY,MAAA,EAAW,GAAA,CAAI,UAAU,KAAA,CAAM,OAAA;AACrD,MAAA,IAAI,KAAA,CAAM,KAAA,KAAU,MAAA,EAAW,GAAA,CAAI,QAAQ,KAAA,CAAM,KAAA;AACjD,MAAA,IAAI,KAAA,CAAM,SAAA,KAAc,MAAA,EAAW,GAAA,CAAI,YAAY,KAAA,CAAM,SAAA;AACzD,MAAA,IAAI,KAAA,CAAM,UAAA,KAAe,MAAA,EAAW,GAAA,CAAI,cAAc,KAAA,CAAM,UAAA;AAC5D,MAAA,IAAI,KAAA,CAAM,QAAA,KAAa,MAAA,EAAW,GAAA,CAAI,YAAY,KAAA,CAAM,QAAA;AACxD,MAAA,IAAI,KAAA,CAAM,UAAA,KAAe,MAAA,EAAW,GAAA,CAAI,cAAc,KAAA,CAAM,UAAA;AAC5D,MAAA,IAAI,KAAA,CAAM,QAAA,KAAa,MAAA,EAAW,GAAA,CAAI,YAAY,KAAA,CAAM,QAAA;AACxD,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAG,CAAE,IAAA,CAAK,WAAA,CAAY,QAAQ,EAAE,MAAA,CAAO,GAAA,EAAK,EAAE,UAAA,EAAY,qCAAqC,CAAA;AACvH,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,IAEA,MAAM,cAAc,EAAA,EAAI;AACtB,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAG,CAAE,IAAA,CAAK,WAAA,CAAY,QAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,EAAA,CAAG,MAAM,EAAE,CAAA;AAC5E,MAAA,IAAI,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,IAEA,MAAM,mBAAmB,MAAA,EAAQ;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAA2C;AAAA,QAC9D,MAAA,EAAQ,sBAAA;AAAA,QACR,WAAW,MAAA,EAAQ,SAAA;AAAA,QACnB,SAAS,MAAA,EAAQ;AAAA,OAClB,CAAA;AACD,MAAA,OAAO,MAAA,CAAO,UAAU,EAAC;AAAA,IAC3B,CAAA;AAAA,IAEA,MAAM,aAAa,KAAA,EAAO;AACxB,MAAA,OAAO,MAAA,CAA2B,EAAE,MAAA,EAAQ,eAAA,EAAiB,OAAO,CAAA;AAAA,IACtE;AAAA,GACF;AACF;;;AC9LO,SAAS,2BAA2B,KAAA,EAUlB;AAGvB,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAA,IAAO,IAAA,CAAK,GAAA,EAAI;AAClC,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,YAAA,IAAgB,EAAA,GAAK,GAAA;AAGhD,EAAA,MAAM,aAAA,GAAgB,KAAA,CAAM,aAAA,IAAiB,EAAA,GAAK,EAAA,GAAK,GAAA;AACvD,EAAA,MAAM,SAAsC,EAAC;AAC7C,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA;AAE3B,EAAA,IAAI,UAAU,MAAA,CAAO,MAAA,KAAW,SAAA,IAAa,MAAA,CAAO,WAAW,SAAA,EAAW;AACxE,IAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,cAAc,MAAA,EAAQ,MAAA,CAAO,OAAO,CAAA;AAAA,EAC1D;AACA,EAAA,IAAI,CAAC,MAAM,UAAA,EAAY;AACrB,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,CAAA;AAAA,EACtC,CAAA,MAAO;AACL,IAAA,MAAM,aAAa,IAAI,IAAA,CAAK,KAAA,CAAM,UAAU,EAAE,OAAA,EAAQ;AACtD,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,IAAK,UAAA,GAAa,MAAM,YAAA,EAAc;AACnE,MAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,cAAc,MAAA,EAAQ,KAAA,CAAM,YAAY,CAAA;AAAA,IAC9D;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,MAAA;AAAA,IAC7B,CAAC,YAAY,OAAA,CAAQ,QAAA,KAAa,QAAQ,SAAA,KAAc,SAAA,IAAa,QAAQ,SAAA,KAAc,eAAA;AAAA,GAC7F;AACA,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,2BAA2B,CAAA;AACzE,EAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC7B,IAAA,IAAI,CAAC,QAAQ,SAAA,IAAa,CAAC,QAAQ,UAAA,IAAc,CAAC,QAAQ,gBAAA,EAAkB;AAC1E,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,eAAA,EAAiB,QAAQ,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,gBAAA,EAAkB,CAAA;AAC1F,MAAA;AAAA,IACF;AACA,IAAA,MAAM,YAAY,IAAI,IAAA,CAAK,OAAA,CAAQ,gBAAgB,EAAE,OAAA,EAAQ;AAC7D,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,IAAK,SAAA,IAAa,MAAM,aAAA,EAAe;AACnE,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,QAAQ,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,gBAAA,EAAkB,CAAA;AAAA,IAC7F;AAAA,EACF;AAIA,EAAA,MAAMI,iBAAgB,KAAA,CAAM,aAAA;AAC5B,EAAA,MAAM,sBAAsB,CAAC,GAAG,IAAI,GAAA,CAAI,KAAA,CAAM,qBAAqB,EAAE,CAAC,CAAA,CACnE,MAAA,CAAO,OAAO,CAAA,CACd,MAAA,CAAO,CAAC,QAAA,KAAaA,cAAAA,IAAiB,aAAaA,cAAa,CAAA;AACnE,EAAA,IAAI,mBAAA,CAAoB,SAAS,CAAA,EAAG;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,mBAAA,EAAqB,QAAQ,mBAAA,CAAoB,IAAA,CAAK,IAAI,CAAA,EAAG,CAAA;AAAA,EACnF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,IAAA,KAAS,YAAY,CAAA,GACtD,OAAA,GACA,MAAA,CAAO,MAAA,GAAS,IACd,WAAA,GACA,SAAA;AAAA,IACN;AAAA,GACF;AACF;;;ACrEA,SAAS,aAAA,GAAoC;AAG3C,EAAA,OAAO,OAAO,SAAS,WAAA,GAAc,IAAA,CAAK,gBAAe,CAAE,eAAA,GAAkB,QAAA,GAAW,MAAA;AAC1F;AAGO,SAAS,uBAAuB,KAAA,EAId;AACvB,EAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAa,SAAA,EAAW,OAAO,EAAE,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAQ,EAAC,EAAE;AAC/E,EAAA,OAAO,0BAAA,CAA2B;AAAA,IAEhC,UAAA,EAAY,MAAM,WAAA,CAAY,UAAA;AAAA,IAC9B,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,eAAe,aAAA;AAAc,GAC9B,CAAA;AACH;AAMA,eAAsB,wBACpBnC,SAAAA,EACkC;AAClC,EAAA,MAAM,cAAc,MAAMA,SAAAA,CAAS,gBAAe,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AACpE,EAAA,IAAI,CAAC,aAAa,SAAA,EAAW;AAC3B,IAAA,OAAO,EAAE,WAAA,EAAa,IAAA,EAAM,IAAI,QAAA,EAAU,EAAC,EAAG,MAAA,EAAQ,EAAE,MAAA,EAAQ,cAAA,EAAgB,MAAA,EAAQ,IAAG,EAAE;AAAA,EAC/F;AACA,EAAA,MAAM,CAAC,IAAA,EAAM,QAAQ,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IACzCA,UAAS,UAAA,EAAW,CAAE,KAAA,CAAM,MAAM,EAA4B,CAAA;AAAA,IAC9DA,UAAS,YAAA,EAAa,CAAE,KAAA,CAAM,MAAM,EAAuB;AAAA,GAC5D,CAAA;AACD,EAAA,OAAO,EAAE,WAAA,EAAa,IAAA,EAAM,QAAA,EAAU,MAAA,EAAQ,sBAAA,CAAuB,EAAE,WAAA,EAAa,IAAA,EAAM,QAAA,EAAU,CAAA,EAAE;AACxG;AC1DO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAGG;AACD,EAAA,uBACEN,GAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,yEAAyE,SAAS,CAAA,CAAA;AAAA,MAC7F,KAAA,EAAO,EAAE,eAAA,EAAiB,KAAA,IAAS,8BAAA,EAA+B;AAAA,MAClE,aAAA,EAAW;AAAA;AAAA,GACb;AAEJ;ACMA,IAAM,KAAA,GAAuB,EAAE,QAAA,EAAU,EAAC,EAAG,SAAS,EAAC,EAAG,QAAA,EAAU,EAAC,EAAE;AAchE,SAAS,iBAAiB,OAAA,EAA0C;AACzE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIE,SAAwB,KAAK,CAAA;AAC3D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,KAAK,CAAA;AAE5C,EAAAC,UAAU,MAAM;AAEd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,KAAA,CAAM,YAAY;AAChB,MAAA,MAAM,SAAS,4BAAA,EAA6B;AAC5C,MAAA,MAAM,WAAWkC,iBAAAA,EAAkB;AACnC,MAAA,MAAM,iBAAiB,QAAA,GACnB,mCAAA,CAAoC,EAAE,QAAA,EAAU,CAAA,GAChD,IAAA;AAEJ,MAAA,MAAM,CAAC,QAAA,EAAU,QAAA,EAAU,OAAO,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,QACtD,MAAA,CAAO,kBAAiB,CAAE,IAAA;AAAA,UACxB,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,IAAA,EAAM,CAAA,CAAE,MAAK,CAAE,CAAA;AAAA,UACtD,MAAM;AAAC,SACT;AAAA,QAAA,CACC,OAAO,YAAA,IAAe,IAAK,QAAQ,OAAA,CAAQ,EAAE,CAAA,EAAG,IAAA;AAAA,UAC/C,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,IAAA,EAAM,CAAA,CAAE,MAAK,CAAE,CAAA;AAAA,UACtD,MAAM;AAAC,SACT;AAAA,QAAA,CACC,gBAAgB,WAAA,EAAY,IAAK,QAAQ,OAAA,CAAQ,EAAE,CAAA,EAAG,IAAA;AAAA,UACrD,CAAC,IAAA,KAAS,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,IAAA,EAAM,CAAA,CAAE,MAAK,CAAE,CAAA;AAAA,UACtD,MAAM;AAAC;AACT,OACD,CAAA;AAED,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,UAAA,CAAW,EAAE,QAAA,EAAU,OAAA,EAAS,QAAA,EAAU,CAAA;AAC1C,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB,CAAA,GAAG;AAEH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,MAAA,GACJ,OAAA,CAAQ,QAAA,CAAS,MAAA,GAAS,CAAA,IAC1B,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAA,IACzB,OAAA,CAAQ,QAAA,CAAS,MAAA,GAAS,CAAA;AAE5B,EAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,MAAA,EAAO;AACpC;AAGO,SAAS,cAAA,CACd,SACA,IAAA,EACgB;AAChB,EAAA,IAAI,IAAA,KAAS,UAAA,EAAY,OAAO,OAAA,CAAQ,QAAA;AACxC,EAAA,IAAI,IAAA,KAAS,SAAA,EAAW,OAAO,OAAA,CAAQ,OAAA;AACvC,EAAA,IAAI,IAAA,KAAS,UAAA,EAAY,OAAO,OAAA,CAAQ,QAAA;AACxC,EAAA,OAAO,EAAC;AACV;AC9DA,IAAM,gBAAA,GAAqD;AAAA,EACzD,aAAA,EAAe,SAAA;AAAA,EACf,OAAA,EAAS,aAAA;AAAA,EACT,QAAA,EAAU,aAAA;AAAA,EACV,GAAA,EAAK;AACP,CAAA;AACA,IAAM,kBAAA,GAAwD;AAAA,EAC5D,KAAA,EAAO,OAAA;AAAA,EACP,WAAA,EAAa;AACf,CAAA;AAEA,IAAM,kBAAA,GAAqF;AAAA,EACzF,MAAA,EAAQ,cAAA;AAAA,EACR,QAAA,EAAU,cAAA;AAAA,EACV,OAAA,EAAS,SAAA;AAAA,EACT,QAAA,EAAU;AACZ,CAAA;AACA,IAAM,SAAA,GAAY,UAAA;AAGlB,SAAS,cAAA,GAKP;AACA,EAAA,OAAO,EAAE,WAAW,eAAA,EAAiB,UAAA,EAAY,MAAM,QAAA,EAAU,IAAA,EAAM,YAAY,OAAA,EAAQ;AAC7F;AAEO,SAAS,kBAAA,CAAmB;AAAA,EACjC,QAAA,EAAA/B,SAAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIJ,QAAAA,CAAoC,EAAE,CAAA;AACxE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,QAAAA,CAA0C,EAAE,CAAA;AAC5E,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAwB,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAE5D,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAW,GAAI,iBAAiB,IAAI,CAAA;AAE7D,EAAA,MAAM,IAAA,GAAOwB,YAAY,YAAY;AACnC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,IAAI;AACF,MAAA,MAAM,CAAC,IAAA,EAAM,QAAQ,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,QACzCpB,UAAS,mBAAA,EAAoB;AAAA,QAC7BA,UAAS,YAAA;AAAa,OACvB,CAAA;AACD,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,MAAM,MAAuC,EAAC;AAC9C,MAAA,KAAA,MAAW,EAAA,IAAM,QAAA,EAAU,GAAA,CAAI,EAAA,CAAG,gBAAgB,CAAA,GAAI,EAAA;AACtD,MAAA,WAAA,CAAY,GAAG,CAAA;AACf,MAAA,gBAAA,GAAmB,QAAQ,CAAA;AAAA,IAC7B,SAAS,CAAA,EAAQ;AACf,MAAA,QAAA,CAAS,CAAA,EAAG,WAAW,iCAAiC,CAAA;AAAA,IAC1D,CAAA,SAAE;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB;AAAA,EACF,CAAA,EAAG,CAACA,SAAAA,EAAU,gBAAgB,CAAC,CAAA;AAE/B,EAAAH,UAAU,MAAM;AACd,IAAA,KAAK,IAAA,EAAK;AAAA,EACZ,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAGT,EAAA,MAAM,OAAA,GAAUuB,WAAAA;AAAA,IACd,OACE,KACA,KAAA,KAOG;AACH,MAAA,MAAM,QAAA,GAAW,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AAChC,MAAA,MAAM,OAAO,QAAA,IAAY,EAAE,GAAG,cAAA,EAAe,EAAG,UAAU,IAAA,EAAK;AAC/D,MAAA,WAAA,CAAY,IAAI,EAAE,CAAA;AAClB,MAAA,IAAI;AACF,QAAA,MAAMpB,UAAS,WAAA,CAAY;AAAA,UACzB,IAAI,QAAA,EAAU,EAAA;AAAA,UACd,kBAAkB,GAAA,CAAI,EAAA;AAAA,UACtB,SAAS,GAAA,CAAI,OAAA;AAAA,UACb,KAAA,EAAO,IAAI,eAAA,IAAmB,IAAA;AAAA,UAC9B,SAAA,EAAW,KAAA,CAAM,SAAA,IAAa,IAAA,CAAK,SAAA;AAAA,UACnC,YAAY,KAAA,CAAM,UAAA,KAAe,KAAA,CAAA,GAAY,KAAA,CAAM,aAAa,IAAA,CAAK,UAAA;AAAA,UACrE,UAAU,KAAA,CAAM,QAAA,KAAa,SAAY,KAAA,CAAM,QAAA,GAAW,KAAK,QAAA,IAAY,IAAA;AAAA,UAC3E,UAAA,EAAY,KAAA,CAAM,UAAA,IAAc,IAAA,CAAK,UAAA;AAAA,UACrC,UAAU,KAAA,CAAM,QAAA,KAAa,KAAA,CAAA,GAAY,KAAA,CAAM,WAAW,IAAA,CAAK;AAAA,SAChE,CAAA;AACD,QAAA,MAAM,QAAA,GAAW,MAAMA,SAAAA,CAAS,YAAA,EAAa;AAC7C,QAAA,MAAM,MAAuC,EAAC;AAC9C,QAAA,KAAA,MAAW,EAAA,IAAM,QAAA,EAAU,GAAA,CAAI,EAAA,CAAG,gBAAgB,CAAA,GAAI,EAAA;AACtD,QAAA,WAAA,CAAY,GAAG,CAAA;AACf,QAAA,gBAAA,GAAmB,QAAQ,CAAA;AAAA,MAC7B,SAAS,CAAA,EAAQ;AACf,QAAAiC,KAAAA,CAAM,KAAA,CAAM,CAAA,EAAG,OAAA,IAAW,iCAAiC,CAAA;AAAA,MAC7D,CAAA,SAAE;AACA,QAAA,WAAA,CAAY,IAAI,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAA,EAAUjC,SAAAA,EAAU,gBAAgB;AAAA,GACvC;AAEA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACEN,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gDAAA,EACb,0BAAAA,GAAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,6BAAA,EAA8B,CAAA,EACnD,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sDAAA,EACb,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,SAAA,EAAU,CAAA;AAAA,QAAE,GAAA;AAAA,QAAE;AAAA,OAAA,EACvC,CAAA;AAAA,sBACAD,IAAAA,CAACgC,MAAAA,EAAA,EAAO,SAAQ,SAAA,EAAU,IAAA,EAAK,IAAA,EAAK,SAAA,EAAU,MAAA,EAAO,OAAA,EAAS,MAAM,KAAK,MAAK,EAC5E,QAAA,EAAA;AAAA,wBAAA/B,GAAAA,CAAC,SAAA,EAAA,EAAU,SAAA,EAAU,aAAA,EAAc,CAAA;AAAA,QAAE;AAAA,OAAA,EACvC;AAAA,KAAA,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,uBACEA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,kDAAiD,QAAA,EAAA,4CAAA,EAE9D,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EACZ,QAAA,EAAA;AAAA,IAAA,SAAA,CAAU,GAAA,CAAI,CAAC,GAAA,KAAQ;AACtB,MAAA,MAAM,EAAA,GAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AAC1B,MAAA,MAAM,MAAA,GAAS,CAAC,CAAC,EAAA,EAAI,QAAA;AACrB,MAAA,MAAM,MAAA,GAAS,aAAa,GAAA,CAAI,EAAA;AAChC,MAAA,MAAM,SAAA,GAA8B,IAAI,SAAA,IAAa,eAAA;AACrD,MAAA,MAAM,UAAA,GAAgC,IAAI,UAAA,IAAc,IAAA;AACxD,MAAA,MAAM,UAAA,GAAgC,IAAI,UAAA,IAAc,OAAA;AAExD,MAAA,MAAM,SAAA,GAAY,SAAA,KAAc,SAAA,IAAa,SAAA,KAAc,eAAA;AAC3D,MAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,EAAS,UAAU,CAAA;AAEtD,MAAA,uBACEA,IAAAA,CAAC,KAAA,EAAA,EAAiB,SAAA,EAAU,qBAAA,EAC1B,QAAA,EAAA;AAAA,wBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,0BAAAC,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAS,MAAA;AAAA,cACT,QAAA,EAAU,MAAA;AAAA,cACV,QAAA,EAAU,CAAC,IAAA,KAAS,KAAK,QAAQ,GAAA,EAAK,EAAE,QAAA,EAAU,IAAA,EAAM;AAAA;AAAA,WAC1D;AAAA,0BACAA,GAAAA,CAAC,gBAAA,EAAA,EAAiB,KAAA,EAAO,IAAI,eAAA,EAAiB,CAAA;AAAA,0BAC9CA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8BAAA,EAAgC,cAAI,OAAA,EAAQ,CAAA;AAAA,UAC3D,GAAA,CAAI,2BACHA,GAAAA,CAAC,SAAM,OAAA,EAAQ,SAAA,EAAU,SAAA,EAAU,UAAA,EAAW,QAAA,EAAA,SAAA,EAE9C,CAAA;AAAA,UAED,MAAA,oBAAUA,GAAAA,CAAC,OAAA,EAAA,EAAQ,WAAU,wDAAA,EAAyD;AAAA,SAAA,EACzF,CAAA;AAAA,QAEC,MAAA,oBACCD,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,oDAAA,EAEb,QAAA,EAAA;AAAA,0BAAAA,IAAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,OAAA,EACf,QAAA,EAAA;AAAA,4BAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAgD,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,4BACzED,IAAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,KAAA,EAAO,SAAA;AAAA,gBACP,aAAA,EAAe,CAAC,CAAA,KAAM,KAAK,QAAQ,GAAA,EAAK,EAAE,SAAA,EAAW,CAAA,EAAuB,CAAA;AAAA,gBAE5E,QAAA,EAAA;AAAA,kCAAAC,IAAC,aAAA,EAAA,EAAc,SAAA,EAAU,oBACvB,QAAA,kBAAAA,GAAAA,CAAC,eAAY,CAAA,EACf,CAAA;AAAA,kCACAA,IAAC,aAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,KAAK,gBAAgB,CAAA,CAAyB,IAAI,CAAC,CAAA,qBAC1DA,GAAAA,CAAC,UAAA,EAAA,EAAmB,OAAO,CAAA,EACxB,QAAA,EAAA,gBAAA,CAAiB,CAAC,CAAA,EAAA,EADJ,CAEjB,CACD,CAAA,EACH;AAAA;AAAA;AAAA;AACF,WAAA,EACF,CAAA;AAAA,0BAGAD,IAAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,OAAA,EACf,QAAA,EAAA;AAAA,4BAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAgD,QAAA,EAAA,QAAA,EAAM,CAAA;AAAA,4BACtED,IAAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,OAAO,UAAA,IAAc,QAAA;AAAA,gBACrB,aAAA,EAAe,CAAC,CAAA,KACd,KAAK,QAAQ,GAAA,EAAK;AAAA,kBAChB,UAAA,EAAY,CAAA,KAAM,QAAA,GAAW,IAAA,GAAQ,CAAA;AAAA;AAAA,kBAErC,QAAA,EAAU;AAAA,iBACX,CAAA;AAAA,gBAGH,QAAA,EAAA;AAAA,kCAAAC,IAAC,aAAA,EAAA,EAAc,SAAA,EAAU,oBACvB,QAAA,kBAAAA,GAAAA,CAAC,eAAY,CAAA,EACf,CAAA;AAAA,kCACAA,GAAAA,CAAC,aAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,IAAA,CAAK,kBAAkB,CAAA,CAA6C,GAAA;AAAA,oBAC3E,CAAC,CAAA,qBACCA,GAAAA,CAAC,UAAA,EAAA,EAAmB,OAAO,CAAA,EACxB,QAAA,EAAA,kBAAA,CAAmB,CAAC,CAAA,EAAA,EADN,CAEjB;AAAA,mBAEJ,EACF;AAAA;AAAA;AAAA;AACF,WAAA,EACF,CAAA;AAAA,UAGC,UAAA,oBACCD,IAAAA,CAAC,OAAA,EAAA,EAAM,WAAU,OAAA,EACf,QAAA,EAAA;AAAA,4BAAAC,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EACb,QAAA,EAAA,kBAAA,CAAmB,UAAU,CAAA,EAChC,CAAA;AAAA,YACC,WAAA,CAAY,MAAA,GAAS,CAAA,mBACpBD,IAAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,KAAA,EAAO,IAAI,QAAA,IAAY,SAAA;AAAA,gBACvB,aAAA,EAAe,CAAC,CAAA,KACd,KAAK,OAAA,CAAQ,GAAA,EAAK,EAAE,QAAA,EAAU,CAAA,KAAM,SAAA,GAAY,IAAA,GAAO,CAAA,EAAG,CAAA;AAAA,gBAG5D,QAAA,EAAA;AAAA,kCAAAC,GAAAA,CAAC,iBAAc,SAAA,EAAU,kBAAA,EACvB,0BAAAA,GAAAA,CAAC,WAAA,EAAA,EAAY,WAAA,EAAY,cAAA,EAAU,CAAA,EACrC,CAAA;AAAA,kCACAA,GAAAA,CAAC,aAAA,EAAA,EACE,sBAAY,GAAA,CAAI,CAAC,sBAChBA,GAAAA,CAAC,UAAA,EAAA,EAAsB,KAAA,EAAO,EAAE,EAAA,EAC7B,QAAA,EAAA,CAAA,CAAE,QADY,CAAA,CAAE,EAEnB,CACD,CAAA,EACH;AAAA;AAAA;AAAA,gCAGFA,GAAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,YAAA,EAAc,IAAI,QAAA,IAAY,EAAA;AAAA,gBAC9B,WAAA,EAAY,MAAA;AAAA,gBACZ,MAAA,EAAQ,CAAC,CAAA,KACP,KAAK,QAAQ,GAAA,EAAK,EAAE,QAAA,EAAU,CAAA,CAAE,MAAA,CAAO,KAAA,CAAM,IAAA,EAAK,IAAK,MAAM,CAAA;AAAA,gBAE/D,SAAA,EAAU;AAAA;AAAA;AACZ,WAAA,EAEJ,CAAA;AAAA,UAID,SAAA,oBACCD,IAAAA,CAAC,OAAA,EAAA,EAAM,WAAU,OAAA,EACf,QAAA,EAAA;AAAA,4BAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAgD,QAAA,EAAA,WAAA,EAAS,CAAA;AAAA,4BACzED,IAAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,KAAA,EAAO,UAAA;AAAA,gBACP,aAAA,EAAe,CAAC,CAAA,KAAM,KAAK,QAAQ,GAAA,EAAK,EAAE,UAAA,EAAY,CAAA,EAAwB,CAAA;AAAA,gBAE9E,QAAA,EAAA;AAAA,kCAAAC,IAAC,aAAA,EAAA,EAAc,SAAA,EAAU,oBACvB,QAAA,kBAAAA,GAAAA,CAAC,eAAY,CAAA,EACf,CAAA;AAAA,kCACAA,IAAC,aAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,KAAK,kBAAkB,CAAA,CAA0B,IAAI,CAAC,CAAA,qBAC7DA,GAAAA,CAAC,UAAA,EAAA,EAAmB,OAAO,CAAA,EACxB,QAAA,EAAA,kBAAA,CAAmB,CAAC,CAAA,EAAA,EADN,CAEjB,CACD,CAAA,EACH;AAAA;AAAA;AAAA;AACF,WAAA,EACF;AAAA,SAAA,EAEJ;AAAA,OAAA,EAAA,EA7HM,IAAI,EA+Hd,CAAA;AAAA,IAEJ,CAAC,CAAA;AAAA,IACA,CAAC,UAAA,oBACAA,IAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+CAA8C,QAAA,EAAA,sGAAA,EAG3D;AAAA,GAAA,EAEJ,CAAA;AAEJ;ACxTA,SAAS,WAAW,EAAA,EAAkC;AACpD,EAAA,MAAM,KAAA,GAAQ,IAAI,IAAA,CAAK,EAAA,CAAG,QAAQ,CAAA;AAClC,EAAA,IAAI,GAAG,MAAA,EAAQ;AACb,IAAA,OAAO,KAAA,CAAM,kBAAA,CAAmB,OAAA,EAAS,EAAE,GAAA,EAAK,WAAW,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,SAAA,EAAW,CAAA;AAAA,EAC9F;AACA,EAAA,OAAO,KAAA,CAAM,eAAe,OAAA,EAAS;AAAA,IACnC,GAAA,EAAK,SAAA;AAAA,IACL,KAAA,EAAO,OAAA;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,MAAA,EAAQ;AAAA,GACT,CAAA;AACH;AAEO,SAAS,kBAAA,CAAmB;AAAA,EACjC,QAAA,EAAAM,SAAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAOG;AACD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIJ,QAAAA,CAAiC,EAAE,CAAA;AAC/D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,IAAIA,QAAAA,iBAAsB,IAAI,KAAK,CAAA;AAC/D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAS,IAAI,CAAA;AAC3C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAwB,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAoC,IAAI,CAAA;AAEpE,EAAA,MAAM,WAAA,GAAcsB,QAAQ,MAAM;AAChC,IAAA,MAAM,IAAqC,EAAC;AAC5C,IAAA,KAAA,MAAW,CAAA,IAAK,QAAA,EAAU,CAAA,CAAE,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AACpC,IAAA,OAAO,CAAA;AAAA,EACT,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,IAAA,GAAOE,YAAY,YAAY;AACnC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,SAAA,CAAU,IAAI,CAAA;AACd,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAMpB,SAAAA,CAAS,kBAAA,EAAmB;AAC/C,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,WAAA,CAAY,IAAI,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAAA,IACjD,SAAS,CAAA,EAAQ;AACf,MAAA,QAAA,CAAS,CAAA,EAAG,WAAW,gCAAgC,CAAA;AAAA,IACzD,CAAA,SAAE;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB;AAAA,EACF,CAAA,EAAG,CAACA,SAAQ,CAAC,CAAA;AAEb,EAAAH,UAAU,MAAM;AACd,IAAA,KAAK,IAAA,EAAK;AAAA,EACZ,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,MAAA,GAAS,CAAC,OAAA,KACd,WAAA,CAAY,CAAC,IAAA,KAAS;AACpB,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,IAAA,IAAI,KAAK,GAAA,CAAI,OAAO,CAAA,EAAG,IAAA,CAAK,OAAO,OAAO,CAAA;AAAA,SACrC,IAAA,CAAK,IAAI,OAAO,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAEH,EAAA,MAAM,cAAc,MAAA,CAAO,MAAA,GAAS,CAAA,IAAK,QAAA,CAAS,SAAS,MAAA,CAAO,MAAA;AAClE,EAAA,MAAM,YAAY,MAChB,WAAA,CAAY,WAAA,mBAAc,IAAI,KAAI,GAAI,IAAI,GAAA,CAAI,MAAA,CAAO,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAC,CAAC,CAAA;AAE7E,EAAA,eAAe,YAAA,GAAe;AAC5B,IAAA,MAAM,KAAA,GAAQ,OACX,MAAA,CAAO,CAAC,MAAM,QAAA,CAAS,GAAA,CAAI,EAAE,OAAO,CAAC,EACrC,GAAA,CAAI,CAAC,OAAO,EAAE,SAAA,EAAW,EAAE,SAAA,EAAW,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,CAAA;AAC9D,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACxB,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAMG,SAAAA,CAAS,YAAA,CAAa,KAAK,CAAA;AAC7C,MAAA,SAAA,CAAU,GAAG,CAAA;AACb,MAAA,UAAA,GAAa,GAAG,CAAA;AAChB,MAAAiC,KAAAA,CAAM,QAAQ,CAAA,SAAA,EAAY,GAAA,CAAI,QAAQ,CAAA,cAAA,EAAc,GAAA,CAAI,OAAO,CAAA,CAAE,CAAA;AAEjE,MAAA,MAAM,IAAA,EAAK;AAAA,IACb,SAAS,CAAA,EAAQ;AACf,MAAAA,KAAAA,CAAM,KAAA,CAAM,CAAA,EAAG,OAAA,IAAW,eAAe,CAAA;AAAA,IAC3C,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,uBACExC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6BAAA,EACb,QAAA,EAAA;AAAA,oBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EACb,QAAA,EAAA;AAAA,sBAAAC,GAAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAU,+BAAA,EAAgC,CAAA;AAAA,sBACxDA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,yBAAwB,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,sBAC1DA,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,OAAA;AAAA,UACT,SAAA,EAAU,6DAAA;AAAA,UACV,YAAA,EAAW,OAAA;AAAA,UAEX,QAAA,kBAAAA,GAAAA,CAACQ,CAAAA,EAAA,EAAE,WAAU,aAAA,EAAc;AAAA;AAAA;AAC7B,KAAA,EACF,CAAA;AAAA,IAEC,0BACCR,GAAAA,CAAC,SAAI,SAAA,EAAU,gDAAA,EACb,0BAAAA,GAAAA,CAAC0C,OAAAA,EAAA,EAAQ,SAAA,EAAU,6BAAA,EAA8B,GACnD,CAAA,GACE,KAAA,mBACF3C,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,KAAA,EACb,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8DAAA,EACb,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC2C,WAAAA,EAAA,EAAY,SAAA,EAAU,SAAA,EAAU,CAAA;AAAA,QAAE,GAAA;AAAA,QAAE;AAAA,OAAA,EACvC,CAAA;AAAA,sBACA5C,IAAAA,CAACgC,MAAAA,EAAA,EAAO,SAAQ,SAAA,EAAU,IAAA,EAAK,IAAA,EAAK,SAAA,EAAU,MAAA,EAAO,OAAA,EAAS,MAAM,KAAK,MAAK,EAC5E,QAAA,EAAA;AAAA,wBAAA/B,GAAAA,CAAC4C,SAAAA,EAAA,EAAU,SAAA,EAAU,aAAA,EAAc,CAAA;AAAA,QAAE;AAAA,OAAA,EACvC;AAAA,KAAA,EACF,CAAA,GACE,OAAO,MAAA,KAAW,CAAA,mBACpB7C,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,iCAAA,EACb,QAAA,EAAA;AAAA,sBAAAC,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qBAAA,EAAsB,QAAA,EAAA,sBAAA,EAAoB,CAAA;AAAA,sBACvDA,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,iCAAgC,QAAA,EAAA,oEAAA,EAE7C,CAAA;AAAA,MACC,MAAA,oBACCD,IAAAA,CAAC,GAAA,EAAA,EAAE,WAAU,sBAAA,EAAuB,QAAA,EAAA;AAAA,QAAA,WAAA;AAAA,QACxB,MAAA,CAAO,QAAA;AAAA,QAAS,gBAAA;AAAA,QAAY,MAAA,CAAO,OAAA;AAAA,QAC5C,MAAA,CAAO,OAAO,MAAA,GAAS,CAAA,GAAI,SAAM,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,OAAA,CAAA,GAAY;AAAA,OAAA,EACpE;AAAA,KAAA,EAEJ,CAAA,mBAEAA,IAAAA,CAAAE,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAAF,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8CAAA,EACb,QAAA,EAAA;AAAA,wBAAAC,IAAC6C,QAAAA,EAAA,EAAS,OAAA,EAAS,WAAA,EAAa,UAAU,SAAA,EAAW,CAAA;AAAA,wBACrD9C,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EACb,QAAA,EAAA;AAAA,UAAA,QAAA,CAAS,IAAA;AAAA,UAAK,MAAA;AAAA,UAAK,MAAA,CAAO,MAAA;AAAA,UAAO;AAAA,SAAA,EACpC;AAAA,OAAA,EACF,CAAA;AAAA,sBACAC,IAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0CACZ,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,EAAA,KAAO;AAClB,QAAA,MAAM,EAAA,GAAK,WAAA,CAAY,EAAA,CAAG,SAAS,CAAA;AACnC,QAAA,uBACED,IAAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YAEC,SAAA,EAAU,uEAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAAC,GAAAA;AAAA,gBAAC6C,QAAAA;AAAA,gBAAA;AAAA,kBACC,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,EAAA,CAAG,OAAO,CAAA;AAAA,kBAChC,QAAA,EAAU,MAAM,MAAA,CAAO,EAAA,CAAG,OAAO;AAAA;AAAA,eACnC;AAAA,8BACA9C,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0BAAA,EACb,QAAA,EAAA;AAAA,gCAAAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACb,QAAA,EAAA;AAAA,kCAAAC,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8BAAA,EACb,QAAA,EAAA,EAAA,CAAG,WAAW,YAAA,EACjB,CAAA;AAAA,kBACC,EAAA,CAAG,MAAA,oBACFA,GAAAA,CAAC8C,KAAAA,EAAA,EAAM,OAAA,EAAQ,WAAA,EAAY,SAAA,EAAU,UAAA,EAAW,QAAA,EAAA,SAAA,EAEhD;AAAA,iBAAA,EAEJ,CAAA;AAAA,gCACA/C,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uDAAA,EACb,QAAA,EAAA;AAAA,kCAAAC,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,UAAA,CAAW,EAAE,CAAA,EAAE,CAAA;AAAA,kCACtBD,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gCAAA,EACd,QAAA,EAAA;AAAA,oCAAAC,GAAAA,CAAC,gBAAA,EAAA,EAAiB,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,CAAA;AAAA,oBACnC,EAAA,EAAI,WAAW,EAAA,CAAG;AAAA,mBAAA,EACrB;AAAA,iBAAA,EACF;AAAA,eAAA,EACF;AAAA;AAAA,WAAA;AAAA,UAzBK,EAAA,CAAG;AAAA,SA0BV;AAAA,MAEJ,CAAC,CAAA,EACH,CAAA;AAAA,sBACAD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4CAAA,EACZ,QAAA,EAAA;AAAA,QAAA,MAAA,oBACCA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+BAAA,EAAgC,QAAA,EAAA;AAAA,UAAA,YAAA;AAAA,UACnC,MAAA,CAAO,QAAA;AAAA,UAAS,WAAA;AAAA,UAC1B,MAAA,CAAO,OAAO,MAAA,GAAS,CAAA,GAAI,KAAK,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,OAAA,CAAA,GAAY;AAAA,SAAA,EACnE,CAAA;AAAA,wBAEFA,IAAAA;AAAA,UAACgC,MAAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,IAAA;AAAA,YACL,SAAA,EAAU,SAAA;AAAA,YACV,QAAA,EAAU,SAAA,IAAa,QAAA,CAAS,IAAA,KAAS,CAAA;AAAA,YACzC,OAAA,EAAS,YAAA;AAAA,YAER,QAAA,EAAA;AAAA,cAAA,SAAA,mBACC/B,GAAAA,CAAC0C,OAAAA,EAAA,EAAQ,SAAA,EAAU,0BAAA,EAA2B,CAAA,mBAE9C1C,GAAAA,CAACmC,YAAAA,EAAA,EAAa,SAAA,EAAU,aAAA,EAAc,CAAA;AAAA,cACtC,SAAA;AAAA,cACM,QAAA,CAAS,IAAA,GAAO,CAAA,GAAI,QAAA,CAAS,IAAA,GAAO;AAAA;AAAA;AAAA;AAC9C,OAAA,EACF;AAAA,KAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ;AC1LA,IAAM,WAAW,4BAAA,EAA6B;AAEvC,IAAM,4BAAA,GAA+B,iBAAA;AAYrC,IAAM,6BAAA,GAAgC,MAC3C,qBAAA,CAAsB,4BAAA,EAA8B;AAAA,EAClD,YAAA,EAAc,CAAC,YAAY;AAC7B,CAAC,CAAA;AAGH,IAAM,aAAA,GAA+D;AAAA,EACnE,UAAA,EAAY,wCAAA;AAAA,EACZ,YAAA,EAAc,6CAAA;AAAA,EACd,UAAA,EAAY,wCAAA;AAAA,EACZ,uBAAA,EAAyB,wDAAA;AAAA,EACzB,aAAA,EAAe,sDAAA;AAAA,EACf,cAAA,EAAgB,2DAAA;AAAA,EAChB,iBAAA,EAAmB;AACrB,CAAA;AAGA,SAAS,UAAU,KAAA,EAAuD;AACxE,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,CAAM,IAAI,CAAA;AACtC,EAAA,OAAO,MAAM,MAAA,GAAS,CAAA,EAAG,KAAK,CAAA,EAAA,EAAK,KAAA,CAAM,MAAM,CAAA,CAAA,CAAA,GAAM,KAAA;AACvD;AAGA,SAAS,aAAa,MAAA,EAAkD;AACtE,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,cAAA,EAAgB,OAAO,MAAA;AAC7C,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,SAAA,EAAW,OAAO,2BAAA;AACxC,EAAA,OAAO,SAAA,CAAU,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA;AACnC;AAGA,eAAe,UAAA,GAA4C;AACzD,EAAA,OAAA,CAAQ,MAAM,uBAAA,CAAwB,QAAQ,CAAA,EAAG,MAAA;AACnD;AAGA,SAAS,gBAAgB,QAAA,EAAgD;AACvE,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAC,MAAM,CAAA,CAAE,QAAA,KAAa,EAAE,SAAA,KAAc,SAAA,IAAa,EAAE,SAAA,KAAc,eAAA;AAAA,GACrE;AACF;AAGA,IAAM,QAAA,GAAmC,CAAC,UAAA,EAAY,WAAA,EAAa,UAAU,SAAS,CAAA;AAStF,SAAS,UAAU,KAAA,EAAsC;AACvD,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,EAAA;AAAA,IACd,WAAA,EAAa,iBAAA;AAAA,IACb,SAAA,EAAW,KAAA,CAAM,SAAA,KAAc,SAAA,GAAY,SAAA,GAAY,UAAA;AAAA,IACvD,aAAa,QAAA,CAAS,QAAA,CAAS,MAAM,OAAsB,CAAA,GAAK,MAAM,OAAA,GAA0B,QAAA;AAAA,IAChG,MAAA,EAAQ,KAAA,CAAM,MAAA,KAAW,SAAA,IAAa,KAAA,CAAM,MAAA,KAAW,SAAA,IAAa,KAAA,CAAM,MAAA,KAAW,SAAA,GACjF,KAAA,CAAM,MAAA,GACN,OAAA;AAAA,IACJ,IAAI,KAAA,CAAM,EAAA;AAAA,IACV,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,KAAA,EAAO,MAAM,KAAA,IAAS,IAAA;AAAA,IACtB,WAAW,KAAA,CAAM;AAAA,GACnB;AACF;AAWA,SAAS,qBAAA,GAAwB;AAC/B,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIjC,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAS,KAAK,CAAA;AAE1C,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,KAAK,QAAA,CACF,cAAA,EAAe,CACf,IAAA,CAAK,CAAC,CAAA,KAAM;AAAE,MAAA,IAAI,CAAC,SAAA,EAAW,YAAA,CAAa,CAAC,CAAC,GAAG,SAAS,CAAA;AAAA,IAAE,CAAC,CAAA,CAC5D,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA,CACd,OAAA,CAAQ,MAAM;AAAE,MAAA,IAAI,CAAC,SAAA,EAAW,SAAA,CAAU,IAAI,CAAA;AAAA,IAAE,CAAC,CAAA;AACpD,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAA,IAAK,CAAA;AAAA,EAClC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,SAAA,EAAW,OAAO,IAAA;AAElC,EAAA,uBACEJ,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+CAAA,EAAgD,QAAA,EAAA,2JAAA,EAG7D,CAAA;AAAA,oBACAA,GAAAA,CAAC,kBAAA,EAAA,EAAmB,QAAA,EAAoB;AAAA,GAAA,EAC1C,CAAA;AAEJ;AAMA,SAAS,oBAAA,CAAqB,EAAE,OAAA,EAAS,KAAA,EAAM,EAAwC;AACrF,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIE,QAAAA,CAA4B,EAAE,CAAA;AAE9D,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,KAAK,QAAA,CACF,YAAA,EAAa,CACb,IAAA,CAAK,CAAC,EAAA,KAAO;AAAE,MAAA,IAAI,CAAC,SAAA,EAAW,WAAA,CAAY,EAAE,CAAA;AAAA,IAAE,CAAC,CAAA,CAChD,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACjB,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAA,IAAK,CAAA;AAAA,EAClC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,uBACEH,GAAAA;AAAA,IAAC,kBAAA;AAAA,IAAA;AAAA,MACC,QAAA;AAAA,MACA,QAAA,EAAU,gBAAgB,QAAQ,CAAA;AAAA,MAClC,OAAA;AAAA,MACA,UAAA,EAAY,MAAM,KAAA;AAAQ;AAAA,GAC5B;AAEJ;AAEO,IAAM,0BAAA,GAAkD;AAAA,EAC7D,EAAA,EAAI,iBAAA;AAAA,EACJ,YAAA,EAAc,QAAA;AAAA,EACd,IAAA,EAAM,iBAAA;AAAA,EACN,WAAA,EAAa,yDAAA;AAAA,EACb,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,OAAA;AAAA,EACV,QAAA,EAAU,YAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKV,SAAA,EAAW,UAAA;AAAA;AAAA;AAAA;AAAA,EAIX,MAAA,EAAQ,CAAC,MAAM,CAAA;AAAA,EACf,OAAA,EAAS,qCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYT,WAAA,EAAa;AAAA,IACX;AAAA,MACE,IAAA,EAAM,MAAA;AAAA,MACN,QAAA,EAAU,SAAA;AAAA,MACV,OAAA,EAAS,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,MACzB,MAAA,EACE,+KAAA;AAAA,MACF,SAAA,EAAW;AAAA,KACb;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,MACE,IAAA,EAAM,OAAA;AAAA,MACN,QAAA,EAAU,wBAAA;AAAA,MACV,OAAA,EAAS,CAAC,QAAQ,CAAA;AAAA,MAClB,MAAA,EAAQ;AAAA,KACV;AAAA,IACA;AAAA,MACE,IAAA,EAAM,OAAA;AAAA,MACN,QAAA,EAAU,4BAAA;AAAA,MACV,OAAA,EAAS,CAAC,QAAQ,CAAA;AAAA,MAClB,MAAA,EAAQ;AAAA,KACV;AAAA,IACA;AAAA,MACE,IAAA,EAAM,OAAA;AAAA,MACN,QAAA,EAAU,0BAAA;AAAA,MACV,OAAA,EAAS,CAAC,QAAQ,CAAA;AAAA,MAClB,MAAA,EAAQ;AAAA;AACV,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,YAAA,EAAc;AAAA,IACZ,wBAAA;AAAA,IACA,4BAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAA,EAAoB;AAAA,IAClB,EAAE,QAAA,EAAU,wBAAA,EAA0B,KAAA,EAAO,2EAAA,EAAsE;AAAA,IACnH,EAAE,QAAA,EAAU,4BAAA,EAA8B,KAAA,EAAO,sEAAA,EAAiE;AAAA,IAClH,EAAE,QAAA,EAAU,0BAAA,EAA4B,KAAA,EAAO,wEAAA;AAAsE,GACvH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,EAAW;AAAA,IACT;AAAA,MACE,GAAA,EAAK,qBAAA;AAAA,MACL,KAAA,EAAO,8FAAA;AAAA,MACP,KAAA,EAAO,MAAA;AAAA,MACP,OAAA,EAAS,UAAA;AAAA,MACT,OAAA,EAAS,CAAC,SAAS;AAAA,KACrB;AAAA,IACA;AAAA,MACE,GAAA,EAAK,sBAAA;AAAA,MACL,KAAA,EAAO,kFAAA;AAAA,MACP,KAAA,EAAO,MAAA;AAAA,MACP,OAAA,EAAS,SAAA;AAAA,MACT,OAAA,EAAS,CAAC,SAAS;AAAA;AACrB,GACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,GAAG,gBAAA;AAAA,IACD,4BAAA;AAAA,IACA,CAAC,UAAA,KAAgB,UAAA,EAAY,MAAA,GAAS,EAAE,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO,GAAI,EAAE,SAAA,EAAW,KAAA,EAAM;AAAA,IAC9F,EAAE,OAAO,6BAAA;AAA8B,GACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,SAAA,GAAY;AAChB,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,MAAM,6BAAA,EAA8B,CAAE,GAAA,EAAI;AAC7D,MAAA,IAAI,CAAC,UAAA,EAAY,MAAA,EAAQ,OAAO,EAAE,WAAW,KAAA,EAAM;AAEnD,MAAA,MAAM,MAAA,GAAS,MAAM,UAAA,EAAW;AAGhC,MAAA,OAAO;AAAA,QACL,SAAA,EAAW,IAAA;AAAA,QACX,KAAA,EAAO,MAAA;AAAA,QACP,MAAA,EAAQ,aAAa,MAAM,CAAA;AAAA,QAC3B,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,SAAS;AAAA,OACrC;AAAA,IACF,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,WAAW,KAAA,EAAM;AAAA,IAC5B;AAAA,EACF,CAAA;AAAA;AAAA;AAAA,EAGA,UAAA,EAAY,mBAAmB,4BAA4B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3D,gBAAgB,YAAY;AAI1B,IAAA,MAAM,SAAS,iBAAA,EAAkB;AACjC,IAAA,MAAM,+BAA8B,CAAE,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAM,CAAA;AAAA,EAC7D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAY,YAAY;AACtB,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,UAAA,EAAW;AAAA,IAC5B,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,6BAAA,GAAgC,UAAA,EAAW;AAAA,EACnD,CAAA;AAAA;AAAA;AAAA,EAGA,cAAA,EACE,4JAAA;AAAA,EACF,MAAM,SAAS,OAAA,EAAS;AACtB,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,UAAA,EAAW;AACtC,MAAA,MAAM,IAAA,GAAO,GAAA,CAAI,GAAA,CAAI,SAAS,CAAA;AAC9B,MAAA,OAAO,SAAS,KAAA,GAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAA,CAAQ,KAAK,CAAA,GAAI,IAAA;AAAA,IACzD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAC;AAAA,IACV;AAAA,EACF,CAAA;AAAA;AAAA,EAEA,WAAA,EAAa;AAAA,IACX;AAAA,MACE,GAAA,EAAK,UAAA;AAAA,MACL,KAAA,EAAO,mBAAA;AAAA,MACP,SAAA,EAAW,SAAA;AAAA,MACX,KAAK,YAAY;AACf,QAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,OAAA,EAAQ;AACtC,QAAA,OAAO,CAAA,oBAAA,EAAkB,OAAO,OAAO,CAAA,YAAA,CAAA;AAAA,MACzC;AAAA,KACF;AAAA,IACA;AAAA,MACE,GAAA,EAAK,eAAA;AAAA,MACL,KAAA,EAAO,0BAAA;AAAA,MACP,SAAA,EAAW,SAAA;AAAA;AAAA;AAAA,MAGX,WAAW,YAAY;AACrB,QAAA,IAAI;AACF,UAAA,OAAO,gBAAgB,MAAM,QAAA,CAAS,YAAA,EAAc,EAAE,MAAA,GAAS,CAAA;AAAA,QACjE,CAAA,CAAA,MAAQ;AACN,UAAA,OAAO,KAAA;AAAA,QACT;AAAA,MACF,CAAA;AAAA,MACA,SAAA,EAAW,oBAAA;AAAA,MACX,KAAK,YAAY;AAAA,MAAC;AAAA;AACpB,GACF;AAAA,EACA,UAAA,EAAY;AACd,CAAA;;;ACpYO,IAAM,6BAAA,GAAgC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmGtC,IAAM,wBAAA,GAA2B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAugBjC,IAAM,wBAAA,GAA2B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmRjC,IAAM,+BAAA,GAAkC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAwKxC,IAAM,qCAAA,GAAwC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAuM9C,IAAM,uCAAA,GAA0C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAyJhD,IAAM,qCAAA,GAAwC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAA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","file":"index.js","sourcesContent":["import type {\n PluginEventDefinition, MessageDefaultsDef, EventField, MessageAction,\n} from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Os FATOS da agenda, e — separadamente — o texto sugerido para cada um.\n//\n// buildAgendaDomainEvents() o contrato do fato: o que houve, que dados\n// vêm junto, se entra na auditoria. Webhook,\n// Google Agenda e auditoria leem isto.\n// buildAgendaMessageDefaults() uma REAÇÃO: canal + texto. Só as automações.\n//\n// É aqui que mora a automação que todo salão e toda clínica esperam ter no\n// primeiro dia: o lembrete de véspera. Cliente que não aparece é prejuízo\n// direto, e o lembrete é a mensagem que se paga sozinha.\n// ---------------------------------------------------------------------------\n\nconst BOOKING_FIELDS: EventField[] = [\n { name: 'customer_name', label: 'Cliente', type: 'string', example: 'Maria Silva' },\n // Para ONDE a mensagem vai — não é texto de mensagem nenhuma, é o endereço.\n // A automação de WhatsApp lê este campo (`recipientField`, padrão\n // 'customer_phone') e pula o disparo quando ele vem vazio: sem número não há\n // envio, e um evento sem ele é um lembrete que nunca sai.\n { name: 'customer_phone', label: 'Telefone do cliente', type: 'string', example: '(21) 99889-9889' },\n { name: 'service_name', label: 'Serviço', type: 'string', example: 'Corte + Escova' },\n { name: 'professional_name', label: 'Profissional', type: 'string', example: 'Camila Duarte' },\n { name: 'booking_date', label: 'Data', type: 'date', example: '12/08/2026' },\n { name: 'booking_time', label: 'Horário', type: 'string', example: '14:30' },\n { name: 'location_name', label: 'Local', type: 'string', example: 'Unidade Centro' },\n // Not in bookingPayload on purpose: the browser has no reliable source for\n // the tenant's public name, so the SENDER fills this slot (messaging-send\n // reads the tenants row). The field stays declared because templates use it\n // and the editor needs its placeholder.\n { name: 'business_name', label: 'Seu negócio', type: 'string', example: 'Seu Negócio' },\n]\n\n/**\n * Os FATOS da agenda.\n *\n * `audit: true` em todos: marcar, remarcar e cancelar um horário são ATOS de\n * alguém — e \"quem cancelou este atendimento?\" é exatamente a pergunta que a\n * trilha de auditoria existe para responder. Nenhum evento aqui é a ausência\n * de um ato: até 'no_show' é registrado por alguém da recepção.\n */\nexport function buildAgendaDomainEvents(): PluginEventDefinition[] {\n return [\n { name: 'agenda.booking_created', title: 'Agendamento criado', icon: 'CalendarPlus', audit: true,\n description: 'Um horário foi marcado',\n trigger: 'Quando o agendamento é criado (recepção, site ou app)',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_reminder', title: 'Lembrete de horário', icon: 'BellRing', audit: false,\n description: 'Véspera do atendimento',\n trigger: 'No dia anterior ao horário marcado',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_rescheduled', title: 'Horário remarcado', icon: 'CalendarClock', audit: true,\n description: 'O atendimento mudou de dia ou de hora',\n trigger: 'Quando a data ou o horário do agendamento muda',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_cancelled', title: 'Agendamento cancelado', icon: 'CalendarX', audit: true,\n description: 'O horário foi desmarcado',\n trigger: 'Quando o agendamento é cancelado',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_completed', title: 'Atendimento concluído', icon: 'CalendarCheck', audit: true,\n description: 'O atendimento aconteceu',\n trigger: 'Quando o agendamento é marcado como concluído',\n fields: BOOKING_FIELDS },\n { name: 'agenda.booking_no_show', title: 'Cliente não compareceu', icon: 'UserX', audit: true,\n description: 'O horário foi perdido',\n trigger: 'Quando o agendamento é marcado como falta',\n fields: BOOKING_FIELDS },\n ]\n}\n\n/**\n * Confirmar / Cancelar, os dois botões que resolvem a conversa inteira.\n *\n * O `id` é o que VOLTA: ele viaja no payload do botão junto com o id do\n * agendamento, e é isso que faz a resposta atualizar o horário certo. O jeito\n * antigo — casar a palavra que a cliente digitou (\"sim\", \"confirmo\") — confirmava\n * todos os horários futuros dela de uma vez, e é essa classe de bug que o botão\n * com id apaga.\n */\nconst CONFIRM_OR_CANCEL: MessageAction[] = [\n { id: 'confirm', label: 'Confirma', kind: 'reply' },\n { id: 'cancel', label: 'Cancela', kind: 'reply' },\n]\n\nexport function buildAgendaMessageDefaults(): MessageDefaultsDef[] {\n return [\n {\n eventKey: 'agenda.booking_created',\n kind: 'transactional',\n // WhatsApp na frente em toda a agenda: confirmação de horário é lida no\n // celular, e no Brasil é lá que a cliente responde.\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // Curto porque os botões dizem o resto: a linha \"qualquer coisa é só\n // chamar\" virou Confirmar/Cancelar, que além de ser menos texto já\n // atualiza o agendamento sozinho.\n // Sem botões, de propósito (decisão do founder 2026-08-24): esta é a\n // confirmação informativa de que a reserva EXISTE. Confirmar presença é\n // trabalho do lembrete de véspera, onde a resposta ainda muda o dia.\n body: 'Oi {{customer_name}}! Tudo certo — seu horário foi reservado na nossa agenda ✅\\n\\nServiço: *{{service_name}}*\\nData: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nSe precisar ajustar alguma coisa, é só responder esta mensagem.\\n\\nEquipe {{business_name}} agradece a preferência!',\n },\n email: {\n subject: 'Horário confirmado — {{booking_date}} às {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário está confirmado:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n{{location_name}}\\n\\nAté lá!\\n{{business_name}}',\n },\n },\n // Confirmar por e-mail é o mínimo que se espera de quem acabou de marcar\n // um horário — nasce ligado. O WhatsApp custa por mensagem e exige número\n // aprovado; ligá-lo sozinho gastaria o dinheiro de alguém sem ser pedido.\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_reminder',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // AQUI moram Confirma/Cancela: na véspera a resposta ainda muda o dia —\n // libera o horário ou garante a presença.\n body: 'Oi {{customer_name}}! Passando para lembrar do seu horário amanhã 💇\\n\\nServiço: *{{service_name}}*\\nData: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nConsegue vir? É só tocar em Confirma ou Cancela aqui embaixo — e se precisar de outro horário, responde esta mensagem.\\n\\nEquipe {{business_name}} te espera!',\n actions: CONFIRM_OR_CANCEL,\n },\n email: {\n subject: 'Lembrete: seu horário é amanhã, {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário é amanhã:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n{{location_name}}\\n\\nSe precisar remarcar, é só responder este e-mail.\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_rescheduled',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}! Seu horário foi remarcado 🗓\\n\\nServiço: *{{service_name}}*\\nNova data: {{booking_date}} às {{booking_time}}\\nProfissional: {{professional_name}}\\n\\nSe a nova data não funcionar para você, é só responder esta mensagem ou usar os botões abaixo.\\n\\nEquipe {{business_name}} agradece a compreensão!',\n // A data mudou, então a confirmação vale de novo: é o momento em que\n // mais gente some sem avisar.\n actions: CONFIRM_OR_CANCEL,\n },\n email: {\n subject: 'Seu horário mudou para {{booking_date}}, {{booking_time}}',\n body: 'Olá {{customer_name}},\\n\\nSeu horário foi remarcado:\\n\\n{{service_name}}\\n{{booking_date}} às {{booking_time}}\\ncom {{professional_name}}\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_cancelled',\n kind: 'transactional',\n channels: ['whatsapp', 'email'],\n defaults: {\n whatsapp: {\n // Sem botões, de propósito: não há o que confirmar num horário que já\n // foi desmarcado, e um \"Confirmar\" aqui só poderia dar erro.\n body: 'Oi {{customer_name}}, seu horário de {{booking_date}} às {{booking_time}} foi cancelado.\\n\\nQuer que eu veja outra data? A equipe {{business_name}} fica à disposição.',\n },\n email: {\n subject: 'Horário de {{booking_date}} cancelado',\n body: 'Olá {{customer_name}},\\n\\nSeu horário de {{booking_date}} às {{booking_time}} foi cancelado.\\n\\nSe quiser remarcar, é só responder este e-mail.\\n\\n{{business_name}}',\n },\n },\n defaultEnabled: { email: true },\n },\n {\n eventKey: 'agenda.booking_completed',\n kind: 'marketing',\n // Pedir opinião é iniciativa do negócio, não resposta a um ato da\n // pessoa — e é por isso que nasce desligado.\n channels: ['whatsapp'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}! Foi ótimo te atender hoje 💛\\n\\nComo foi a experiência com {{professional_name}}? Sua opinião ajuda demais a equipe {{business_name}} a melhorar sempre.',\n },\n },\n },\n {\n eventKey: 'agenda.booking_no_show',\n kind: 'transactional',\n channels: ['whatsapp'],\n defaults: {\n whatsapp: {\n body: 'Oi {{customer_name}}, senti sua falta no horário de {{booking_date}} 😔\\n\\nAconteceu alguma coisa? Se quiser, já deixo outro horário separado para você aqui na {{business_name}}, é só responder.',\n },\n },\n },\n ]\n}\n","import type { PluginRegistryDef, PluginScope, VerticalId } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport type { AgendaDataProvider } from './data/types'\nimport type { StatusConfig, BookingTypeConfig } from './types'\nimport type { AgendaFinancialBridge } from './bridges/financial-bridge'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Public options interface\n// ---------------------------------------------------------------------------\n\nexport interface AgendaPluginLabels {\n pageTitle: string\n pageSubtitle: string\n calendar: string\n dayView: string\n weekView: string\n monthView: string\n listView: string\n workingHours: string\n confirmations: string\n newAppointment: string\n filters: string\n}\n\nexport interface ConfirmationChannelOption {\n id: string\n label: string\n icon: string\n}\n\nexport interface CancellationReasonOption {\n id: string\n label: string\n requiresNotes?: boolean\n}\n\nexport interface CancellationDetailsProvider {\n listReasons(): Promise<CancellationReasonOption[]>\n saveCancellationDetails(input: {\n bookingId: string\n reasonId: string\n notes?: string\n cancelledAt?: string\n }): Promise<void>\n}\n\nexport interface ExternalBookingSource {\n type: string\n id?: string\n [key: string]: unknown\n}\n\nexport interface LocationOption {\n id: string\n name: string\n isHQ?: boolean\n}\n\nexport interface AgendaPluginOptions {\n modules?: {\n workingHours?: boolean\n confirmations?: boolean\n conflictDetection?: boolean\n dragAndDrop?: boolean\n locationSelection?: boolean\n /** Enable financial integration (auto-enabled when financialBridge is provided) */\n financial?: boolean\n }\n labels?: Partial<AgendaPluginLabels>\n currency?: { code?: string; locale?: string; symbol?: string }\n\n /** Booking kind used in public.appointments.kind (default: 'appointment') */\n bookingKind?: string\n\n /** Order kind for financial records (default: 'service_order') */\n orderKind?: string\n\n /** Schedule kind in public.schedules.kind (default: 'working_hours') */\n scheduleKind?: string\n\n /** Booking type tabs shown in the appointment modal */\n bookingTypes?: BookingTypeConfig[]\n\n /**\n * Simplifies the agenda to Google-Calendar-style events (no client /\n * professional / service). When set to 'simple', the plugin exposes a single\n * \"Evento\" booking type whose modal shows only title / date-time / notes.\n * Ignored when an explicit `bookingTypes` override is provided.\n */\n eventMode?: 'simple'\n\n /** Booking status options */\n statuses?: StatusConfig[]\n\n /** Default calendar view (default: 'resourceTimeGridWeek'). Options: 'dayGridMonth', 'timeGridWeek', 'resourceTimeGridWeek', 'listWeek' */\n defaultCalendarView?: string\n\n /** Calendar visible time range (default: '07:00'-'21:00') */\n businessHours?: { startTime: string; endTime: string }\n\n /** Slot duration in minutes (default: 30) */\n slotDuration?: number\n\n /** Person kind for professionals (default: 'staff') */\n professionalKind?: string\n\n /** Person kind for clients (default: 'customer') */\n clientKind?: string\n\n /** Auto-create an order when creating a booking (default: true) */\n autoCreateOrder?: boolean\n\n /** Contact/client lookup */\n contactLookup?: EntityLookup\n\n /** Client entity definition for the Client tab in booking modal */\n clientEntityDef?: EntityDef\n\n /** Service lookup */\n serviceLookup?: EntityLookup\n\n /** Professional/staff lookup */\n professionalLookup?: EntityLookup\n\n /** Location lookup */\n locationLookup?: EntityLookup\n\n /** Called when user clicks a selected entity link (e.g. view client profile) */\n onEntityClick?: (type: 'client' | 'service' | 'professional', id: string) => void\n\n /** Business locations for unit filtering */\n locations?: LocationOption[]\n\n /** Confirmation channel options */\n confirmationChannels?: ConfirmationChannelOption[]\n\n /** Optional app/plugin bridge for cancel-time reason capture. */\n cancellationDetails?: CancellationDetailsProvider\n\n /** Called after a booking is created from an external operational source. */\n onBookingCreated?: (input: { bookingId: string; source?: ExternalBookingSource }) => void | Promise<void>\n\n /** App-owned registries shown under /settings/agenda Properties. */\n settingsRegistries?: PluginRegistryDef[]\n\n /** Financial bridge for agenda × financial cross-plugin integration */\n financialBridge?: AgendaFinancialBridge\n\n /** Data provider — defaults to Supabase, falls back to mock */\n dataProvider?: AgendaDataProvider\n\n /** Default values for schedule block advanced settings */\n scheduleBlockDefaults?: {\n bufferMinutes?: number\n maxConcurrent?: number\n minAdvanceHours?: number\n maxAdvanceDays?: number\n }\n\n navPosition?: number\n navSection?: 'main' | 'secondary'\n /**\n * Mostra o Check-in como entrada própria, logo abaixo da Agenda.\n *\n * Opt-in porque é uma tela de RECEPÇÃO: um salão e uma clínica recebem gente\n * na porta o dia inteiro; uma agenda de reuniões internas não recebe\n * ninguém, e a entrada só ocuparia espaço no menu.\n */\n checkin?: boolean\n /** O que \"Receber\" faz. Quem tem o modal de recebimento é o host. */\n onCheckinReceive?: (booking: { id: string; orderId: string | null; clientName: string | null }) => void\n scope?: PluginScope\n verticalId?: VerticalId\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: AgendaPluginLabels = {\n pageTitle: 'Agenda',\n pageSubtitle: 'Calendar and appointment management',\n calendar: 'Calendar',\n dayView: 'Day',\n weekView: 'Week',\n monthView: 'Month',\n listView: 'Agenda',\n workingHours: 'Working Hours',\n confirmations: 'Confirmations',\n newAppointment: 'New Appointment',\n filters: 'Filters',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\nconst DEFAULT_STATUSES: StatusConfig[] = [\n { value: 'scheduled', label: 'Scheduled', color: '#6366f1' },\n { value: 'confirmed', label: 'Confirmed', color: '#3b82f6' },\n { value: 'waiting', label: 'Waiting', color: '#f97316', availableWhen: 'today_only' },\n { value: 'in_progress', label: 'In Progress', color: '#f59e0b', availableWhen: 'today_only' },\n { value: 'completed', label: 'Completed', color: '#10b981', availableWhen: 'today_or_past' },\n { value: 'cancelled', label: 'Cancelled', color: '#ef4444' },\n { value: 'no_show', label: 'No Show', color: '#6b7280', availableWhen: 'today_or_past' },\n]\n\nfunction withCheckinStatus(statuses: StatusConfig[], checkin?: boolean): StatusConfig[] {\n if (!checkin || statuses.some((s) => s.value === 'waiting')) return statuses\n const at = statuses.findIndex((s) => s.value === 'in_progress')\n const waiting: StatusConfig = {\n value: 'waiting', label: 'Waiting', color: '#f97316', availableWhen: 'today_only',\n }\n if (at < 0) return [...statuses, waiting]\n return [...statuses.slice(0, at), waiting, ...statuses.slice(at)]\n}\n\nconst DEFAULT_BOOKING_TYPES: BookingTypeConfig[] = [\n {\n id: 'appointment', label: 'Appointment', icon: 'Calendar', color: '#6366f1',\n fields: { client: true, professional: true, services: true, location: true, status: true },\n requiresServices: true, requiresClient: true,\n },\n {\n id: 'task', label: 'Task', icon: 'CheckSquare', color: '#f59e0b',\n fields: { client: false, professional: true, services: false, location: false, status: true },\n requiresServices: false, requiresClient: false,\n },\n {\n id: 'block', label: 'Block', icon: 'Ban', color: '#6b7280',\n fields: { client: false, professional: true, services: false, location: false, status: false },\n requiresServices: false, requiresClient: false,\n },\n]\n\n// Simple / Google-Calendar-style event — a single \"Evento\" type with just a\n// free-text title, date-time and notes. No client / professional / service.\n// Used by personal-finance-style agendas (see eventMode: 'simple').\nconst SIMPLE_EVENT_BOOKING_TYPES: BookingTypeConfig[] = [\n {\n id: 'event', label: 'Event', icon: 'Calendar', color: '#6366f1',\n fields: { title: true, client: false, professional: false, services: false, location: false, status: false },\n requiresServices: false, requiresClient: false,\n },\n]\n\n// ---------------------------------------------------------------------------\n// Resolved config — fully merged, no optionals\n// ---------------------------------------------------------------------------\n\nexport interface AgendaModules {\n workingHours: boolean\n confirmations: boolean\n conflictDetection: boolean\n dragAndDrop: boolean\n locationSelection: boolean\n financial: boolean\n}\n\n/**\n * Derived UI capabilities — computed ONCE in resolveConfig from the resolved\n * bookingTypes so no component ever re-derives \"is this a simple event agenda?\"\n * ad-hoc. A capability is enabled when ANY booking type uses that field. In\n * eventMode:'simple' the single \"Evento\" type disables\n * client/professional/services/location/status, so every consumer (popover,\n * filter rail, modal) hides the professional/service/status machinery in one\n * place instead of scattering `eventMode === 'simple'` checks.\n */\nexport interface AgendaCapabilities {\n title: boolean\n client: boolean\n professional: boolean\n services: boolean\n location: boolean\n status: boolean\n}\n\nexport interface AgendaCurrency {\n code: string\n locale: string\n symbol: string\n}\n\nexport interface ResolvedAgendaConfig {\n modules: AgendaModules\n /** Whether this is a simple Google-Calendar-style event agenda (eventMode:'simple'). */\n simpleMode: boolean\n /** Derived once from bookingTypes — see AgendaCapabilities. */\n capabilities: AgendaCapabilities\n labels: AgendaPluginLabels\n currency: AgendaCurrency\n bookingKind: string\n orderKind: string\n scheduleKind: string\n statuses: StatusConfig[]\n bookingTypes: BookingTypeConfig[]\n businessHours: { startTime: string; endTime: string }\n slotDuration: number\n professionalKind: string\n clientKind: string\n autoCreateOrder: boolean\n locations: LocationOption[]\n confirmationChannels: ConfirmationChannelOption[]\n cancellationDetails?: CancellationDetailsProvider\n onBookingCreated?: (input: { bookingId: string; source?: ExternalBookingSource }) => void | Promise<void>\n contactLookup?: EntityLookup\n clientEntityDef?: EntityDef\n serviceLookup?: EntityLookup\n professionalLookup?: EntityLookup\n locationLookup?: EntityLookup\n onEntityClick?: (type: 'client' | 'service' | 'professional', id: string) => void\n financialBridge?: AgendaFinancialBridge\n scheduleBlockDefaults: {\n bufferMinutes: number\n maxConcurrent: number\n minAdvanceHours: number\n maxAdvanceDays: number\n }\n defaultCalendarView: string\n}\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nexport function resolveConfig(options?: AgendaPluginOptions): ResolvedAgendaConfig {\n // ── eventMode:'simple' derives ALL module + capability defaults ONCE, here. ──\n // Simple = Google-Calendar-style events (title/description + timestamp). It\n // flips professional/service machinery OFF by default: no working-hours /\n // schedule checks, no confirmations outreach, no conflict (double-booking)\n // detection, no location. Explicit `modules.*` re-enable individually. Full\n // mode (beauty) is unchanged — every default below matches the old behavior\n // when `simple` is false. Field-level machinery (client/professional/\n // services/location/status/title) is derived into `capabilities` from the\n // resolved bookingTypes, so components never test eventMode themselves.\n const simple = options?.eventMode === 'simple'\n const bookingTypes = options?.bookingTypes\n ?? (simple ? SIMPLE_EVENT_BOOKING_TYPES : DEFAULT_BOOKING_TYPES)\n const capabilities: AgendaCapabilities = {\n title: bookingTypes.some((bt) => bt.fields.title === true),\n client: bookingTypes.some((bt) => bt.fields.client),\n professional: bookingTypes.some((bt) => bt.fields.professional),\n services: bookingTypes.some((bt) => bt.fields.services),\n location: bookingTypes.some((bt) => bt.fields.location),\n status: bookingTypes.some((bt) => bt.fields.status),\n }\n return {\n modules: {\n // Off-unless-explicit in simple mode (`?? !simple`); default-on in full.\n workingHours: options?.modules?.workingHours ?? !simple,\n confirmations: options?.modules?.confirmations ?? !simple,\n conflictDetection: options?.modules?.conflictDetection ?? !simple,\n dragAndDrop: options?.modules?.dragAndDrop !== false,\n locationSelection: options?.modules?.locationSelection === true,\n financial: options?.modules?.financial ?? !!options?.financialBridge,\n },\n simpleMode: simple,\n capabilities,\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n bookingKind: options?.bookingKind ?? 'appointment',\n orderKind: options?.orderKind ?? 'service_order',\n scheduleKind: options?.scheduleKind ?? 'working_hours',\n // Check-in WRITES `waiting`, so enabling check-in has to declare it. An app\n // that passes its own `statuses` (most do) would otherwise be missing the\n // one status the feature produces — the calendar cannot colour or select it,\n // and the checked-in client drops out of the very queue meant to track them.\n statuses: withCheckinStatus(options?.statuses ?? DEFAULT_STATUSES, options?.checkin),\n bookingTypes,\n businessHours: options?.businessHours ?? { startTime: '07:00', endTime: '21:00' },\n slotDuration: options?.slotDuration ?? 30,\n professionalKind: options?.professionalKind ?? 'staff',\n clientKind: options?.clientKind ?? 'customer',\n autoCreateOrder: options?.autoCreateOrder !== false,\n locations: options?.locations ?? [],\n confirmationChannels: options?.confirmationChannels ?? [],\n cancellationDetails: options?.cancellationDetails,\n onBookingCreated: options?.onBookingCreated,\n contactLookup: options?.contactLookup,\n clientEntityDef: options?.clientEntityDef,\n serviceLookup: options?.serviceLookup,\n professionalLookup: options?.professionalLookup,\n locationLookup: options?.locationLookup,\n onEntityClick: options?.onEntityClick,\n financialBridge: options?.financialBridge,\n scheduleBlockDefaults: {\n bufferMinutes: options?.scheduleBlockDefaults?.bufferMinutes ?? 0,\n maxConcurrent: options?.scheduleBlockDefaults?.maxConcurrent ?? 1,\n minAdvanceHours: options?.scheduleBlockDefaults?.minAdvanceHours ?? 0,\n maxAdvanceDays: options?.scheduleBlockDefaults?.maxAdvanceDays ?? 60,\n },\n defaultCalendarView: options?.defaultCalendarView ?? 'resourceTimeGridWeek',\n }\n}\n","import { createPluginContext } from '@fayz-ai/admin'\nimport type { ResolvedAgendaConfig } from './config'\nimport type { AgendaDataProvider } from './data/types'\nimport type { AgendaUIState } from './store'\n\nconst ctx = createPluginContext<ResolvedAgendaConfig, AgendaDataProvider, AgendaUIState>('AgendaPage')\n\nexport const AgendaContextProvider = ctx.ContextProvider\nexport const useAgendaConfig = ctx.useConfig\nexport const useAgendaProvider = ctx.useProvider\nexport const useAgendaStore = ctx.useStore\n","/**\n * Injects agenda calendar CSS at runtime.\n * This ensures styles work both in symlinked dev mode and when consumed\n * as a built package (where CSS side-effect imports are extracted by tsup\n * and not automatically loaded).\n */\n\nconst STYLE_ID = 'saas-agenda-calendar-styles'\n\nconst css = /* css */ `\n/* Dark mode content background — uses the content token */\n.dark .agenda-calendar,\n.dark .agenda-calendar .fc,\n.dark .agenda-calendar .fc-view-harness,\n.dark .agenda-calendar .fc-timegrid,\n.dark .agenda-calendar .fc-scrollgrid,\n.dark .agenda-calendar .fc-timegrid-col,\n.dark .agenda-calendar .fc-daygrid-body,\n.dark .agenda-calendar .fc-timegrid-slot-lane {\n background-color: hsl(var(--content));\n}\n\n/* FullCalendar — Google Calendar inspired theme */\n\n.agenda-calendar {\n --fc-border-color: hsl(var(--border));\n --fc-today-bg-color: transparent;\n --fc-now-indicator-color: hsl(var(--destructive));\n --fc-highlight-color: hsl(var(--primary) / 0.06);\n --fc-non-business-color: hsl(var(--muted) / 0.15);\n --fc-neutral-bg-color: transparent;\n --fc-page-bg-color: transparent;\n --fc-event-border-color: transparent;\n}\n\n.agenda-calendar .fc {\n font-family: inherit;\n background: transparent;\n}\n\n.agenda-calendar .fc .fc-view-harness {\n background: transparent;\n}\n\n/* ── Column headers ── */\n.agenda-calendar .fc-col-header-cell {\n background: transparent;\n border-bottom: 1px solid var(--fc-border-color);\n border-left: none;\n border-right: none;\n border-top: none;\n}\n\n.agenda-calendar .fc-col-header-cell-cushion {\n padding: 8px 4px;\n font-weight: 400;\n font-size: 0.7rem;\n color: hsl(var(--muted-foreground));\n text-decoration: none;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n/* Today's column header */\n.agenda-calendar .fc-day-today .fc-col-header-cell-cushion {\n color: hsl(var(--primary));\n font-weight: 600;\n}\n\n/* Resource header (professional columns) */\n.agenda-calendar .fc .fc-resource-header {\n background: transparent;\n border-bottom: 1px solid var(--fc-border-color);\n}\n\n/* ── Time slots — compact ── */\n.agenda-calendar .fc-timegrid-slot {\n height: 1.5rem;\n border-bottom: 1px solid hsl(var(--border) / 0.4);\n}\n\n.agenda-calendar .fc-timegrid-slot-label {\n vertical-align: top;\n border: none;\n}\n\n.agenda-calendar .fc-timegrid-slot-label-cushion {\n font-size: 0.65rem;\n color: hsl(var(--muted-foreground) / 0.7);\n padding: 1px 8px 0 0;\n}\n\n/* Half-hour lines lighter */\n.agenda-calendar .fc-timegrid-slot-minor {\n border-bottom-style: none;\n}\n\n/* Column dividers */\n.agenda-calendar .fc-timegrid-col {\n border-right: 1px solid hsl(var(--border) / 0.5);\n}\n\n/* ── Events ── */\n.agenda-calendar .fc-event {\n border-radius: 6px;\n border-width: 0;\n border-left: 4px solid;\n cursor: pointer;\n transition: opacity 0.15s, box-shadow 0.15s, backdrop-filter 0.15s;\n font-size: 0.7rem;\n line-height: 1.3;\n margin: 0 2px;\n overflow: hidden;\n backdrop-filter: blur(8px) saturate(140%);\n -webkit-backdrop-filter: blur(8px) saturate(140%);\n}\n\n.agenda-calendar .fc-event .fc-event-main {\n background: inherit;\n border-radius: inherit;\n overflow: hidden;\n}\n\n.agenda-calendar .fc-event:not(.fc-bg-event):hover {\n opacity: 0.92;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n backdrop-filter: blur(12px) saturate(160%);\n -webkit-backdrop-filter: blur(12px) saturate(160%);\n}\n\n.agenda-calendar .fc-bg-event {\n pointer-events: none;\n}\n\n/* ── Now indicator ── */\n.agenda-calendar .fc-timegrid-now-indicator-line {\n border-color: hsl(var(--destructive));\n border-width: 2px;\n}\n\n.agenda-calendar .fc-timegrid-now-indicator-arrow {\n border-top-color: hsl(var(--destructive));\n}\n\n/* ── Month view ── */\n.agenda-calendar .fc-daygrid-day-number {\n font-size: 0.8rem;\n padding: 4px 8px;\n text-decoration: none;\n color: hsl(var(--foreground));\n}\n\n.agenda-calendar .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {\n background-color: hsl(var(--primary));\n color: hsl(var(--primary-foreground));\n border-radius: 50%;\n width: 1.5rem;\n height: 1.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n}\n\n/* ── Selection ── */\n.agenda-calendar .fc-highlight {\n background: hsl(var(--primary) / 0.08);\n}\n\n/* ── Links ── */\n.agenda-calendar .fc a {\n text-decoration: none;\n color: inherit;\n}\n\n/* ── Scrollbar ── */\n.agenda-calendar .fc-scroller {\n scrollbar-width: thin;\n scrollbar-color: hsl(var(--muted-foreground) / 0.12) transparent;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar {\n width: 6px;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.agenda-calendar .fc-scroller::-webkit-scrollbar-thumb {\n background: hsl(var(--muted-foreground) / 0.12);\n border-radius: 3px;\n}\n\n/* ── Clean up borders ── */\n.agenda-calendar .fc .fc-timegrid {\n border: none;\n}\n\n.agenda-calendar .fc-scrollgrid {\n border: none !important;\n}\n\n.agenda-calendar .fc-scrollgrid td:last-child {\n border-right: none;\n}\n\n/* ── Unavailable time background — opaque/disabled feel ── */\n.agenda-calendar .fc-unavailable-bg {\n background: hsl(var(--muted-foreground) / 0.08) !important;\n background-image: repeating-linear-gradient(\n 45deg,\n transparent,\n transparent 4px,\n hsl(var(--muted-foreground) / 0.04) 4px,\n hsl(var(--muted-foreground) / 0.04) 8px\n ) !important;\n border-radius: 0;\n border-left: none !important;\n}\n\n/* ── Location label on schedule blocks ── */\n.agenda-calendar .fc-location-label {\n background: transparent !important;\n border: none !important;\n border-left-width: 0 !important;\n cursor: default !important;\n pointer-events: none;\n box-shadow: none !important;\n z-index: 1 !important;\n margin: 0 4px !important;\n font-weight: 500 !important;\n}\n\n.agenda-calendar .fc-location-label .fc-event-main {\n padding: 0 !important;\n}\n\n/* Week view day header with date */\n.agenda-calendar .fc-timegrid .fc-col-header-cell {\n padding: 4px 0;\n}\n\n/* ── Alternating resource column backgrounds ── */\n.agenda-calendar .fc-resource-alt {\n background-color: hsl(var(--muted) / 0.4) !important;\n}\n\n.dark .agenda-calendar .fc-resource-alt {\n background-color: hsl(var(--muted-foreground) / 0.08) !important;\n}\n\n/* Resource group header separator — stronger border between professionals */\n.agenda-calendar .fc-resource-group {\n border-left: 2px solid hsl(var(--border));\n}\n\n/* Also stripe the resource header label for the alt group */\n.agenda-calendar th.fc-resource-alt {\n background-color: hsl(var(--muted) / 0.4) !important;\n}\n\n.dark .agenda-calendar th.fc-resource-alt {\n background-color: hsl(var(--muted-foreground) / 0.06) !important;\n}\n`\n\nlet injected = false\n\nexport function injectCalendarStyles(): void {\n if (injected) return\n if (typeof document === 'undefined') return\n\n // Check if already present (e.g. from CSS import in dev mode)\n if (document.getElementById(STYLE_ID)) {\n injected = true\n return\n }\n\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = css\n document.head.appendChild(style)\n injected = true\n}\n","import { usePluginPrefs } from '@fayz-ai/admin'\n\nconst DEFAULTS = {\n startTime: '07:00',\n endTime: '21:00',\n}\n\nexport function useAgendaSettings() {\n const prefs = usePluginPrefs('agenda', DEFAULTS)\n\n return {\n startTime: prefs.get('startTime'),\n endTime: prefs.get('endTime'),\n setStartTime: (v: string) => prefs.set('startTime', v),\n setEndTime: (v: string) => prefs.set('endTime', v),\n }\n}\n","import React from 'react'\nimport { FilterSection, FilterCheckRow, FilterCheckList } from '@fayz-ai/ui'\nimport type { StatusConfig } from '../types'\n\n// ---------------------------------------------------------------------------\n// The left rail's shared parts.\n//\n// Agenda and Check-in are neighbouring tabs over the same bookings, and each\n// had grown its own filter column: one said \"Agendado\", the other \"Agendada\";\n// one painted the checkbox in the status colour, the other a grey box with a\n// dot beside it. Two vocabularies for one thing makes switching tabs a\n// re-learning exercise.\n//\n// The rail's LOOK now lives in @fayz-ai/ui — Reservas is a third screen with\n// the same column, and a design that only exists inside plugin-agenda is a\n// design the neighbours copy by eye. What stays here is the agenda's own\n// plumbing: the professional picker's search.\n// ---------------------------------------------------------------------------\n\nexport { FilterSection, FilterCheckList }\n\n/**\n * The status filter. Nothing selected means everything — the boxes draw checked\n * when the list is empty, because that is what the screen is showing.\n *\n * The box itself carries the status colour, so the filter doubles as the legend\n * for the rows and badges beside it.\n */\nexport function StatusFilterList({\n statuses, selected, onToggle,\n}: {\n statuses: ReadonlyArray<StatusConfig>\n selected: readonly string[]\n onToggle: (value: string) => void\n}) {\n return (\n <>\n {statuses.map((st) => (\n <FilterCheckRow\n key={st.value}\n option={{ value: st.value, label: st.label, color: st.color }}\n checked={selected.length === 0 || selected.includes(st.value)}\n onToggle={() => onToggle(st.value)}\n />\n ))}\n </>\n )\n}\n\n/** The professional filter — same row, with the box in the app's primary\n * instead of a per-row colour, because an agenda has no colour of its own.\n *\n * A BUSCA NÃO É ENFEITE. Uma clínica tem seis agendas e rolar resolve; uma\n * rede de franquia tem centenas, e aí a lista deixa de ser um filtro e vira um\n * obstáculo — 739 caixinhas para achar a Paula. Acima de `maxRows` a caixa de\n * busca aparece e a lista passa a mostrar só o que casa, com a conta do que\n * ficou de fora para que \"não achei\" nunca seja confundido com \"não existe\". */\nexport function ProfessionalFilterList({\n names, selected, onToggle,\n search, onSearchChange, searchPlaceholder, maxRows = 40, footer,\n}: {\n /** `{ id, label }` — the agenda keys by id, the check-in queue by name. */\n names: ReadonlyArray<{ id: string; label: string }>\n selected: readonly string[]\n onToggle: (id: string) => void\n /** Presente ⇒ a busca é controlada por quem chama (e pode ir ao servidor). */\n search?: string\n onSearchChange?: (value: string) => void\n searchPlaceholder?: string\n /** Quantos nomes desenhar. Acima disto a busca é o caminho. */\n maxRows?: number\n /** Linha final de quem chama — \"buscando no servidor\", por exemplo. */\n footer?: React.ReactNode\n}) {\n const searchable = onSearchChange !== undefined && (names.length > maxRows || Boolean(search))\n const term = (search ?? '').trim().toLowerCase()\n // Filtrar aqui também quando quem chama já filtrou no servidor não custa nada\n // e evita o piscar entre a tecla e a resposta.\n const matches = term ? names.filter((n) => n.label.toLowerCase().includes(term)) : names\n const shown = matches.slice(0, maxRows)\n const hidden = matches.length - shown.length\n\n return (\n <>\n {searchable && (\n <input\n type=\"search\"\n value={search ?? ''}\n onChange={(e) => onSearchChange?.(e.target.value)}\n placeholder={searchPlaceholder}\n className=\"mb-1.5 w-full rounded-md border border-border bg-background px-2 py-1 text-xs outline-none focus:border-primary\"\n />\n )}\n {shown.map((item) => (\n <FilterCheckRow\n key={item.id}\n option={{ value: item.id, label: item.label }}\n checked={selected.length === 0 || selected.includes(item.id)}\n onToggle={() => onToggle(item.id)}\n />\n ))}\n {matches.length === 0 && (\n <p className=\"px-1 py-1 text-xs text-muted-foreground\">—</p>\n )}\n {hidden > 0 && (\n <p className=\"px-1 py-1 text-[11px] text-muted-foreground\">+{hidden}</p>\n )}\n {footer}\n </>\n )\n}\n","import React, { useState, useEffect } from 'react'\nimport { createPortal } from 'react-dom'\nimport { X, Check, Banknote, QrCode, CreditCard, ArrowRightLeft, FileCheck, ExternalLink } from 'lucide-react'\nimport { useAgendaConfig } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { BookingPaymentDetail } from '../bridges/financial-bridge'\n\n// ---------------------------------------------------------------------------\n// Payment method type visuals (mirrors financial PaymentModal)\n// ---------------------------------------------------------------------------\n\nconst TYPE_ICONS: Record<string, React.ElementType> = {\n cash: Banknote, pix: QrCode, credit_card: CreditCard, debit_card: CreditCard,\n bank_transfer: ArrowRightLeft, check: FileCheck,\n}\n\nconst TYPE_COLORS: Record<string, string> = {\n cash: 'border-success/30 bg-success/5 hover:bg-success/10 data-[active=true]:border-success data-[active=true]:bg-success/15',\n pix: 'border-teal-500/30 bg-teal-500/5 hover:bg-teal-500/10 data-[active=true]:border-teal-500 data-[active=true]:bg-teal-500/15',\n credit_card: 'border-info/30 bg-info/5 hover:bg-info/10 data-[active=true]:border-info data-[active=true]:bg-info/15',\n debit_card: 'border-magic/30 bg-magic/5 hover:bg-magic/10 data-[active=true]:border-magic data-[active=true]:bg-magic/15',\n bank_transfer: 'border-warning/30 bg-warning/5 hover:bg-warning/10 data-[active=true]:border-warning data-[active=true]:bg-warning/15',\n check: 'border-input/30 bg-muted/5 hover:bg-muted/10 data-[active=true]:border-input data-[active=true]:bg-muted/15',\n}\n\nconst ICON_COLORS: Record<string, string> = {\n cash: 'text-success', pix: 'text-teal-500', credit_card: 'text-info',\n debit_card: 'text-magic', bank_transfer: 'text-warning', check: 'text-muted-foreground',\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\ninterface Props {\n orderId: string\n orderTotal: number\n services?: Array<{ name: string; price: number; durationMinutes: number }>\n onClose: () => void\n onPaymentChange?: () => void\n formatCurrency: (amount: number) => string\n /** Render inline (no portal overlay) — for embedding in tabs */\n inline?: boolean\n}\n\nexport function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPaymentChange, formatCurrency, inline }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const bridge = config.financialBridge!\n\n const [visible, setVisible] = useState(false)\n const [loading, setLoading] = useState(true)\n const [detail, setDetail] = useState<BookingPaymentDetail | null>(null)\n\n // Payment form\n const [selectedTypeId, setSelectedTypeId] = useState('')\n const [paymentTypes, setPaymentTypes] = useState<Array<{ id: string; name: string; transactionType?: string }>>([])\n const [bankAccounts, setBankAccounts] = useState<Array<{ id: string; name: string; accountType: string }>>([])\n const [filteredMethods, setFilteredMethods] = useState<Array<{ id: string; name: string }>>([])\n const [selectedBankId, setSelectedBankId] = useState('')\n const [paymentMethodId, setPaymentMethodId] = useState('')\n const [cardBrand, setCardBrand] = useState('')\n const [cardInstallments, setCardInstallments] = useState(1)\n const [processing, setProcessing] = useState(false)\n const [justPaid, setJustPaid] = useState(false)\n\n useEffect(() => { requestAnimationFrame(() => setVisible(true)) }, [])\n\n // Single combined fetch for all initial data\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n Promise.all([\n bridge.getPaymentDetail(orderId).catch(() => null),\n bridge.getPaymentMethodTypes().catch(() => [] as typeof paymentTypes),\n bridge.getBankAccounts().catch(() => [] as typeof bankAccounts),\n ]).then(([d, types, accounts]) => {\n if (cancelled) return\n setDetail(d)\n setPaymentTypes(types)\n setBankAccounts(accounts)\n setLoading(false)\n })\n return () => { cancelled = true }\n }, [orderId])\n\n function handleClose() {\n setVisible(false)\n setTimeout(onClose, 200)\n }\n\n const selectedType = paymentTypes.find((t) => t.id === selectedTypeId)\n const txType = selectedType?.transactionType ?? ''\n const needsBank = ['bank_transfer', 'pix', 'check'].includes(txType)\n const needsCard = txType === 'credit_card' || txType === 'debit_card'\n const needsCardInstallments = txType === 'credit_card'\n\n function handleSelectType(typeId: string) {\n setSelectedTypeId(typeId)\n setSelectedBankId('')\n setPaymentMethodId('')\n setCardBrand('')\n setCardInstallments(1)\n // Fetch specific payment methods for this type\n if (bridge.getPaymentMethods) {\n bridge.getPaymentMethods(typeId).then(setFilteredMethods).catch(() => setFilteredMethods([]))\n }\n }\n\n async function handleCheckout() {\n if (!selectedTypeId) return\n setProcessing(true)\n try {\n const result = await bridge.checkout(orderId, {\n paymentMethodTypeId: selectedTypeId,\n paymentMethodId: paymentMethodId || undefined,\n bankAccountId: needsBank ? selectedBankId || undefined : undefined,\n cardBrand: needsCard ? cardBrand || undefined : undefined,\n cardInstallments: needsCardInstallments ? cardInstallments : undefined,\n })\n setDetail(result)\n setJustPaid(true)\n onPaymentChange?.()\n // Show confirmation animation, then transition to summary\n setTimeout(() => setJustPaid(false), 2200)\n } catch { /* toast */ }\n setProcessing(false)\n }\n\n const isPaid = detail?.status === 'paid'\n\n const content = (\n <div className=\"px-5 py-4 space-y-4\">\n\n {/* Loading */}\n {loading && (\n <div className=\"space-y-3 py-2\">\n {[...Array(3)].map((_, i) => (\n <div key={i} className=\"h-8 rounded-lg bg-muted animate-pulse\" />\n ))}\n </div>\n )}\n\n {/* Just paid — confirmation animation */}\n {!loading && isPaid && justPaid && (\n <div className=\"text-center py-8 space-y-2 animate-in fade-in zoom-in-95 duration-300\">\n <div className=\"flex h-14 w-14 mx-auto items-center justify-center rounded-full bg-success/10 animate-bounce\" style={{ animationDuration: '600ms', animationIterationCount: '2' }}>\n <Check className=\"h-7 w-7 text-success\" />\n </div>\n <p className=\"text-sm font-semibold text-success\">{t('agenda.payment.checkoutComplete')}</p>\n <p className=\"text-xs text-muted-foreground\">{formatCurrency(detail!.totalAmount)}</p>\n </div>\n )}\n\n {/* Invoice summary — shown after animation or when returning to an already-paid/pending booking */}\n {!loading && detail && detail.status !== 'none' && !justPaid && (\n <div className=\"space-y-3 animate-in fade-in duration-300\">\n {/* Movement rows with inline status badge */}\n {detail.movements.length > 0 ? (\n <div className=\"space-y-1.5\">\n {detail.movements.map((mov) => {\n const methodName = mov.paymentMethodTypeName\n const txKey = (methodName ?? '').toLowerCase().replace(/\\s+/g, '_')\n const Icon = TYPE_ICONS[txKey] ?? Banknote\n const iconColor = ICON_COLORS[txKey] ?? 'text-muted-foreground'\n const isMovPaid = mov.status === 'paid'\n const isPartial = mov.status === 'partial'\n const isOverdue = mov.status === 'overdue'\n\n return (\n <div key={mov.id} className=\"flex items-center gap-3 rounded-lg border px-3 py-2.5\">\n <Icon className={`h-4 w-4 shrink-0 ${isMovPaid ? iconColor : 'text-muted-foreground'}`} />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">\n {methodName ?? '—'}\n {mov.cardBrand ? ` · ${mov.cardBrand}` : ''}\n {mov.cardInstallments && mov.cardInstallments > 1 ? ` ${mov.cardInstallments}x` : ''}\n </p>\n <p className=\"text-[10px] text-muted-foreground\">\n {mov.paymentDate ?? mov.dueDate}\n {detail.movements.length > 1 && mov.installmentNumber ? ` · ${t('agenda.payment.installment')} ${mov.installmentNumber}` : ''}\n </p>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n {isMovPaid && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-[10px] font-medium text-success\">\n <Check className=\"h-2.5 w-2.5\" /> {t('agenda.payment.paid')}\n </span>\n )}\n {isPartial && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-warning/10 px-2 py-0.5 text-[10px] font-medium text-warning\">\n ! {formatCurrency(mov.paidAmount)}/{formatCurrency(mov.amount)}\n </span>\n )}\n {isOverdue && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-destructive/10 px-2 py-0.5 text-[10px] font-medium text-destructive\">\n ! {t('agenda.payment.overdue')}\n </span>\n )}\n {mov.status === 'pending' && (\n <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground\">\n {t('agenda.payment.pending')}\n </span>\n )}\n <span className=\"text-sm font-semibold\">{formatCurrency(mov.paidAmount || mov.amount)}</span>\n </div>\n </div>\n )\n })}\n </div>\n ) : (\n <div className=\"flex items-center justify-between text-sm px-1\">\n <span className=\"text-muted-foreground\">{t('agenda.payment.total')}</span>\n <span className=\"font-semibold\">{formatCurrency(detail.totalAmount)}</span>\n </div>\n )}\n\n {/* Invoice ref + link */}\n <div className=\"flex items-center justify-between\">\n {detail.referenceNumber && (\n <span className=\"text-[10px] font-mono text-muted-foreground\">#{detail.referenceNumber}</span>\n )}\n <a\n href={`#/financial/receivables/detail/${detail.invoiceId}`}\n className=\"inline-flex items-center gap-1.5 text-xs font-medium text-primary hover:underline ml-auto\"\n >\n {t('agenda.payment.viewInvoice')}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n </div>\n )}\n\n {/* Checkout view — only when no invoice exists yet */}\n {!loading && (!detail || detail.movements.length === 0) && (\n <>\n {/* Service summary */}\n {services && services.length > 0 && (\n <div>\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.payment.serviceSummary')}</p>\n <div className=\"space-y-0.5\">\n {services.map((svc, i) => (\n <div key={i} className=\"flex items-center justify-between text-sm py-1\">\n <span className=\"truncate\">{svc.name}</span>\n <span className=\"shrink-0 text-muted-foreground\">{formatCurrency(svc.price)}</span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Total */}\n <div className=\"flex items-center justify-between text-sm font-semibold pt-2 border-t\">\n <span>{t('agenda.payment.total')}</span>\n <span>{formatCurrency(orderTotal)}</span>\n </div>\n\n {/* Payment method grid */}\n <div>\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.payment.paymentMethod')}</p>\n {paymentTypes.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-input bg-muted/30 px-3 py-3 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('agenda.payment.noMethods')}</p>\n <a href=\"#/financial/settings\" className=\"mt-1.5 inline-block text-xs font-medium text-primary hover:underline\">\n {t('agenda.payment.configureMethods')} →\n </a>\n </div>\n ) : (\n <div className=\"grid grid-cols-3 gap-1.5\">\n {paymentTypes.map((pt) => {\n const ptTx = pt.transactionType ?? pt.name.toLowerCase().replace(/\\s+/g, '_')\n const Icon = TYPE_ICONS[ptTx] ?? Banknote\n const colorClass = TYPE_COLORS[ptTx] ?? TYPE_COLORS.cash\n const iconColor = ICON_COLORS[ptTx] ?? ICON_COLORS.cash\n const isActive = selectedTypeId === pt.id\n return (\n <button\n key={pt.id}\n type=\"button\"\n data-active={isActive}\n onClick={() => handleSelectType(pt.id)}\n className={`flex flex-col items-center gap-1 rounded-lg border p-2.5 text-[10px] font-medium transition-all ${colorClass}`}\n >\n <Icon className={`h-4 w-4 ${iconColor}`} />\n <span className=\"truncate w-full text-center\">{pt.name}</span>\n </button>\n )\n })}\n </div>\n )}\n </div>\n\n {/* Extra fields based on payment type */}\n {selectedTypeId && (\n <div className=\"space-y-3\">\n {/* Specific payment method (filtered by type) */}\n {filteredMethods.length > 0 && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">\n {needsCard ? t('agenda.payment.card') : t('agenda.payment.method')}\n </label>\n <select value={paymentMethodId} onChange={(e) => setPaymentMethodId(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.select')}</option>\n {filteredMethods.map((m) => <option key={m.id} value={m.id}>{m.name}</option>)}\n </select>\n </div>\n )}\n\n {/* Card brand + installments */}\n {needsCard && (\n <div className={`grid gap-2.5 ${needsCardInstallments ? 'grid-cols-2' : 'grid-cols-1'}`}>\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.cardBrand')}</label>\n <select value={cardBrand} onChange={(e) => setCardBrand(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.selectBrand')}</option>\n {['Visa', 'Mastercard', 'American Express', 'Elo', 'Hipercard', 'Diners Club'].map((b) => (\n <option key={b} value={b}>{b}</option>\n ))}\n </select>\n </div>\n {needsCardInstallments && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.cardInstallments')}</label>\n <select value={cardInstallments} onChange={(e) => setCardInstallments(Number(e.target.value))}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n {Array.from({ length: 12 }, (_, i) => i + 1).map((n) => (\n <option key={n} value={n}>{n}x {n > 1 ? formatCurrency(orderTotal / n) : ''}</option>\n ))}\n </select>\n </div>\n )}\n </div>\n )}\n\n {/* Bank account */}\n {needsBank && bankAccounts.length > 0 && (\n <div>\n <label className=\"text-[11px] font-medium text-muted-foreground\">{t('agenda.payment.bankAccount')}</label>\n <select value={selectedBankId} onChange={(e) => setSelectedBankId(e.target.value)}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\">\n <option value=\"\">{t('agenda.payment.selectAccount')}</option>\n {bankAccounts.map((a) => (\n <option key={a.id} value={a.id}>{a.name}</option>\n ))}\n </select>\n </div>\n )}\n </div>\n )}\n\n {/* Confirm button */}\n <button\n type=\"button\"\n onClick={handleCheckout}\n disabled={processing || !selectedTypeId}\n className=\"w-full rounded-lg bg-primary border border-primary py-2.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\"\n >\n {processing\n ? t('agenda.payment.checkingOut')\n : `${t('agenda.payment.checkout')} ${formatCurrency(orderTotal)}`\n }\n </button>\n </>\n )}\n </div>\n )\n\n if (inline) return content\n\n return createPortal(\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center transition-colors duration-200\"\n style={{ backgroundColor: visible ? 'rgba(0,0,0,0.5)' : 'rgba(0,0,0,0)' }}\n onClick={handleClose}\n >\n <div\n className=\"w-full max-w-md rounded-modal border bg-card shadow-2xl mx-4 transition-all duration-200 max-h-[90vh] overflow-y-auto\"\n style={{ opacity: visible ? 1 : 0, transform: visible ? 'scale(1) translateY(0)' : 'scale(0.95) translateY(8px)' }}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between px-5 py-4 border-b sticky top-0 bg-card z-10\">\n <h3 className=\"text-base font-semibold\">{t('agenda.payment.title')}</h3>\n <button onClick={handleClose} className=\"p-1 text-muted-foreground hover:text-foreground transition-colors\">\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n {content}\n </div>\n </div>,\n document.body,\n )\n}\n","// ---------------------------------------------------------------------------\n// Agenda Plugin — Pure TypeScript types\n// Zero dependencies. Maps to public archetype tables.\n// ---------------------------------------------------------------------------\n\n// ============================================================\n// ENUMS / LITERALS\n// ============================================================\n\n/** Booking status lifecycle */\nexport type BookingStatus =\n | 'scheduled'\n | 'confirmed'\n // The client is here and has not sat down yet. What check-in produces, and\n // the reception's most-used fact: who already arrived (agenda 003).\n | 'waiting'\n | 'in_progress'\n | 'completed'\n | 'cancelled'\n | 'no_show'\n\n/** Confirmation outreach status */\nexport type ConfirmationStatus = 'pending' | 'sent' | 'confirmed' | 'declined'\n\n/** Booking type identifier — extensible via string literal union */\nexport type BookingTypeId = 'appointment' | 'task' | 'out_of_office' | 'block' | (string & {})\n\n/** Configuration for a booking type (event type) */\nexport interface BookingTypeConfig {\n id: BookingTypeId\n label: string\n icon: string\n color: string\n fields: {\n /** Free-text event title (maps to the booking's display name). Used by\n * simple / Google-Calendar-style events that have no client party. */\n title?: boolean\n client: boolean\n professional: boolean\n services: boolean\n location: boolean\n status: boolean\n }\n requiresServices: boolean\n requiresClient: boolean\n}\n\n// ============================================================\n// CORE ENTITIES\n// ============================================================\n\n/** A booking service line item (from public.appointment_items) */\nexport interface BookingService {\n id: string\n serviceId: string | null\n name: string\n durationMinutes: number\n price: number\n assigneeId: string | null\n}\n\n/** Calendar booking — the main entity rendered on the calendar (from v_appointments view on orders) */\nexport interface CalendarBooking {\n id: string\n tenantId: string\n kind: string\n /** Lifecycle stage: booked, invoiced, paid, etc. */\n stage?: string\n /** Financial direction: credit, debit, null */\n direction?: string | null\n startsAt: string\n endsAt: string | null\n status: BookingStatus\n notes: string | null\n /** In unified model, orderId === id (the booking IS the order) */\n orderId: string | null\n locationId: string | null\n metadata: Record<string, unknown>\n\n // Client (party)\n clientId: string | null\n clientName: string | null\n clientPhone: string | null\n clientEmail: string | null\n clientAvatarUrl: string | null\n\n // Professional (assignee)\n professionalId: string | null\n professionalName: string | null\n professionalAvatarUrl: string | null\n\n // Location\n locationName: string | null\n\n // Order totals\n orderTotal: number | null\n orderStatus: string | null\n /** Quando a pessoa CHEGOU (005). `updatedAt` não serve: qualquer edição o reescreve. */\n checkedInAt?: string | null\n /** Payment status from financial bridge (enriched at runtime) */\n paymentStatus?: import('./bridges/financial-bridge').BookingPaymentStatus\n\n // Aggregated services\n services: BookingService[] | null\n totalDurationMinutes: number | null\n\n createdAt: string\n updatedAt: string\n}\n\n/** Professional / staff resource for the calendar */\nexport interface Professional {\n id: string\n name: string\n avatarUrl: string | null\n locationId: string | null\n locationName: string | null\n isActive: boolean\n}\n\n/**\n * O recorte da lista de agendas. Existe porque numa rede a lista NÃO cabe: o\n * quadro inteiro mora em `people`, e a agenda desenha uma coluna por linha que\n * volta. Sem `search` não há como achar um nome entre centenas; sem `limit` a\n * grade tenta desenhar todos.\n */\nexport interface ProfessionalQuery {\n /** Trecho do nome. */\n search?: string\n /** Sobrepõe a unidade ativa. Ausente = a unidade em que a tela está. */\n unitId?: string\n /** Teto de linhas. */\n limit?: number\n}\n\n/** Working hours schedule (from public.schedules) */\nexport interface Schedule {\n id: string\n tenantId: string\n kind: string\n assigneeId: string | null\n locationId: string | null\n dayOfWeek: number | null\n specificDate: string | null\n startsAt: string\n endsAt: string\n isActive: boolean\n metadata: Record<string, unknown>\n}\n\n/** Available time slot */\nexport interface TimeSlot {\n start: string\n end: string\n}\n\n/** Confirmation record stored in booking metadata */\nexport interface ConfirmationRecord {\n channel: string\n sentAt: string\n status: ConfirmationStatus\n confirmedAt?: string\n}\n\n// ============================================================\n// STATUS CONFIGURATION\n// ============================================================\n\n/**\n * When a status is available for selection relative to the booking date.\n * - 'always' — any date (e.g. scheduled, confirmed, cancelled)\n * - 'today_or_past' — booking is today or earlier (e.g. completed, no_show)\n * - 'today_only' — booking is today (e.g. in_progress)\n */\nexport type StatusAvailability = 'always' | 'today_or_past' | 'today_only'\n\nexport interface StatusConfig {\n value: string\n label: string\n color: string\n /** When this status can be selected (default: 'always') */\n availableWhen?: StatusAvailability\n}\n\n/** Check if a status is available for a given booking date */\nexport function isStatusAvailable(status: StatusConfig, bookingStartsAt: string): boolean {\n const when = status.availableWhen ?? 'always'\n if (when === 'always') return true\n const bookingDate = bookingStartsAt.slice(0, 10)\n const today = new Date().toISOString().slice(0, 10)\n if (when === 'today_or_past') return bookingDate <= today\n if (when === 'today_only') return bookingDate === today\n return true\n}\n\n// ============================================================\n// MODAL TAB EXTENSION\n// ============================================================\n\n/** Props passed to every booking modal tab component */\nexport interface BookingModalTabProps {\n bookingId?: string\n clientId: string\n orderId: string | null\n services: Array<{ name: string; price: number; durationMinutes: number }>\n formatCurrency: (amount: number) => string\n onDataChange?: () => void\n}\n\n/** A tab registered in the booking edit modal */\nexport interface BookingModalTab {\n id: string\n label: string\n icon: string\n order: number\n component: React.ComponentType<BookingModalTabProps>\n visible?: (ctx: { mode: 'create' | 'edit'; clientId?: string; orderId?: string }) => boolean\n}\n\n// ============================================================\n// INPUT TYPES (create / mutate)\n// ============================================================\n\nexport interface CreateBookingInput {\n kind?: BookingTypeId\n clientId: string\n professionalId: string\n locationId?: string\n startsAt: string\n notes?: string\n /** Free-text event title for simple events (no client party). Maps to the\n * booking's display name (clientName in the read model). */\n title?: string\n services: CreateBookingServiceInput[]\n}\n\nexport interface CreateBookingServiceInput {\n serviceId: string\n name: string\n durationMinutes: number\n price: number\n assigneeId?: string\n}\n\nexport interface UpdateBookingInput {\n clientId?: string\n professionalId?: string\n locationId?: string\n startsAt?: string\n endsAt?: string\n status?: BookingStatus\n notes?: string\n /** Free-text event title for simple events (no client party). */\n title?: string\n services?: CreateBookingServiceInput[]\n}\n\nexport interface SaveScheduleInput {\n assigneeId: string\n locationId?: string\n dayOfWeek?: number\n specificDate?: string\n startsAt: string\n endsAt: string\n isActive?: boolean\n metadata?: Record<string, unknown>\n}\n\n// ============================================================\n// QUERY / FILTER TYPES\n// ============================================================\n\nexport interface BookingQuery {\n dateRange: { start: string; end: string }\n professionalIds?: string[]\n locationId?: string\n statuses?: string[]\n kind?: string\n}\n\nexport interface ConflictCheckParams {\n assigneeId: string\n startsAt: string\n endsAt: string\n excludeBookingId?: string\n}\n\nexport interface AvailableSlotsParams {\n assigneeId: string\n date: string\n durationMinutes: number\n slotInterval?: number\n}\n","import React, { useState, useEffect, useMemo, useRef } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Clock, AlertTriangle, X, User, Briefcase, FileText, CircleDot, Plus, MapPin, Calendar, DollarSign, CheckSquare, Ban, Check, HandCoins } from 'lucide-react'\n\nconst BOOKING_TYPE_ICONS: Record<string, React.ElementType> = {\n Calendar, CheckSquare, Ban,\n}\nimport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@fayz-ai/ui'\nimport { cn } from '@fayz-ai/ui'\nimport { SearchCombobox, type ComboboxOption } from '@fayz-ai/ui'\nimport { ContactPicker, RightRailPage } from '@fayz-ai/admin'\nimport { BookingPaymentPanel } from './BookingPaymentPanel'\nimport { CrudDetailPage } from '@fayz-ai/admin'\nimport { CrudFormPage } from '@fayz-ai/admin'\nimport { useLimitGuard, invalidateLimit, useLookupCreate } from '@fayz-ai/admin'\nimport { Button } from '@fayz-ai/ui'\nimport { useAgendaConfig, useAgendaProvider, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { getCurrentLocale } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CreateBookingInput, BookingTypeId } from '../types'\nimport type { ExternalBookingSource } from '../config'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction fmtCurrency(amount: number, locale: string, code: string): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(amount)\n}\n\nfunction formatCompactDate(dateStr: string, locale: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n return d.toLocaleDateString(locale === 'pt-BR' ? 'pt-BR' : 'en-US', {\n weekday: 'short', month: 'short', day: 'numeric',\n })\n}\n\ninterface ServiceItem { serviceId: string; name: string; durationMinutes: number; price: number }\ninterface CancellationReasonItem { id: string; label: string; requiresNotes?: boolean }\n\n// ---------------------------------------------------------------------------\n// Inline editable number — allows clearing, commits on blur/enter\n// ---------------------------------------------------------------------------\n\nfunction InlineNumber({ value, onChange, min = 0, step = 1, className, disabled, tooltip }: {\n value: number; onChange: (v: number) => void; min?: number; step?: number\n className?: string; disabled?: boolean; tooltip?: string\n}) {\n const [draft, setDraft] = useState(String(value))\n const [focused, setFocused] = useState(false)\n\n useEffect(() => { if (!focused) setDraft(String(value)) }, [value, focused])\n\n function commit() {\n setFocused(false)\n const v = parseFloat(draft)\n if (!isNaN(v) && v >= min) {\n onChange(v)\n } else {\n setDraft(String(value))\n }\n }\n\n const input = (\n <input\n type=\"text\"\n inputMode=\"decimal\"\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onFocus={(e) => { setFocused(true); e.target.select() }}\n onBlur={commit}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); commit() } }}\n disabled={disabled}\n className={cn(\n 'text-right text-[11px] text-muted-foreground bg-transparent border-b border-transparent hover:border-muted-foreground/40 focus:border-foreground focus:outline-none tabular-nums',\n className,\n )}\n />\n )\n\n if (!tooltip) return input\n\n return (\n <TooltipProvider delayDuration={400}>\n <Tooltip>\n <TooltipTrigger asChild>{input}</TooltipTrigger>\n <TooltipContent side=\"top\" className=\"text-xs\">{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Custom Status Select\n// ---------------------------------------------------------------------------\n\nfunction StatusSelect({ value, onChange, statuses, bookingDate }: {\n value: string; onChange: (v: string) => void\n statuses: Array<{ value: string; label: string; color: string; availableWhen?: string }>\n bookingDate?: string\n}) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const dropdownRef = useRef<HTMLDivElement>(null)\n const current = statuses.find((s) => s.value === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => {\n const target = e.target as Node\n if (ref.current?.contains(target)) return\n if (dropdownRef.current?.contains(target)) return\n setOpen(false)\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n const btnRef = useRef<HTMLButtonElement>(null)\n const [dropRect, setDropRect] = useState<DOMRect | null>(null)\n\n function handleOpen() {\n if (btnRef.current) setDropRect(btnRef.current.getBoundingClientRect())\n setOpen((p) => !p)\n }\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button ref={btnRef} type=\"button\" onClick={handleOpen}\n className=\"flex items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left w-full\">\n {current && <>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: current.color }} />\n <span>{current.label}</span>\n </>}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && dropRect && createPortal(\n <div ref={dropdownRef} data-modal-passthrough style={{ position: 'fixed', left: dropRect.left, top: dropRect.bottom + 4, width: dropRect.width, zIndex: 9999, pointerEvents: 'auto' }}\n className=\"fayz-glass-surface rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100\">\n {statuses.map((s: any) => {\n const available = !bookingDate || isStatusAvailable(s as any, bookingDate)\n return (\n <button key={s.value} type=\"button\" disabled={!available}\n onClick={() => { if (available) { onChange(s.value); setOpen(false) } }}\n className={`flex w-full items-center gap-2.5 px-3 py-1.5 text-sm transition-colors ${\n !available ? 'opacity-30 cursor-not-allowed' : s.value === value ? 'bg-muted/30' : 'hover:bg-muted/50'\n }`}>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: s.color }} />\n <span>{s.label}</span>\n </button>\n )\n })}\n </div>,\n document.body,\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Professional Select — compact inline dropdown with initials\n// ---------------------------------------------------------------------------\n\nfunction ProfessionalSelect({ value, onChange, professionals }: {\n value: string; onChange: (v: string) => void\n professionals: Array<{ id: string; name: string }>\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = professionals.find((p) => p.id === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left\">\n {current ? (\n <span>{current.name}</span>\n ) : (\n <span className=\"text-muted-foreground\">{t('agenda.appointment.selectProfessional')}</span>\n )}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 right-0 z-50 mt-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100\">\n {professionals.map((p: any) => (\n <button key={p.id} type=\"button\"\n onClick={() => { onChange(p.id); setOpen(false) }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50 transition-colors ${p.id === value ? 'bg-muted/30' : ''}`}>\n <span>{p.name}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Location Select — compact inline dropdown\n// ---------------------------------------------------------------------------\n\nfunction LocationSelect({ value, onChange, locations }: {\n value: string; onChange: (v: string) => void\n locations: Array<{ id: string; name: string }>\n}) {\n const t = useTranslation()\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = locations.find((l) => l.id === value)\n\n useEffect(() => {\n if (!open) return\n const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative flex-1\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-muted/30 transition-colors text-left\">\n {current ? (\n <span>{current.name}</span>\n ) : (\n <span className=\"text-muted-foreground\">{t('agenda.appointment.selectLocation')}</span>\n )}\n <svg className=\"ml-auto h-3 w-3 text-muted-foreground shrink-0\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute top-full left-0 right-0 z-50 mt-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100 max-h-48 overflow-y-auto\">\n {locations.map((l: any) => (\n <button key={l.id} type=\"button\"\n onClick={() => { onChange(l.id); setOpen(false) }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50 transition-colors ${l.id === value ? 'bg-muted/30' : ''}`}>\n <span>{l.name}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Appointment Modal — Google Calendar-inspired compact layout\n// ---------------------------------------------------------------------------\n\ninterface Props {\n open: boolean\n mode: 'create' | 'edit'\n bookingId?: string\n prefill?: Partial<CreateBookingInput> & { endsAt?: string }\n initialTab?: string\n externalSource?: ExternalBookingSource\n onClose: () => void\n onCreated?: (bookingId: string, source?: ExternalBookingSource) => void\n}\n\nexport function AppointmentModal({ open, mode, bookingId, prefill, initialTab, externalSource, onClose, onCreated }: Props) {\n const t = useTranslation()\n const locale = getCurrentLocale()\n const config = useAgendaConfig()\n const provider = useAgendaProvider()\n const initialSnapshot = useRef<string>('')\n const createBooking = useAgendaStore((s) => s.createBooking)\n const guardBookings = useLimitGuard('bookings_month')\n const updateBooking = useAgendaStore((s) => s.updateBooking)\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const fetchBookings = useAgendaStore((s) => s.fetchBookings)\n const agendaDateRange = useAgendaStore((s) => s.dateRange)\n const professionals = useAgendaStore((s) => s.professionals)\n const storeLocations = useAgendaStore((s) => s.locations)\n\n // --- State ---\n // Default to the first configured booking type (e.g. 'event' in simple mode,\n // 'appointment' otherwise) so single-type agendas resolve their type cleanly.\n const defaultBookingType = (config.bookingTypes[0]?.id ?? 'appointment') as BookingTypeId\n const [loading, setLoading] = useState(mode === 'edit')\n const [bookingType, setBookingType] = useState<BookingTypeId>(prefill?.kind ?? defaultBookingType)\n const [title, setTitle] = useState('')\n const [clientId, setClientId] = useState(prefill?.clientId ?? '')\n const [clientSearch, setClientSearch] = useState('')\n const [clientPhone, setClientPhone] = useState('')\n const [professionalId, setProfessionalId] = useState(prefill?.professionalId ?? '')\n const [locationId, setLocationId] = useState(prefill?.locationId ?? '')\n const [services, setServices] = useState<ServiceItem[]>([])\n const [serviceSearch, setServiceSearch] = useState('')\n const [date, setDate] = useState(() => {\n if (prefill?.startsAt) return prefill.startsAt.slice(0, 10)\n return new Date().toISOString().slice(0, 10)\n })\n const [startTime, setStartTime] = useState(() => {\n if (prefill?.startsAt) {\n const d = new Date(prefill.startsAt)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n }\n return '09:00'\n })\n const [status, setStatus] = useState('scheduled')\n const [notes, setNotes] = useState('')\n const [showNotes, setShowNotes] = useState(false)\n const [saving, setSaving] = useState(false)\n const [conflict, setConflict] = useState(false)\n // Client search/quick-create state now lives inside <ContactPicker>.\n const [serviceOptions, setServiceOptions] = useState<ComboboxOption[]>([])\n const [initialServiceOptions, setInitialServiceOptions] = useState<ComboboxOption[]>([])\n const [editingDate, setEditingDate] = useState(false)\n const [editingTime, setEditingTime] = useState(false)\n const [confirmingDelete, setConfirmingDelete] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [editOrderId, setEditOrderId] = useState<string | null>(null)\n const [editOrderTotal, setEditOrderTotal] = useState(0)\n const [editPaymentStatus, setEditPaymentStatus] = useState<import('../bridges/financial-bridge').BookingPaymentStatus>('none')\n const [paymentStatusLoading, setPaymentStatusLoading] = useState(false)\n const [modalTab, setModalTab] = useState<'appointment' | 'client' | 'financial'>('appointment')\n const [clientData, setClientData] = useState<Record<string, any> | null>(null)\n const [clientDataLoading, setClientDataLoading] = useState(false)\n const [clientEditing, setClientEditing] = useState(false)\n const [cancellationReasons, setCancellationReasons] = useState<CancellationReasonItem[]>([])\n const [cancellationReasonId, setCancellationReasonId] = useState('')\n const [cancellationNotes, setCancellationNotes] = useState('')\n const [cancellationReasonsLoading, setCancellationReasonsLoading] = useState(false)\n\n // Active booking type config\n const activeType = config.bookingTypes.find((bt) => bt.id === bookingType) ?? config.bookingTypes[0]\n\n // What was asked for, not merely whether something is asked for. The dialog\n // covered the calendar, so \"opened\" and \"opened with a new slot\" were the\n // same event; beside the calendar you can pick a second slot while the first\n // is still on screen, and keying the reset on `open` alone would leave the\n // old date and time in a form the new click was supposed to have started.\n const requestKey = [\n mode, bookingId ?? '', initialTab ?? '',\n prefill?.startsAt ?? '', prefill?.endsAt ?? '',\n prefill?.professionalId ?? '', prefill?.locationId ?? '',\n prefill?.clientId ?? '', prefill?.kind ?? '',\n ].join('|')\n\n // Reset form when modal opens\n useEffect(() => {\n if (!open) return\n setClientId(prefill?.clientId ?? ''); setClientSearch(''); setClientPhone('')\n setProfessionalId(prefill?.professionalId ?? ''); setLocationId(prefill?.locationId ?? ''); setServices([])\n setServiceSearch(''); setNotes(''); setStatus('scheduled'); setShowNotes(false)\n setConflict(false); setLoading(mode === 'edit')\n setBookingType(prefill?.kind ?? defaultBookingType); setTitle('')\n setEditingDate(false); setEditingTime(false); setConfirmingDelete(false); setDeleting(false)\n setEditOrderId(null); setEditOrderTotal(0); setEditPaymentStatus('none'); setPaymentStatusLoading(false)\n setClientData(null); setClientDataLoading(false); setClientEditing(false)\n setCancellationReasonId(''); setCancellationNotes(''); setCancellationReasonsLoading(false)\n setModalTab((initialTab as 'appointment' | 'client' | 'financial') || 'appointment')\n if (!prefill?.professionalId && professionals.length === 1) setProfessionalId(professionals[0].id)\n setDate(() => {\n if (prefill?.startsAt) return prefill.startsAt.slice(0, 10)\n return new Date().toISOString().slice(0, 10)\n })\n setStartTime(() => {\n if (prefill?.startsAt) {\n const d = new Date(prefill.startsAt)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n }\n return '09:00'\n })\n }, [open, requestKey])\n\n // Um lugar só não é uma escolha. Standing numa unidade, `getLocations`\n // devolve essa unidade e mais nada, e pedir um clique para confirmar o óbvio\n // é o campo cobrando atenção sem dar informação.\n //\n // Efeito próprio e não uma linha no reset: as unidades chegam por rede e\n // podem aterrissar DEPOIS do modal abrir. Só preenche o que está vazio, então\n // nunca passa por cima de uma escolha — da pessoa ou do prefill.\n useEffect(() => {\n if (!open || locationId) return\n const opts = storeLocations.length > 0 ? storeLocations : config.locations\n if (opts.length === 1) setLocationId(opts[0]!.id)\n }, [open, locationId, storeLocations, config.locations])\n\n // Edit: load existing\n useEffect(() => {\n if (!open || mode !== 'edit' || !bookingId) return\n setLoading(true)\n provider.getBookingById(bookingId).then((b) => {\n if (!b) { setLoading(false); return }\n setBookingType((b.kind as BookingTypeId) ?? defaultBookingType)\n setTitle(b.clientName ?? '')\n setClientId(b.clientId ?? ''); setClientSearch(b.clientName ?? '')\n setProfessionalId(b.professionalId ?? ''); setLocationId(b.locationId ?? '')\n setDate(b.startsAt.slice(0, 10))\n const d = new Date(b.startsAt)\n setStartTime(`${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`)\n setStatus(b.status); setNotes(b.notes ?? '')\n if (b.notes) setShowNotes(true)\n if (b.services) setServices(b.services.map((s: any) => ({\n serviceId: s.serviceId ?? '', name: s.name, durationMinutes: s.durationMinutes, price: s.price,\n })))\n setEditOrderId(b.orderId ?? null)\n setEditOrderTotal(b.orderTotal ?? 0)\n setEditPaymentStatus(b.paymentStatus ?? 'none')\n // Save initial snapshot for dirty check\n const svcSnap = b.services ? b.services.map((s: any) => ({ id: s.serviceId ?? '', dur: s.durationMinutes, price: s.price })) : []\n initialSnapshot.current = JSON.stringify({\n title: b.clientName ?? '',\n clientId: b.clientId ?? '', professionalId: b.professionalId ?? '', locationId: b.locationId ?? '',\n date: b.startsAt.slice(0, 10),\n startTime: `${String(new Date(b.startsAt).getHours()).padStart(2, '0')}:${String(new Date(b.startsAt).getMinutes()).padStart(2, '0')}`,\n status: b.status, notes: b.notes ?? '', cancellationReasonId: '', cancellationNotes: '', services: svcSnap,\n })\n setLoading(false)\n // Resolve payment status from bridge if available\n if (b.orderId && config.financialBridge) {\n setPaymentStatusLoading(true)\n config.financialBridge.resolvePaymentStatuses([b.orderId]).then((map) => {\n const summary = map.get(b.orderId!)\n if (summary) {\n setEditPaymentStatus(summary.status)\n setEditOrderTotal(summary.totalAmount)\n }\n }).catch(() => {}).finally(() => setPaymentStatusLoading(false))\n }\n }).catch(() => setLoading(false))\n // Same key as the reset above: whenever that clears the form to `loading`,\n // this has to be the thing that fills it back in.\n }, [open, requestKey])\n\n // Fetch client data when client tab is opened\n useEffect(() => {\n if (modalTab !== 'client' || !clientId || !config.contactLookup || clientData) return\n setClientDataLoading(true)\n config.contactLookup.getById(clientId).then((result) => {\n setClientData(result?.data ?? null)\n setClientDataLoading(false)\n }).catch(() => setClientDataLoading(false))\n }, [modalTab, clientId])\n\n useEffect(() => {\n if (!open || status !== 'cancelled' || !config.cancellationDetails || cancellationReasons.length > 0) return\n setCancellationReasonsLoading(true)\n config.cancellationDetails.listReasons()\n .then((reasons) => setCancellationReasons(reasons))\n .catch(() => setCancellationReasons([]))\n .finally(() => setCancellationReasonsLoading(false))\n }, [open, status, config.cancellationDetails, cancellationReasons.length])\n\n // Fetch initial service list when modal opens\n useEffect(() => {\n if (!open || !config.serviceLookup) return\n const lookup = config.serviceLookup\n const fetch = lookup.list ? () => lookup.list!() : () => lookup.search('')\n fetch().then((results) => {\n const opts = results.map((r: any) => ({ id: r.id, label: r.label, subtitle: r.subtitle, price: r.price, data: r.data }))\n setInitialServiceOptions(opts)\n }).catch(() => setInitialServiceOptions([]))\n }, [open])\n\n // Search effects (client search now lives inside <ContactPicker>)\n useEffect(() => {\n if (!config.serviceLookup || serviceSearch.length < 1) { setServiceOptions([]); return }\n const timer = setTimeout(async () => {\n try {\n const results = await config.serviceLookup!.search(serviceSearch)\n setServiceOptions(results.map((r: any) => ({ id: r.id, label: r.label, subtitle: r.subtitle, price: r.price, data: r.data })))\n } catch { setServiceOptions([]) }\n }, 250)\n return () => clearTimeout(timer)\n }, [serviceSearch])\n\n // Computed\n const serviceDuration = services.reduce((sum, s) => sum + s.durationMinutes, 0)\n const selectionDuration = useMemo(() => {\n if (!prefill?.startsAt || !prefill?.endsAt) return 0\n return Math.round((new Date(prefill.endsAt).getTime() - new Date(prefill.startsAt).getTime()) / 60000)\n }, [prefill?.startsAt, prefill?.endsAt])\n const totalDuration = serviceDuration > 0 ? serviceDuration : selectionDuration\n const totalPrice = services.reduce((sum, s) => sum + s.price, 0)\n const { currency } = config\n\n const endTime = useMemo(() => {\n const [h, m] = startTime.split(':').map(Number)\n const total = h * 60 + m + totalDuration\n return `${String(Math.floor(total / 60) % 24).padStart(2, '0')}:${String(total % 60).padStart(2, '0')}`\n }, [startTime, totalDuration])\n\n // Conflict check\n useEffect(() => {\n if (!professionalId || totalDuration === 0) { setConflict(false); return }\n const timer = setTimeout(() => {\n provider.checkConflict({\n assigneeId: professionalId, startsAt: `${date}T${startTime}:00`, endsAt: `${date}T${endTime}:00`, excludeBookingId: bookingId,\n }).then(setConflict).catch(() => setConflict(false))\n }, 300)\n return () => clearTimeout(timer)\n }, [professionalId, date, startTime, endTime, bookingId])\n\n function addService(opt: ComboboxOption) {\n const duration = (opt.data?.duration_minutes as number) || 60\n setServices((p) => [...p, { serviceId: opt.id, name: opt.label, durationMinutes: duration, price: opt.price ?? 0 }])\n setServiceSearch(''); setServiceOptions([])\n }\n function removeService(idx: number) { setServices((p) => p.filter((_, i) => i !== idx)) }\n\n // A service that does not exist yet. A catalogue is never complete on the day\n // someone calls asking for what is missing from it, and leaving the booking to\n // register one loses the slot being booked. Inline rather than a dialog: this\n // already sits inside a form. Without `create` on the source, search only.\n const serviceCreate = useLookupCreate(\n config.serviceLookup,\n (created) => {\n const duration = (created.data?.duration_minutes as number) || 60\n setServices((p) => [...p, {\n serviceId: created.id,\n name: created.label,\n durationMinutes: duration,\n price: created.price ?? 0,\n }])\n setServiceSearch('')\n setServiceOptions([])\n },\n { variant: 'inline' },\n )\n\n async function handleSubmit(e: React.FormEvent) {\n e.preventDefault()\n if (!canSubmit) return\n // Plan quantity guard (client-side, before the store call): opens the global\n // UpgradeModal and aborts when the monthly booking cap is reached. CREATE only.\n if (mode === 'create' && (await guardBookings()) === 'blocked') return\n setSaving(true)\n try {\n const startsAt = new Date(`${date}T${startTime}:00`).toISOString()\n if (mode === 'create') {\n const newBooking = await createBooking({ kind: bookingType, clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined,\n title: activeType.fields.title ? title.trim() : undefined,\n services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })) })\n invalidateLimit('bookings_month')\n onClose()\n onCreated?.(newBooking.id, externalSource)\n } else if (bookingId) {\n await updateBooking(bookingId, {\n clientId, professionalId, locationId: locationId || undefined, startsAt, notes: notes || undefined, status: status as any,\n title: activeType.fields.title ? title.trim() : undefined,\n services: services.map((s: any) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price })),\n })\n if (status === 'cancelled' && config.cancellationDetails && cancellationReasonId) {\n await config.cancellationDetails.saveCancellationDetails({\n bookingId,\n reasonId: cancellationReasonId,\n notes: cancellationNotes.trim() || undefined,\n cancelledAt: new Date().toISOString(),\n })\n }\n onClose()\n }\n } catch { /* toast */ }\n setSaving(false)\n }\n\n async function handleDelete() {\n if (!bookingId) return\n setDeleting(true)\n try {\n await deleteBooking(bookingId)\n onClose()\n } catch {\n // deleteBooking surfaces its own toast. Return the footer to its normal\n // state (out of the confirm step) so a failure is clear feedback rather\n // than a modal that silently stays stuck on \"Confirm delete\".\n setConfirmingDelete(false)\n } finally {\n setDeleting(false)\n }\n }\n\n const isPaidBooking = editPaymentStatus === 'paid'\n const selectedCancellationReason = cancellationReasons.find((reason) => reason.id === cancellationReasonId)\n const needsCancellationReason = mode === 'edit' && status === 'cancelled' && !!config.cancellationDetails\n const needsCancellationNotes = needsCancellationReason && !!selectedCancellationReason?.requiresNotes\n\n // Dirty check — only enable Update when something changed\n const formSnapshot = useMemo(() =>\n JSON.stringify({ title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services: services.map((s: any) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),\n [title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services]\n )\n const isDirty = mode === 'create' || formSnapshot !== initialSnapshot.current\n\n const canSubmit = (\n (!activeType.fields.title || title.trim()) &&\n (!activeType.requiresClient || clientId) &&\n (!activeType.fields.professional || professionalId) &&\n (!activeType.requiresServices || services.length > 0) &&\n (!needsCancellationReason || !!cancellationReasonId) &&\n (!needsCancellationNotes || !!cancellationNotes.trim()) &&\n !conflict && !saving\n )\n\n const showTabs = config.bookingTypes.length > 1\n\n // The column heads the page, so the form no longer names itself.\n const railTitle = mode === 'create'\n ? t('agenda.appointment.new')\n : (title.trim() || clientSearch || t('agenda.appointment.edit'))\n\n return (\n // A booking is written next to the calendar it belongs to, not on top of\n // it: the dialog used to dim the week you were reading while you filled in\n // a slot from it, and a second panel opening from the same edge as the\n // assistant meant two vocabularies for one side of the screen.\n <RightRailPage title={railTitle} open={open} onClose={onClose} width=\"max-w-lg\">\n\n {/* ═══ TOP — type tabs + date/time ═══ */}\n <div className=\"px-5 pt-3 pb-3 shrink-0 space-y-3\">\n {/* Booking type tabs (create) or section tabs (edit) */}\n {showTabs && mode === 'create' ? (\n <div className=\"flex gap-1 border-b fayz-glass-divider\">\n {config.bookingTypes.map((bt) => {\n const label = t(`agenda.bookingType.${bt.id}`) || bt.label\n const isActive = bookingType === bt.id\n const BtIcon = BOOKING_TYPE_ICONS[bt.icon] ?? Calendar\n return (\n <button key={bt.id} type=\"button\" onClick={() => setBookingType(bt.id)}\n className={`relative flex items-center gap-1.5 pb-2 px-2 text-xs font-medium transition-colors ${\n isActive ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'\n }`}>\n <BtIcon className=\"h-3.5 w-3.5\" />\n {label}\n {isActive && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-foreground\" />\n )}\n </button>\n )\n })}\n </div>\n ) : mode === 'edit' && (\n (config.clientEntityDef && clientId) || (config.modules.financial && editOrderId) ? (\n <div className=\"flex gap-1 border-b fayz-glass-divider\">\n {([\n { id: 'appointment' as const, label: t(`agenda.bookingType.${bookingType}`) || activeType.label, icon: Calendar, show: true },\n { id: 'client' as const, label: t('agenda.appointment.clientTab'), icon: User, show: !!config.clientEntityDef && !!clientId },\n { id: 'financial' as const, label: t('agenda.payment.title'), icon: DollarSign, show: config.modules.financial && !!editOrderId },\n ]).filter((tab) => tab.show).map((tab) => {\n const isActive = modalTab === tab.id\n return (\n <button key={tab.id} type=\"button\" onClick={() => setModalTab(tab.id)}\n className={`relative flex items-center gap-1.5 pb-2 px-2 text-xs font-medium transition-colors ${\n isActive ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'\n }`}>\n <tab.icon className=\"h-3.5 w-3.5\" />\n {tab.label}\n {tab.id === 'financial' && editPaymentStatus === 'paid' && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-success\" />\n )}\n {tab.id === 'financial' && editPaymentStatus !== 'paid' && (\n (editPaymentStatus !== 'none' || (totalPrice > 0 && date <= new Date().toISOString().slice(0, 10)))\n ) && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-warning\" />\n )}\n {isActive && (\n <span className=\"absolute bottom-0 left-0 right-0 h-0.5 rounded-full bg-foreground\" />\n )}\n </button>\n )\n })}\n </div>\n ) : null\n )}\n\n {/* Date/time + professional row — hidden on financial tab */}\n {modalTab === 'appointment' && (\n <>\n <div className=\"flex items-center gap-3\">\n <Clock className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n {/* Wraps: the column is ~380px, so the assignee drops to its\n own line rather than squeezing the time out of the row. */}\n <div className=\"flex flex-wrap items-center gap-x-1.5 gap-y-1 text-sm flex-1 min-w-0\">\n {editingDate ? (\n <input type=\"date\" value={date} autoFocus\n onChange={(e) => { setDate(e.target.value); setEditingDate(false) }}\n onBlur={() => setEditingDate(false)}\n className=\"bg-transparent text-sm font-medium focus:outline-none border-b border-foreground w-auto shrink-0\" />\n ) : (\n <button type=\"button\" onClick={() => setEditingDate(true)}\n className=\"px-0.5 py-0.5 font-medium border-b border-transparent hover:border-foreground transition-colors shrink-0\">\n {formatCompactDate(date, locale)}\n </button>\n )}\n {editingTime ? (\n <input type=\"time\" value={startTime} autoFocus\n onChange={(e) => { if (e.target.value) { setStartTime(e.target.value); setEditingTime(false) } }}\n onBlur={() => setEditingTime(false)}\n className=\"bg-transparent text-xs text-muted-foreground focus:outline-none border-b border-foreground w-auto shrink-0\" />\n ) : (\n <button type=\"button\" onClick={() => setEditingTime(true)}\n className=\"px-0.5 py-0.5 text-xs text-muted-foreground border-b border-transparent hover:border-foreground transition-colors shrink-0\">\n {startTime}\n </button>\n )}\n <span className=\"text-[11px] text-muted-foreground/60\">—</span>\n <span className=\"text-[11px] text-muted-foreground/60\">{endTime}</span>\n\n {/* Professional — right-aligned on the same row */}\n {activeType.fields.professional && (\n <div className=\"ml-auto shrink-0\">\n <ProfessionalSelect value={professionalId} onChange={setProfessionalId} professionals={professionals} />\n </div>\n )}\n </div>\n </div>\n\n {conflict && (\n <div className=\"flex items-center gap-2 rounded-lg bg-destructive/10 px-3 py-1.5 text-xs text-destructive\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0\" />\n {t('agenda.appointment.conflict')}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* ═══ BODY ═══ */}\n <div className=\"flex flex-col flex-1 min-h-0 overflow-hidden\">\n\n {/* Client tab content — reuses the same CrudDetailPage as /clients/:id */}\n {modalTab === 'client' && clientId && config.clientEntityDef && (\n <div className=\"flex-1 overflow-y-auto px-5 py-4\">\n {clientDataLoading ? (\n <div className=\"space-y-3 py-2\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"h-8 rounded-lg bg-muted animate-pulse\" />\n ))}\n </div>\n ) : clientData ? (\n clientEditing ? (\n <CrudFormPage\n embedded\n entityDef={config.clientEntityDef}\n mode=\"edit\"\n initialData={clientData}\n namePlural=\"\"\n onCancel={() => setClientEditing(false)}\n onSubmit={async (data) => {\n try {\n const { getSupabaseClientOptional } = await import('@fayz-ai/core')\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return\n const dbData: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(data)) {\n dbData[k.replace(/[A-Z]/g, (m) => '_' + m.toLowerCase())] = v\n }\n await supabase.from('people').update(dbData).eq('id', clientId)\n setClientData({ ...clientData, ...data })\n setClientEditing(false)\n } catch { /* toast */ }\n }}\n />\n ) : (\n <CrudDetailPage\n embedded\n entityDef={config.clientEntityDef}\n item={clientData}\n namePlural=\"\"\n basePath=\"\"\n onBack={() => setModalTab('appointment')}\n onEdit={() => setClientEditing(true)}\n />\n )\n ) : (\n <p className=\"text-sm text-muted-foreground py-4 text-center\">{t('agenda.appointment.noClientData')}</p>\n )}\n </div>\n )}\n\n {/* Financial tab content */}\n {modalTab === 'financial' && editOrderId && config.financialBridge && (\n <div className=\"flex-1 overflow-y-auto\">\n <BookingPaymentPanel\n orderId={editOrderId}\n orderTotal={editOrderTotal}\n services={services.map((s: any) => ({ name: s.name, price: s.price, durationMinutes: s.durationMinutes }))}\n formatCurrency={(v) => fmtCurrency(v, currency.locale, currency.code)}\n inline\n onClose={() => setModalTab('appointment')}\n onPaymentChange={() => {\n config.financialBridge!.getPaymentDetail(editOrderId).then((d) => {\n if (d) { setEditPaymentStatus(d.status); setEditOrderTotal(d.totalAmount) }\n }).catch(() => {})\n // Propagate to the calendar card + popover badge (booking.paymentStatus\n // is ledger-derived) so they update without a page refresh.\n if (agendaDateRange.start) fetchBookings(agendaDateRange)\n }}\n />\n </div>\n )}\n\n {/* Appointment tab content */}\n <form onSubmit={handleSubmit} className=\"flex flex-col flex-1 min-h-0 overflow-hidden\" style={{ display: modalTab === 'appointment' ? undefined : 'none' }}>\n <div className=\"border-t fayz-glass-divider px-5 py-3 space-y-1 flex-1 overflow-y-auto\">\n\n {/* Loading skeleton */}\n {loading && (\n <div className=\"space-y-2 py-2\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 py-1.5\">\n <div className=\"h-4 w-4 rounded bg-muted animate-pulse shrink-0\" />\n <div className=\"h-8 flex-1 rounded-lg bg-muted animate-pulse\" />\n </div>\n ))}\n </div>\n )}\n\n {!loading && <>\n\n {/* Title — free-text event name (simple / Google-Calendar-style events) */}\n {activeType.fields.title && (\n <div className=\"flex items-center gap-3 py-1\">\n <Calendar className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <input type=\"text\" value={title} onChange={(e) => setTitle(e.target.value)}\n placeholder={t('agenda.appointment.addTitle')} autoFocus={mode === 'create'} aria-required\n className=\"w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n\n {/* Client */}\n {activeType.fields.client && (\n <div className=\"flex items-center gap-3 py-1\">\n <User className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <div className=\"flex-1\">\n {/* Shared find-or-create flow (@fayz-ai/admin), same component\n and same behaviour as the conversations composer.\n `variant=\"inline\"` only drops the chrome, to match this\n form's icon rows. Creating opens the app's own client\n form — see `createEntityDef`. */}\n <ContactPicker\n value={clientId || clientSearch ? { id: clientId || undefined, name: clientSearch, phone: clientPhone } : null}\n onChange={(contact) => {\n setClientId(contact?.id ?? '')\n setClientSearch(contact?.name ?? '')\n setClientPhone(contact?.phone ?? '')\n }}\n kind={config.clientKind}\n lookup={config.contactLookup}\n createEntityDef={config.clientEntityDef}\n clearable={!isPaidBooking}\n variant=\"inline\"\n placeholder={t('agenda.appointment.searchClient')}\n createLabel={t('agenda.appointment.newClient')}\n required={activeType.requiresClient}\n />\n </div>\n </div>\n )}\n\n {/* Location */}\n {activeType.fields.location && config.modules.locationSelection && (storeLocations.length > 0 || config.locations.length > 0) && (\n <div className=\"flex items-center gap-3 py-1\">\n <MapPin className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <LocationSelect\n value={locationId}\n onChange={setLocationId}\n locations={storeLocations.length > 0 ? storeLocations : config.locations}\n />\n </div>\n )}\n\n {/* Services */}\n {activeType.fields.services && (\n <div className=\"flex items-start gap-3 py-1\">\n <Briefcase className=\"h-4 w-4 mt-1.5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1\">\n {services.length > 0 && (\n <div className=\"space-y-0.5 mb-1\">\n {services.map((svc, idx) => (\n <div key={idx} className=\"flex items-center rounded-md bg-muted/30 px-2.5 py-1.5 text-sm\">\n <span className=\"flex-1 truncate min-w-0\">{svc.name}</span>\n <div className=\"flex items-center gap-0.5 shrink-0 ml-3\">\n <InlineNumber\n value={svc.durationMinutes}\n onChange={(v) => setServices((p) => p.map((s, i) => i === idx ? { ...s, durationMinutes: Math.round(v) } : s))}\n min={5}\n step={5}\n className=\"w-10 shrink-0\"\n disabled={isPaidBooking}\n tooltip={t('agenda.appointment.duration')}\n />\n <span className=\"text-[11px] text-muted-foreground\">min</span>\n </div>\n <div className=\"flex items-center gap-0.5 shrink-0 ml-3\">\n <span className=\"text-[11px] text-muted-foreground\">{currency.symbol}</span>\n <InlineNumber\n value={svc.price}\n onChange={(v) => setServices((p) => p.map((s, i) => i === idx ? { ...s, price: v } : s))}\n min={0}\n step={0.01}\n className=\"w-14 shrink-0\"\n disabled={isPaidBooking}\n tooltip={t('agenda.appointment.price')}\n />\n </div>\n {!isPaidBooking && (\n <button type=\"button\" onClick={() => removeService(idx)} className=\"p-0.5 ml-2 text-muted-foreground hover:text-destructive shrink-0\">\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n\n {serviceCreate.creating && serviceCreate.form}\n\n {!isPaidBooking && !serviceCreate.creating && <SearchCombobox\n value={serviceSearch}\n onChange={setServiceSearch}\n onSelect={addService}\n options={serviceOptions}\n placeholder={t('agenda.appointment.searchService')}\n onBlurEmpty={() => {}}\n onFocus={() => { if (!serviceSearch && serviceOptions.length === 0) setServiceOptions(initialServiceOptions) }}\n renderRight={(opt) => {\n const dur = (opt.data?.duration_minutes as number) || 0\n const hasPrice = opt.price != null\n if (!hasPrice && !dur) return null\n return (\n <span className=\"text-muted-foreground text-xs whitespace-nowrap\">\n {hasPrice && fmtCurrency(opt.price!, currency.locale, currency.code)}\n {hasPrice && dur > 0 && ' · '}\n {dur > 0 && `${dur}min`}\n </span>\n )\n }}\n minimal\n chevron\n required={activeType.requiresServices && services.length === 0}\n allowCreate={!!serviceCreate.onCreate}\n onCreateNew={serviceCreate.onCreate}\n createLabel={t('agenda.appointment.newService')}\n inlineLabel={services.length > 0 ? t('agenda.appointment.addService') : t('agenda.appointment.addServiceFirst')}\n inlineIcon={services.length > 0 ? 'plus' : 'search'}\n />}\n </div>\n </div>\n )}\n\n {/* Status */}\n {activeType.fields.status && (\n <div className=\"flex items-center gap-3 py-1\">\n <CircleDot className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <StatusSelect value={status} onChange={setStatus} statuses={config.statuses} bookingDate={date} />\n </div>\n )}\n\n {needsCancellationReason && (\n <div className=\"flex items-start gap-3 py-1\">\n <Ban className=\"h-4 w-4 mt-2 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 space-y-2\">\n <select\n value={cancellationReasonId}\n onChange={(event) => setCancellationReasonId(event.target.value)}\n disabled={cancellationReasonsLoading}\n aria-required\n className=\"w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring\"\n >\n <option value=\"\">{cancellationReasonsLoading ? t('agenda.cancellation.loadingReasons') : t('agenda.cancellation.selectReason')}</option>\n {cancellationReasons.map((reason) => (\n <option key={reason.id} value={reason.id}>\n {reason.label}{reason.requiresNotes ? ' *' : ''}\n </option>\n ))}\n </select>\n <textarea\n value={cancellationNotes}\n onChange={(event) => setCancellationNotes(event.target.value)}\n placeholder={needsCancellationNotes ? t('agenda.cancellation.notesRequired') : t('agenda.cancellation.notesOptional')}\n rows={2}\n aria-required={needsCancellationNotes || undefined}\n className=\"w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm resize-none shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n </div>\n )}\n\n {/* Notes — progressive disclosure */}\n {!showNotes ? (\n <div className=\"flex items-center gap-3 py-1\">\n <FileText className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <button type=\"button\" onClick={() => setShowNotes(true)}\n className=\"text-sm text-muted-foreground hover:text-foreground transition-colors text-left py-1.5 pl-2\">\n {t('agenda.appointment.addNotes')}\n </button>\n </div>\n ) : (\n <div className=\"flex items-start gap-3 py-1\">\n <FileText className=\"h-4 w-4 mt-2 text-muted-foreground shrink-0\" />\n <textarea value={notes} onChange={(e) => setNotes(e.target.value)}\n placeholder={t('agenda.appointment.addDescription')} rows={2} autoFocus\n className=\"w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm resize-none focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n\n </>}\n </div>\n\n {/* Appointment footer — inside form for submit */}\n {modalTab === 'appointment' && !clientEditing && (\n <div className=\"px-5 py-2.5 border-t fayz-glass-divider bg-transparent shrink-0\">\n {confirmingDelete ? (\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-destructive font-medium\">{t('agenda.appointment.deleteConfirm')}</span>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => setConfirmingDelete(false)}>\n {t('agenda.appointment.cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" size=\"sm\" onClick={handleDelete} disabled={deleting}>\n {deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {mode === 'edit' && (\n <button type=\"button\" onClick={() => setConfirmingDelete(true)} className=\"text-xs text-destructive font-medium hover:underline\">{t('agenda.appointment.delete')}</button>\n )}\n {services.length > 0 && (\n <span className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {totalDuration}min\n {config.modules.financial && totalPrice > 0 && mode === 'edit' ? (\n paymentStatusLoading ? (\n <span className=\"h-4 w-16 rounded-full bg-muted animate-pulse\" />\n ) : isPaidBooking ? (\n <button type=\"button\" onClick={(e) => { e.stopPropagation(); setModalTab('financial') }}\n className=\"inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-[10px] font-medium text-success hover:bg-success/20 transition-colors\">\n <Check className=\"h-2.5 w-2.5\" />\n {fmtCurrency(totalPrice, currency.locale, currency.code)} · {t('agenda.payment.paid')}\n </button>\n ) : date <= new Date().toISOString().slice(0, 10) ? (\n <button type=\"button\" onClick={(e) => { e.stopPropagation(); setModalTab('financial') }}\n className=\"inline-flex items-center gap-1 rounded-full bg-warning/10 px-2 py-0.5 text-[10px] font-medium text-warning hover:bg-warning/20 transition-colors\">\n <HandCoins className=\"h-3 w-3\" />\n {fmtCurrency(totalPrice, currency.locale, currency.code)} · {t('agenda.payment.collect')}\n </button>\n ) : (\n <span>· {fmtCurrency(totalPrice, currency.locale, currency.code)}</span>\n )\n ) : (\n <span>· {fmtCurrency(totalPrice, currency.locale, currency.code)}</span>\n )}\n </span>\n )}\n </div>\n {/* No Cancel button: the column's header already holds the\n way out, and at this width it crowded Save. */}\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" variant=\"default\" size=\"sm\" disabled={!canSubmit || !isDirty}>\n {saving ? t('agenda.appointment.saving') : mode === 'create' ? t('agenda.appointment.save') : t('agenda.appointment.update')}\n </Button>\n </div>\n </div>\n )}\n </div>\n )}\n </form>\n\n {/* Non-appointment tab footer — outside form */}\n {modalTab !== 'appointment' && !clientEditing && (\n <div className=\"px-5 py-2.5 border-t fayz-glass-divider bg-transparent shrink-0\">\n <div className=\"flex items-center\">\n <button type=\"button\" onClick={() => { setModalTab('appointment'); setClientEditing(false) }}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors\">\n <svg className=\"h-3 w-3\" viewBox=\"0 0 16 16\" fill=\"none\"><path d=\"M10 12L6 8l4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>\n {t('agenda.payment.backToAppointment')}\n </button>\n </div>\n </div>\n )}\n </div>\n </RightRailPage>\n )\n}\n","import React, { useEffect, useRef, useState, useCallback } from 'react'\nimport { createPortal } from 'react-dom'\n\n// ---------------------------------------------------------------------------\n// Inject animations once\n// ---------------------------------------------------------------------------\n\nconst STYLE_ID = 'saas-floating-panel'\nif (typeof document !== 'undefined' && !document.getElementById(STYLE_ID)) {\n const s = document.createElement('style')\n s.id = STYLE_ID\n s.textContent = `\n @keyframes _fp-dismiss { from { opacity:1; transform:scale(1) } to { opacity:0; transform:scale(.96) } }\n @keyframes _fp-expand { from { opacity:1; transform:scale(1) } to { opacity:0; transform:scale(1.08) } }\n .saas-fp-dismissing { animation: _fp-dismiss 150ms ease-in forwards; pointer-events: none }\n .saas-fp-expanding { animation: _fp-expand 200ms ease-in forwards; pointer-events: none }\n `\n document.head.appendChild(s)\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype Phase = 'visible' | 'dismissing' | 'expanding'\n\nexport interface FloatingPanelRef {\n /** Dismiss with fade-out, then call onClose */\n dismiss: () => void\n /** Expand-out animation (e.g. popover → modal), then call callback */\n expandThen: (callback: () => void) => void\n}\n\ninterface FloatingPanelProps {\n position: { x: number; y: number }\n width: number\n height: number\n /** Offset from cursor (default: { x: 0, y: 0 }) */\n offset?: { x: number; y: number }\n onClose: () => void\n className?: string\n children: (ref: FloatingPanelRef) => React.ReactNode\n zIndex?: number\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function FloatingPanel({\n position, width, height, offset, onClose, className, children, zIndex = 100,\n}: FloatingPanelProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [phase, setPhase] = useState<Phase>('visible')\n const phaseRef = useRef<Phase>('visible')\n phaseRef.current = phase\n const onCloseRef = useRef(onClose)\n onCloseRef.current = onClose\n const expandCallbackRef = useRef<(() => void) | null>(null)\n\n const dismiss = useCallback(() => {\n if (phaseRef.current !== 'visible') return\n setPhase('dismissing')\n setTimeout(() => onCloseRef.current(), 150)\n }, [])\n\n const expandThen = useCallback((callback: () => void) => {\n if (phaseRef.current !== 'visible') return\n expandCallbackRef.current = callback\n setPhase('expanding')\n setTimeout(() => {\n callback()\n onCloseRef.current()\n }, 220)\n }, [])\n\n // Outside click + Escape\n useEffect(() => {\n function handleClick(e: MouseEvent) {\n if (phaseRef.current !== 'visible') return\n if (ref.current && !ref.current.contains(e.target as Node)) {\n // Don't dismiss if clicking another calendar event — let eventClick handle it\n const target = e.target as HTMLElement\n if (target.closest('.fc-event')) return\n dismiss()\n }\n }\n function handleKey(e: KeyboardEvent) {\n if (e.key === 'Escape') dismiss()\n }\n document.addEventListener('mousedown', handleClick)\n document.addEventListener('keydown', handleKey)\n return () => {\n document.removeEventListener('mousedown', handleClick)\n document.removeEventListener('keydown', handleKey)\n }\n }, [dismiss])\n\n // Clamp position to viewport\n const ox = offset?.x ?? 0\n const oy = offset?.y ?? 0\n let x = position.x + ox\n let y = position.y + oy\n if (x + width > window.innerWidth - 12) x = x - width - ox * 2\n if (y + height > window.innerHeight - 12) y = y - height - oy * 2\n if (x < 12) x = 12\n if (y < 12) y = 12\n\n const panelRef: FloatingPanelRef = { dismiss, expandThen }\n\n return createPortal(\n <div ref={ref}\n style={{ position: 'fixed', left: x, top: y, zIndex, transition: phase === 'visible' ? 'left 200ms ease-out, top 200ms ease-out' : undefined }}\n className={`fayz-glass-surface rounded-modal border bg-popover shadow-lg overflow-hidden ${\n phase === 'expanding' ? 'saas-fp-expanding'\n : phase === 'dismissing' ? 'saas-fp-dismissing'\n : 'animate-in fade-in zoom-in-95 duration-150'\n } ${className ?? ''}`}>\n {children(panelRef)}\n </div>,\n document.body,\n )\n}\n","import React, { useState, useRef, useEffect } from 'react'\nimport { X, Pencil, Trash2, Clock, MapPin, User, FileText, DollarSign, Check, AlertTriangle, HandCoins } from 'lucide-react'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { FloatingPanel, type FloatingPanelRef } from './FloatingPanel'\nimport { useAgendaConfig, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CalendarBooking } from '../types'\n\ninterface Props {\n booking: CalendarBooking\n position: { x: number; y: number }\n onClose: () => void\n onEdit: (id: string) => void\n}\n\nfunction fmtTime(iso: string) {\n return new Date(iso).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })\n}\nfunction fmtDate(iso: string) {\n return new Date(iso).toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' })\n}\nfunction fmtCurrency(amount: number, locale: string, code: string) {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(amount)\n}\n\n// Inline status select for the popover\nfunction PopoverStatusSelect({ value, statuses, bookingStartsAt, onChange }: {\n value: string; statuses: Array<{ value: string; label: string; color: string; availableWhen?: string }>\n bookingStartsAt: string; onChange: (v: string) => void\n}) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = statuses.find((s) => s.value === value)\n\n useEffect(() => {\n if (!open) return\n const h = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false) }\n document.addEventListener('mousedown', h)\n return () => document.removeEventListener('mousedown', h)\n }, [open])\n\n return (\n <div ref={ref} className=\"relative inline-block\">\n <button type=\"button\" onClick={() => setOpen((p) => !p)}\n className=\"inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors hover:opacity-80\"\n style={{ backgroundColor: (current?.color ?? '#6b7280') + '18', color: current?.color ?? '#6b7280' }}>\n <span className=\"h-2 w-2 rounded-full\" style={{ backgroundColor: current?.color }} />\n {current?.label ?? value}\n <svg className=\"h-3 w-3 opacity-50\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/>\n </svg>\n </button>\n {open && (\n <div className=\"fayz-glass-surface absolute bottom-full left-0 z-50 mb-1 rounded-lg border bg-popover shadow-lg py-1 animate-in fade-in zoom-in-95 duration-100 min-w-[140px]\">\n {statuses.map((s) => {\n const available = isStatusAvailable(s as any, bookingStartsAt)\n return (\n <button key={s.value} type=\"button\" disabled={!available}\n onClick={() => { if (available) { onChange(s.value); setOpen(false) } }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-xs transition-colors ${\n !available ? 'opacity-30 cursor-not-allowed' : s.value === value ? 'bg-muted/30' : 'hover:bg-muted/50'\n }`}>\n <span className=\"h-2 w-2 rounded-full shrink-0\" style={{ backgroundColor: s.color }} />\n <span>{s.label}</span>\n </button>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport function AppointmentPopover({ booking, position, onClose, onEdit }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const updateStatus = useAgendaStore((s) => s.updateBookingStatus)\n const openModal = useAgendaStore((s) => s.openAppointmentModal)\n const [confirmingDelete, setConfirmingDelete] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const statusConfig = config.statuses.find((s) => s.value === booking.status)\n const color = statusConfig?.color ?? '#6b7280'\n const timeRange = `${fmtTime(booking.startsAt)}${booking.endsAt ? ' – ' + fmtTime(booking.endsAt) : ''}`\n\n async function handleDelete() {\n setDeleting(true)\n try { await deleteBooking(booking.id); onClose() } catch { setDeleting(false) }\n }\n\n return (\n <>\n <FloatingPanel position={position} width={320} height={340} onClose={onClose}>\n {(panel) => (\n <>\n {/* Action bar */}\n <div className=\"flex items-center justify-end gap-0.5 px-3 pt-3 pb-1\">\n {confirmingDelete ? (\n <>\n <span className=\"text-xs text-destructive font-medium mr-auto pl-1\">{t('agenda.appointment.deleteConfirm')}</span>\n <button onClick={() => setConfirmingDelete(false)}\n className=\"rounded px-2 py-0.5 text-[11px] font-medium hover:bg-muted/50 transition-colors\">{t('agenda.appointment.cancel')}</button>\n <button onClick={handleDelete} disabled={deleting}\n className=\"rounded bg-destructive border border-destructive px-2 py-0.5 text-[11px] font-medium text-destructive-foreground hover:bg-destructive/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\">{deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}</button>\n </>\n ) : (\n <>\n <button onClick={() => panel.expandThen(() => onEdit(booking.id))}\n className=\"p-1.5 rounded-full hover:bg-muted transition-colors\" title={t('common.edit')}>\n <Pencil className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n <button onClick={() => setConfirmingDelete(true)}\n className=\"p-1.5 rounded-full hover:bg-destructive/10 transition-colors\" title={t('common.delete')}>\n <Trash2 className=\"h-4 w-4 text-muted-foreground hover:text-destructive\" />\n </button>\n <button onClick={panel.dismiss} className=\"p-1.5 rounded-full hover:bg-muted transition-colors\">\n <X className=\"h-4 w-4 text-muted-foreground\" />\n </button>\n </>\n )}\n </div>\n\n {/* Content */}\n <div className=\"px-5 pb-5 space-y-3\">\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-1.5 h-3 w-3 rounded shrink-0\" style={{ backgroundColor: color }} />\n <div className=\"min-w-0\">\n {/* Client agendas link to the person; simple events (no client\n capability) render the free-text title as a plain heading —\n booking.clientName carries the event title in that model. */}\n {config.capabilities.client ? (\n <PersonLink personId={booking.clientId} name={booking.clientName ?? 'Unknown'} className=\"text-base\" />\n ) : (\n <p className=\"text-base font-medium truncate\">{booking.clientName || t('agenda.appointment.untitled')}</p>\n )}\n <p className=\"text-sm text-muted-foreground mt-0.5\">{fmtDate(booking.startsAt)} · {timeRange}</p>\n </div>\n </div>\n\n {booking.services && booking.services.length > 0 && (\n <div className=\"flex items-start gap-3\">\n <Clock className=\"h-4 w-4 mt-0.5 text-muted-foreground shrink-0\" />\n <div className=\"text-sm space-y-0.5\">\n {booking.services.map((svc) => (\n <p key={svc.id}>{svc.name} <span className=\"text-muted-foreground\">({svc.durationMinutes}min)</span></p>\n ))}\n </div>\n </div>\n )}\n\n {config.capabilities.professional && booking.professionalName && (\n <div className=\"flex items-center gap-3\">\n <User className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-sm\">{booking.professionalName}</span>\n </div>\n )}\n\n {booking.locationName && (\n <div className=\"flex items-center gap-3\">\n <MapPin className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-sm\">{booking.locationName}</span>\n </div>\n )}\n\n {booking.notes && (\n <div className=\"flex items-start gap-3\">\n <FileText className=\"h-4 w-4 mt-0.5 text-muted-foreground shrink-0\" />\n <p className=\"text-sm text-muted-foreground\">{booking.notes}</p>\n </div>\n )}\n\n {booking.orderTotal != null && booking.orderTotal > 0 && (() => {\n const total = fmtCurrency(booking.orderTotal, config.currency.locale, config.currency.code)\n const ps = booking.paymentStatus ?? 'none'\n const hasFinancial = config.modules.financial && booking.orderId\n\n // No financial module — just show total\n if (!hasFinancial) {\n return (\n <div className=\"pt-2 border-t fayz-glass-divider flex items-center justify-between text-sm\">\n <span className=\"text-muted-foreground\">{t('agenda.appointment.total')}</span>\n <span className=\"font-medium\">{total}</span>\n </div>\n )\n }\n\n const badgeConfig: Record<string, { icon: React.ElementType; bg: string; text: string; label: string }> = {\n none: { icon: HandCoins, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.collect')}` },\n pending: { icon: Clock, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.pending')}` },\n partial: { icon: DollarSign, bg: 'bg-warning/10 hover:bg-warning/15', text: 'text-warning', label: `${total} · ${t('agenda.payment.partial')}` },\n paid: { icon: Check, bg: 'bg-success/10 hover:bg-success/15', text: 'text-success', label: `${total} · ${t('agenda.payment.paid')}` },\n overdue: { icon: AlertTriangle, bg: 'bg-destructive/10 hover:bg-destructive/15', text: 'text-destructive', label: `${total} · ${t('agenda.payment.overdue')}` },\n cancelled: { icon: X, bg: 'bg-muted hover:bg-muted/80', text: 'text-muted-foreground', label: `${total} · ${t('agenda.payment.cancelled')}` },\n }\n const cfg = badgeConfig[ps] ?? badgeConfig.none\n const StatusIcon = cfg.icon\n\n return (\n <div className=\"pt-2 border-t fayz-glass-divider flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">{t('agenda.appointment.total')}</span>\n <button\n type=\"button\"\n onClick={() => { onClose(); openModal('edit', { bookingId: booking.id, initialTab: 'financial' }) }}\n className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium transition-colors ${cfg.bg} ${cfg.text}`}\n >\n <StatusIcon className=\"h-3 w-3\" />\n {cfg.label}\n </button>\n </div>\n )\n })()}\n\n {/* Status workflow — hidden for simple events (no status capability). */}\n {config.capabilities.status && (\n <div className=\"pt-2 border-t fayz-glass-divider\">\n <PopoverStatusSelect\n value={booking.status}\n statuses={config.statuses}\n bookingStartsAt={booking.startsAt}\n onChange={(v) => { updateStatus(booking.id, v); onClose() }}\n />\n </div>\n )}\n </div>\n </>\n )}\n </FloatingPanel>\n </>\n )\n}\n","import React, { useRef, useState, useMemo } from 'react'\nimport { createPortal } from 'react-dom'\nimport { Pencil, Trash2, Check } from 'lucide-react'\nimport { FloatingPanel } from './FloatingPanel'\nimport { useAgendaConfig, useAgendaStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { isStatusAvailable } from '../types'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Tooltip — portaled to body\n// ---------------------------------------------------------------------------\n\nfunction Tooltip({ anchor, label }: { anchor: DOMRect; label: string }) {\n return createPortal(\n <div style={{ position: 'fixed', left: anchor.left + anchor.width / 2, top: anchor.bottom + 6, transform: 'translateX(-50%)', zIndex: 120 }}\n className=\"pointer-events-none\">\n <div className=\"rounded-md bg-foreground text-background px-2 py-0.5 text-[11px] font-medium whitespace-nowrap shadow-lg\">\n {label}\n </div>\n </div>,\n document.body,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Status dot with portaled tooltip\n// ---------------------------------------------------------------------------\n\nfunction StatusDot({ color, label, isActive, disabled, onClick }: {\n color: string; label: string; isActive: boolean; disabled?: boolean; onClick: () => void\n}) {\n const [hover, setHover] = useState(false)\n const btnRef = useRef<HTMLButtonElement>(null)\n const [rect, setRect] = useState<DOMRect | null>(null)\n\n return (\n <>\n <button ref={btnRef} type=\"button\" onClick={disabled ? undefined : onClick} disabled={disabled}\n onMouseEnter={() => { setHover(true); if (btnRef.current) setRect(btnRef.current.getBoundingClientRect()) }}\n onMouseLeave={() => setHover(false)}\n className={`flex h-7 w-7 items-center justify-center rounded-full transition-all ${\n disabled ? 'opacity-25 cursor-not-allowed' : isActive ? 'ring-2 ring-offset-2 ring-offset-popover' : 'hover:scale-110'\n }`}\n style={{ backgroundColor: color, ['--tw-ring-color' as any]: isActive ? color : undefined }}>\n {isActive && <Check className=\"h-3.5 w-3.5 text-white\" strokeWidth={2.5} />}\n </button>\n {hover && rect && <Tooltip anchor={rect} label={label} />}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Context Menu\n// ---------------------------------------------------------------------------\n\ninterface Props {\n booking: CalendarBooking\n position: { x: number; y: number }\n onClose: () => void\n onEdit: (id: string) => void\n}\n\nexport function EventContextMenu({ booking, position, onClose, onEdit }: Props) {\n const t = useTranslation()\n const config = useAgendaConfig()\n const updateStatus = useAgendaStore((s) => s.updateBookingStatus)\n const deleteBooking = useAgendaStore((s) => s.deleteBooking)\n const [confirming, setConfirming] = useState(false)\n const [deleting, setDeleting] = useState(false)\n\n async function handleDelete() {\n setDeleting(true)\n try { await deleteBooking(booking.id); onClose() } catch { setDeleting(false) }\n }\n\n return (\n <FloatingPanel position={position} width={230} height={180} offset={{ x: 4, y: 4 }} onClose={onClose} zIndex={110}>\n {(panel) => (\n <>\n <div className=\"py-1\">\n <button onClick={() => panel.expandThen(() => onEdit(booking.id))}\n className=\"flex w-full items-center gap-3 px-4 py-2 text-sm hover:bg-muted/50 transition-colors\">\n <Pencil className=\"h-4 w-4 text-muted-foreground\" /> {t('agenda.contextMenu.edit')}\n </button>\n {confirming ? (\n <div className=\"flex items-center justify-between px-4 py-2\">\n <span className=\"text-xs text-destructive font-medium\">{t('agenda.appointment.deleteConfirm')}</span>\n <div className=\"flex items-center gap-1.5\">\n <button onClick={() => setConfirming(false)}\n className=\"rounded px-2 py-0.5 text-[11px] font-medium hover:bg-muted/50 transition-colors\">{t('agenda.appointment.cancel')}</button>\n <button onClick={handleDelete} disabled={deleting}\n className=\"rounded bg-destructive border border-destructive px-2 py-0.5 text-[11px] font-medium text-destructive-foreground hover:bg-destructive/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors\">{deleting ? t('agenda.appointment.deleting') : t('agenda.appointment.confirmDelete')}</button>\n </div>\n </div>\n ) : (\n <button onClick={() => setConfirming(true)}\n className=\"flex w-full items-center gap-3 px-4 py-2 text-sm hover:bg-muted/50 transition-colors text-destructive\">\n <Trash2 className=\"h-4 w-4\" /> {t('agenda.contextMenu.delete')}\n </button>\n )}\n </div>\n\n {/* Status workflow — hidden for simple events (no status capability). */}\n {config.capabilities.status && (\n <div className=\"border-t px-4 py-3\">\n <p className=\"text-[11px] font-medium text-muted-foreground mb-2\">{t('agenda.contextMenu.changeStatus')}</p>\n <div className=\"flex items-center gap-1.5\">\n {config.statuses.map((s) => {\n const available = isStatusAvailable(s, booking.startsAt)\n return (\n <StatusDot key={s.value} color={s.color} label={available ? s.label : `${s.label} ${t('agenda.contextMenu.notAvailable')}`}\n isActive={booking.status === s.value}\n disabled={!available}\n onClick={() => { if (available) { updateStatus(booking.id, s.value); panel.dismiss() } }} />\n )\n })}\n </div>\n </div>\n )}\n </>\n )}\n </FloatingPanel>\n )\n}\n","import React, { useMemo } from 'react'\nimport { formatCurrency, useTranslation, getCurrentLocale } from '@fayz-ai/core'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Mobile agenda list — a thumb-friendly, date-grouped list of upcoming items.\n// Rendered on <md viewports instead of the FullCalendar grid. Each row shows a\n// category/status dot, the title, the time, and (for finance-style events) the\n// amount. Fed straight from the store bookings so it works for any seeded app.\n// ---------------------------------------------------------------------------\n\nfunction startOfDay(d: Date): Date {\n const x = new Date(d)\n x.setHours(0, 0, 0, 0)\n return x\n}\n\nfunction timeLabel(iso: string): string {\n const d = new Date(iso)\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n}\n\nexport interface AgendaMobileListProps {\n bookings: CalendarBooking[]\n statusColors: Record<string, string>\n currencyCode: string\n onSelect: (booking: CalendarBooking) => void\n /** Lets the empty state offer the one thing the screen is for. */\n onCreate?: () => void\n}\n\n/**\n * Loading state for the mobile list. Shaped like the list it replaces — a day\n * heading and a couple of rows — so the screen does not jump when real data\n * lands. A blank pane while the query runs reads as \"nothing scheduled\", which\n * is the one answer this screen must never give wrongly.\n */\nexport function AgendaMobileListSkeleton() {\n return (\n <div className=\"flex-1 space-y-5 overflow-hidden px-3 py-3\" aria-busy=\"true\" aria-live=\"polite\">\n {[0, 1].map((g) => (\n <div key={g} className=\"animate-pulse\">\n <div className=\"mb-2 ml-1 h-3 w-20 rounded bg-muted\" />\n <div className=\"space-y-1.5\">\n {[0, 1].map((r) => (\n <div key={r} className=\"flex items-center gap-3 rounded-card border border-border bg-card px-3 py-3\">\n <div className=\"h-2 w-2 shrink-0 rounded-full bg-muted\" />\n <div className=\"min-w-0 flex-1 space-y-1.5\">\n <div className=\"h-3.5 w-2/3 rounded bg-muted\" />\n <div className=\"h-3 w-12 rounded bg-muted\" />\n </div>\n <div className=\"h-3.5 w-14 shrink-0 rounded bg-muted\" />\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n\nexport function AgendaMobileList({ bookings, statusColors, currencyCode, onSelect, onCreate }: AgendaMobileListProps) {\n const t = useTranslation()\n const locale = getCurrentLocale() === 'pt-BR' ? 'pt-BR' : 'en'\n\n const groups = useMemo(() => {\n const todayStart = startOfDay(new Date()).getTime()\n const sorted = bookings\n .filter((b) => !!b.startsAt)\n .slice()\n .sort((a, b) => (a.startsAt < b.startsAt ? -1 : a.startsAt > b.startsAt ? 1 : 0))\n const map = new Map<string, CalendarBooking[]>()\n for (const b of sorted) {\n const day = startOfDay(new Date(b.startsAt))\n if (day.getTime() < todayStart) continue // upcoming only\n const key = day.toISOString().slice(0, 10)\n const list = map.get(key) ?? []\n list.push(b)\n map.set(key, list)\n }\n return Array.from(map.entries()).map(([key, items]) => ({ key, date: new Date(key + 'T00:00:00'), items }))\n }, [bookings])\n\n function dayLabel(date: Date): string {\n const today = startOfDay(new Date())\n const diff = Math.round((startOfDay(date).getTime() - today.getTime()) / 86400000)\n if (diff === 0) return t('agenda.list.today')\n if (diff === 1) return t('agenda.list.tomorrow')\n return date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long' })\n }\n\n if (groups.length === 0) {\n return (\n <div className=\"flex flex-1 flex-col items-center justify-center gap-4 px-6 py-16 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('agenda.list.empty')}</p>\n {onCreate && (\n <button\n type=\"button\"\n onClick={onCreate}\n className=\"fz-tap inline-flex items-center rounded-full bg-primary px-5 text-sm font-medium text-primary-foreground active:scale-[0.98]\"\n >\n {t('agenda.calendar.newAppointment')}\n </button>\n )}\n </div>\n )\n }\n\n return (\n <div className=\"flex-1 overflow-y-auto px-3 py-3 space-y-5\">\n {groups.map((g) => (\n <div key={g.key}>\n <h3 className=\"px-1 pb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {dayLabel(g.date)}\n </h3>\n <div className=\"space-y-1.5\">\n {g.items.map((b) => {\n const color = statusColors[b.status] ?? '#6b7280'\n const hasAmount = typeof b.orderTotal === 'number' && b.orderTotal > 0\n return (\n <button\n key={b.id}\n onClick={() => onSelect(b)}\n className=\"flex w-full items-center gap-3 rounded-card border bg-card px-3 py-2.5 text-left shadow-sm transition-colors active:bg-muted/50\"\n >\n <span className=\"h-2.5 w-2.5 shrink-0 rounded-full\" style={{ backgroundColor: color }} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-foreground\">{b.clientName ?? '—'}</p>\n <p className=\"text-xs text-muted-foreground\">{timeLabel(b.startsAt)}</p>\n </div>\n {hasAmount && (\n <span className=\"shrink-0 text-sm font-semibold tabular-nums text-foreground\">\n {formatCurrency(b.orderTotal, currencyCode)}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n ))}\n </div>\n )\n}\n","import type { EventInput } from '@fullcalendar/core'\nimport type { CalendarBooking } from '../types'\n\n/**\n * Booking → FullCalendar event. Extracted from CalendarView so the resource-lane\n * rule below is testable without mounting the grid.\n */\nexport function bookingToEvent(\n booking: CalendarBooking,\n statusColors: Record<string, string>,\n visibleResourceIds: string[] = [],\n): EventInput {\n const color = statusColors[booking.status] ?? '#6b7280'\n const serviceNames = booking.services?.map((service) => service.name).join(', ') ?? ''\n return {\n id: booking.id,\n // A tenant-wide block (an imported whole-agenda Google event, for example)\n // has no assignee. Availability treats it as busy for every professional, so\n // resource views must render it in every visible lane instead of dropping it.\n ...(booking.professionalId\n ? { resourceId: booking.professionalId }\n : visibleResourceIds.length > 0\n ? { resourceIds: visibleResourceIds }\n : {}),\n title: booking.clientName ?? 'Unknown',\n start: booking.startsAt,\n end: booking.endsAt ?? undefined,\n backgroundColor: color + '30',\n borderColor: color,\n textColor: color,\n extendedProps: { booking, serviceNames },\n }\n}\n","import React, { useRef, useEffect, useLayoutEffect, useCallback, useMemo, useState } from 'react'\nimport { injectCalendarStyles } from '../styles/calendar-styles'\nimport FullCalendar from '@fullcalendar/react'\nimport dayGridPlugin from '@fullcalendar/daygrid'\nimport timeGridPlugin from '@fullcalendar/timegrid'\nimport resourceTimeGridPlugin from '@fullcalendar/resource-timegrid'\nimport interactionPlugin from '@fullcalendar/interaction'\nimport listPlugin from '@fullcalendar/list'\nimport ptBrLocale from '@fullcalendar/core/locales/pt-br'\nimport type { EventInput, EventClickArg, DateSelectArg, EventDropArg } from '@fullcalendar/core'\nimport { ChevronLeft, ChevronRight, Plus, ChevronDown, Settings } from 'lucide-react'\nimport { usePluginPrefs, PageActions } from '@fayz-ai/admin'\nimport { getCurrentLocale } from '@fayz-ai/core'\nimport { useTranslation, useDataChanged, useActiveUnitId } from '@fayz-ai/core'\nimport { useAgendaConfig, useAgendaProvider, useAgendaStore } from '../context'\nimport { useAgendaSettings } from '../hooks/useAgendaSettings'\nimport { MiniCalendar } from '../components/MiniCalendar'\nimport { FilterSection, StatusFilterList, ProfessionalFilterList } from '../components/FilterRail'\nimport { AppointmentModal } from '../components/AppointmentModal'\nimport { AppointmentPopover } from '../components/AppointmentPopover'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { EventContextMenu } from '../components/EventContextMenu'\nimport { AgendaMobileList, AgendaMobileListSkeleton } from '../components/AgendaMobileList'\nimport { ConfirmDialog, toast } from '@fayz-ai/ui'\nimport { Button, PageHeaderActions } from '@fayz-ai/ui'\nimport type { CalendarBooking, Schedule } from '../types'\nimport { bookingToEvent } from '../lib/calendar-events'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Generate FullCalendar background events showing unavailable time.\n * For each day, creates background blocks for the gaps OUTSIDE working hours\n * within the visible business hours window. This grays out non-working time.\n */\nfunction generateAvailabilityEvents(\n schedules: Schedule[],\n professionals: { id: string }[],\n dateRange: { start: string; end: string } | null,\n businessHours?: { startTime: string; endTime: string },\n locationMap?: Map<string, string>,\n): EventInput[] {\n if (!dateRange || schedules.length === 0) return []\n\n const bgEvents: EventInput[] = []\n const startDate = new Date(dateRange.start)\n const endDate = new Date(dateRange.end)\n const bizStart = businessHours?.startTime ?? '08:00'\n const bizEnd = businessHours?.endTime ?? '20:00'\n\n // Group schedules by assignee\n const byAssignee = new Map<string, Schedule[]>()\n for (const s of schedules) {\n const aid = s.assigneeId\n if (!aid) continue\n const list = byAssignee.get(aid) ?? []\n list.push(s)\n byAssignee.set(aid, list)\n }\n\n function timeToMinutes(t: string): number {\n const [h, m] = t.split(':').map(Number)\n return h * 60 + m\n }\n\n function minutesToTime(m: number): string {\n return `${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`\n }\n\n const bizStartMin = timeToMinutes(bizStart)\n const bizEndMin = timeToMinutes(bizEnd)\n\n for (const prof of professionals) {\n const profSchedules = byAssignee.get(prof.id) ?? []\n\n // Separate weekly and date-specific schedules\n const weekly = profSchedules.filter((s) => s.dayOfWeek != null && !s.specificDate)\n const exceptions = profSchedules.filter((s) => s.specificDate != null)\n const exceptionDates = new Set(exceptions.map((s) => s.specificDate!))\n\n const current = new Date(startDate)\n while (current < endDate) {\n const dateStr = current.toISOString().slice(0, 10)\n const dayOfWeek = current.getDay()\n\n // Get working periods for this day\n let daySchedules: Schedule[]\n if (exceptionDates.has(dateStr)) {\n daySchedules = exceptions.filter((s) => s.specificDate === dateStr && s.isActive)\n } else {\n daySchedules = weekly.filter((s) => s.dayOfWeek === dayOfWeek && s.isActive)\n }\n\n // Convert working periods to sorted minute ranges, preserving locationId\n const workRanges = daySchedules\n .map((s) => {\n const locId = s.locationId ?? (s.metadata?.locationId as string | undefined)\n return {\n start: timeToMinutes(s.startsAt),\n end: timeToMinutes(s.endsAt),\n locationName: locId && locationMap ? locationMap.get(locId) : undefined,\n }\n })\n .sort((a, b) => a.start - b.start)\n\n // Compute unavailable gaps within business hours\n let cursor = bizStartMin\n for (const range of workRanges) {\n const availStart = Math.max(range.start, bizStartMin)\n const availEnd = Math.min(range.end, bizEndMin)\n\n // Gap before this working range = unavailable\n if (cursor < availStart) {\n bgEvents.push({\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(cursor) + ':00',\n end: dateStr + 'T' + minutesToTime(availStart) + ':00',\n display: 'background',\n classNames: ['fc-unavailable-bg'],\n })\n }\n\n // Location label on available range\n if (availStart < availEnd && range.locationName) {\n bgEvents.push({\n id: `loc-${prof.id}-${dateStr}-${minutesToTime(availStart)}`,\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(availStart) + ':00',\n end: dateStr + 'T' + minutesToTime(availStart + 20) + ':00',\n title: range.locationName,\n display: 'auto',\n editable: false,\n backgroundColor: 'transparent',\n borderColor: 'transparent',\n textColor: '#a3a3a3',\n classNames: ['fc-location-label'],\n extendedProps: { isLocationLabel: true },\n })\n }\n\n cursor = Math.max(cursor, availEnd)\n }\n\n // Gap after last working range = unavailable\n if (cursor < bizEndMin) {\n bgEvents.push({\n resourceId: prof.id,\n start: dateStr + 'T' + minutesToTime(cursor) + ':00',\n end: dateStr + 'T' + minutesToTime(bizEndMin) + ':00',\n display: 'background',\n classNames: ['fc-unavailable-bg'],\n })\n }\n\n\n current.setDate(current.getDate() + 1)\n }\n }\n\n return bgEvents\n}\n\n// ---------------------------------------------------------------------------\n// Loading skeleton — mimics the resource-timegrid-week layout\n// ---------------------------------------------------------------------------\n\nfunction CalendarSkeleton({ profCount = 2 }: { profCount?: number }) {\n const days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']\n const hours = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00']\n\n return (\n <div className=\"flex-1 overflow-hidden animate-pulse\">\n <div className=\"flex border-b\" style={{ paddingLeft: 56 }}>\n {Array.from({ length: profCount }).map((_, pi) => (\n <div key={pi} className=\"flex-1 border-r last:border-r-0 py-2 px-3\">\n <div className=\"flex items-center justify-center gap-2\">\n <div className=\"h-6 w-6 rounded-full bg-muted\" />\n <div className=\"h-3 w-20 rounded bg-muted\" />\n </div>\n </div>\n ))}\n </div>\n <div className=\"flex border-b\" style={{ paddingLeft: 56 }}>\n {Array.from({ length: profCount }).map((_, pi) => (\n <div key={pi} className=\"flex-1 flex border-r last:border-r-0\">\n {days.map((d) => (\n <div key={d} className=\"flex-1 py-1.5 text-center\">\n <span className=\"text-[10px] text-muted-foreground/40\">{d}</span>\n </div>\n ))}\n </div>\n ))}\n </div>\n <div className=\"relative\">\n {hours.map((h) => (\n <div key={h} className=\"flex border-b border-border/30\" style={{ height: 50 }}>\n <div className=\"w-14 shrink-0 pr-2 text-right\">\n <span className=\"text-[10px] text-muted-foreground/30\">{h}</span>\n </div>\n <div className=\"flex-1 flex\">\n {Array.from({ length: profCount * 7 }).map((_, ci) => (\n <div key={ci} className={`flex-1 border-r border-border/20 ${Math.floor(ci / 7) % 2 === 1 ? 'bg-muted/20' : ''}`} />\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\n/**\n * O PISO da coluna de um dia numa view de recurso.\n *\n * Piso, não largura: enquanto couber, as colunas encolhem e a grade ocupa a\n * tela inteira como sempre ocupou. O piso só entra quando não cabe mais — e aí\n * a grade para de encolher e o contêiner ROLA.\n *\n * Sem ele o FullCalendar divide a largura disponível pelo número de colunas e\n * aceita qualquer resultado, inclusive 14px: foi o que empilhou \"ADRIANA SILVA\n * MOREIRA\" por cima de \"Adriellen Cristiana Duarte\" na captura do Espaço\n * Facial. `dayMinWidth` faria isto nativamente, mas exige o plugin premium\n * ScrollGrid, que não está instalado — então o piso é imposto por fora, com\n * `min-width` no filho e `overflow-x` no pai.\n *\n * O valor tem que ficar ABAIXO do ponto em que o cabeçalho do dia se compacta\n * sozinho (`dayHeaderCompact`, ~50px: \"SEG. 9/7\" vira \"S 7\"). Com um piso ACIMA\n * dele a coluna nunca chega a apertar, o cabeçalho nunca encolhe, e a grade\n * larga e rolando é o que aparece — foi o que a segunda captura mostrou. Abaixo\n * dele, a coluna encolhe até o cabeçalho curto e só então a rolagem entra.\n */\nconst MIN_COLUMN_PX = 48\n\n/** Piso da altura da agenda: abaixo disto a grade não é utilizável, e é melhor\n * a página rolar do que a semana virar uma tarja. */\nconst MIN_SHELL_HEIGHT = 360\n\n/**\n * \"ADRIANA SILVA MOREIRA\" → \"Adriana M.\"\n *\n * O cabeçalho de uma coluna de agenda tem cerca de cem pixels e o nome completo\n * de um profissional brasileiro tem quatro palavras. Truncar por CSS corta no\n * meio da primeira (\"Adriellen Cristi…\") e joga fora justamente o sobrenome, que\n * é o que distingue duas Adrianas.\n *\n * Primeiro nome + inicial do último sobrenome preserva as duas metades que\n * identificam alguém. O nome inteiro continua no `title` do elemento e no link\n * da ficha — abreviar é uma decisão de LARGURA, não de conteúdo.\n *\n * O caixa-alta do cadastro vira caixa de nome: a fonte grita porque o V1\n * gritava, e um cabeçalho inteiro em maiúsculas ocupa mais espaço e lê pior.\n */\nexport function abbreviateName(full: string): string {\n const parts = full.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return full\n // Partículas não identificam ninguém: \"Alana Matos de Paula\" abrevia por\n // \"Paula\", nunca por \"de\".\n const particles = new Set(['de', 'da', 'do', 'das', 'dos', 'e', 'del', 'di', 'du', 'van', 'von'])\n const cap = (w: string) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()\n const first = cap(parts[0])\n if (parts.length === 1) return first\n const surnames = parts.slice(1).filter((w) => !particles.has(w.toLowerCase()))\n const last = surnames.length > 0 ? surnames[surnames.length - 1] : parts[parts.length - 1]\n return `${first} ${last.charAt(0).toUpperCase()}.`\n}\n\n\n/**\n * Quantas agendas ficam marcadas quando ninguém escolheu nenhuma.\n *\n * \"Nenhuma escolhida\" sempre quis dizer \"todas\", e numa clínica de seis\n * profissionais isso é a resposta certa. Numa rede com 739 agendáveis é uma\n * semana com 739 colunas: a tela congela antes de desenhar a primeira, e não há\n * como escapar porque o próprio seletor está dentro dela.\n *\n * O padrão é uma seleção EXPLÍCITA — as caixinhas aparecem marcadas — e não um\n * recorte que a tela não conta.\n */\nconst MAX_DEFAULT_AGENDAS = 6\n\n/**\n * O teto de agendas selecionadas ao mesmo tempo.\n *\n * Com a rolagem horizontal a grade não quebra mais, então isto deixa de ser\n * sobre layout e passa a ser sobre utilidade: dez colunas por dia já são setenta\n * numa semana, e rolar além disso não é ler uma agenda, é procurar uma.\n */\nconst MAX_SELECTED_AGENDAS = 10\n\n// Quantos nomes o seletor lista antes de exigir busca. Rolar 739 caixinhas não\n// é uma forma de achar ninguém.\nconst MAX_PICKER_ROWS = 40\n\n\n// Resource views — one column per professional. Used when the app has staff.\nconst RESOURCE_VIEW_OPTIONS = [\n { key: 'resourceTimeGridDay', labelKey: 'agenda.calendar.viewDay' },\n { key: 'resourceTimeGridWeek', labelKey: 'agenda.calendar.viewWeek' },\n { key: 'dayGridMonth', labelKey: 'agenda.calendar.viewMonth' },\n] as const\n\n// Non-resource variants — used when there are no professionals/resources (e.g. a\n// personal-finance agenda). A resource timegrid renders an EMPTY grid with zero\n// resource columns and drops events that have no resourceId, so those apps fall\n// back to a plain month/day/week calendar.\nconst PLAIN_VIEW_OPTIONS = [\n { key: 'timeGridDay', labelKey: 'agenda.calendar.viewDay' },\n { key: 'timeGridWeek', labelKey: 'agenda.calendar.viewWeek' },\n { key: 'dayGridMonth', labelKey: 'agenda.calendar.viewMonth' },\n { key: 'listMonth', labelKey: 'agenda.calendar.viewList' },\n] as const\n\n// Sentinel view key for the thumb-friendly mobile agenda list (AgendaMobileList),\n// which is NOT a FullCalendar view. Selected by default on <md so B2C opens on the\n// list; picking any grid option (Dia/Semana/Mês) mounts the real calendar instead.\nconst MOBILE_LIST_VIEW = '__mobileList__'\nconst AGENDA_POLL_INTERVAL_MS = 30_000\nconst AGENDA_REALTIME_DEBOUNCE_MS = 300\n\n/** Collapse a resource view to a plain month calendar when there are no resources. */\nfunction viewForNoResources(view: string): string {\n return view.startsWith('resource') ? 'dayGridMonth' : view\n}\n\n/** Promote a plain timegrid to its resource variant when the app has resources. */\nfunction viewForResources(view: string): string {\n if (view === 'timeGridWeek') return 'resourceTimeGridWeek'\n if (view === 'timeGridDay') return 'resourceTimeGridDay'\n return view\n}\n\n/** Small viewport (<md) → render the thumb-friendly agenda list instead of the grid. */\nfunction useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState(() =>\n typeof window !== 'undefined' && window.matchMedia('(max-width: 767px)').matches)\n useEffect(() => {\n if (typeof window === 'undefined') return\n const mq = window.matchMedia('(max-width: 767px)')\n const onChange = () => setIsMobile(mq.matches)\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [])\n return isMobile\n}\n\n// ---------------------------------------------------------------------------\n// Calendar View\n// ---------------------------------------------------------------------------\n\nexport function CalendarView() {\n injectCalendarStyles()\n const config = useAgendaConfig()\n const provider = useAgendaProvider()\n const t = useTranslation()\n const currentLocale = getCurrentLocale()\n const fcLocale = currentLocale === 'pt-BR' ? ptBrLocale : undefined\n const calendarRef = useRef<FullCalendar>(null)\n const prefs = usePluginPrefs('agenda', { calendarView: config.defaultCalendarView ?? 'resourceTimeGridWeek' })\n const agendaSettings = useAgendaSettings()\n const effectiveBusinessHours = {\n startTime: agendaSettings.startTime,\n endTime: agendaSettings.endTime,\n }\n\n const bookings = useAgendaStore((s) => s.bookings)\n const bookingsLoading = useAgendaStore((s) => s.bookingsLoading)\n const professionals = useAgendaStore((s) => s.professionals)\n const professionalsLoading = useAgendaStore((s) => s.professionalsLoading)\n const professionalsTruncated = useAgendaStore((s) => s.professionalsTruncated)\n const currentView = useAgendaStore((s) => s.currentView)\n const selectedProfIds = useAgendaStore((s) => s.selectedProfessionalIds)\n const selectedStatuses = useAgendaStore((s) => s.selectedStatuses)\n const schedules = useAgendaStore((s) => s.schedules)\n const fetchBookings = useAgendaStore((s) => s.fetchBookings)\n const fetchProfessionals = useAgendaStore((s) => s.fetchProfessionals)\n const fetchLocations = useAgendaStore((s) => s.fetchLocations)\n const storeLocations = useAgendaStore((s) => s.locations)\n const fetchSchedules = useAgendaStore((s) => s.fetchSchedules)\n const rescheduleBooking = useAgendaStore((s) => s.rescheduleBooking)\n const setView = useAgendaStore((s) => s.setView)\n const setFilters = useAgendaStore((s) => s.setFilters)\n const _openModal = useAgendaStore((s) => s.openAppointmentModal)\n const closeModal = useAgendaStore((s) => s.closeAppointmentModal)\n const modalState = useAgendaStore((s) => s.appointmentModal)\n\n // Resource-capable = the app has professionals/staff. When it doesn't (e.g. a\n // personal-finance agenda), resource views render empty, so we force plain\n // (non-resource) views and default to a month calendar.\n const isMobile = useIsMobile()\n const resourceCapable = professionals.length > 0\n const viewOptions = resourceCapable ? RESOURCE_VIEW_OPTIONS : PLAIN_VIEW_OPTIONS\n\n // Mobile (<md) has its own view selection, independent of the desktop pref: it\n // defaults to the thumb-friendly list and lets the user switch to any grid view\n // (Dia/Semana/Mês) without changing the desktop's stored calendarView. The list\n // sentinel replaces FullCalendar's own listMonth so mobile always gets the rich\n // AgendaMobileList, and a list option is offered even for resource apps.\n // ── A altura da agenda é MEDIDA, não calculada ──────────────────────────\n //\n // Era `h-[calc(100vh-7.5rem)]`, e o 7.5rem era um palpite sobre onde a tela\n // começa. Na casca real ela começa a 126px, não 120 — e o contêiner de página\n // ainda soma 24px de `padding-bottom`. Trinta pixels a mais do que cabe: o\n // suficiente para a página ganhar rolagem e mostrar uma faixa branca embaixo\n // do calendário, que é exatamente o defeito que isto conserta.\n //\n // Um número mágico sobre a altura de um cabeçalho que ele não controla é uma\n // aposta que se perde em toda mudança de casca, de zoom ou de densidade. Medir\n // a própria posição responde certo em todas elas.\n const shellRef = useRef<HTMLDivElement>(null)\n const [shellHeight, setShellHeight] = useState<number | undefined>(undefined)\n useLayoutEffect(() => {\n const measure = () => {\n const el = shellRef.current\n if (!el) return\n const top = el.getBoundingClientRect().top\n // O respiro que o contêiner de página reserva embaixo (`pb-6`). Lido do\n // pai em vez de fixado aqui, pelo mesmo motivo que a altura é medida.\n const parent = el.parentElement\n const pad = parent ? parseFloat(getComputedStyle(parent).paddingBottom) || 0 : 0\n setShellHeight(Math.max(MIN_SHELL_HEIGHT, window.innerHeight - top - pad))\n }\n measure()\n window.addEventListener('resize', measure)\n // A casca muda de altura sem a janela mudar — barra de aviso, banner de\n // plano, o menu mobile abrindo. O observer pega o que o resize não pega.\n const ro = new ResizeObserver(measure)\n if (document.body) ro.observe(document.body)\n return () => { window.removeEventListener('resize', measure); ro.disconnect() }\n }, [])\n\n const [mobileView, setMobileView] = useState<string>(MOBILE_LIST_VIEW)\n const mobileViewOptions = useMemo(\n () => [\n ...viewOptions.filter((o) => o.key !== 'listMonth'),\n { key: MOBILE_LIST_VIEW, labelKey: 'agenda.calendar.viewList' },\n ],\n [viewOptions],\n )\n const mobileGridActive = isMobile && mobileView !== MOBILE_LIST_VIEW\n\n const [selectedBooking, setSelectedBooking] = useState<CalendarBooking | null>(null)\n const [popoverAnchor, setPopoverAnchor] = useState<{ x: number; y: number } | null>(null)\n const [popoverVisible, _setPopoverVisible] = useState(false)\n const popoverVisibleRef = useRef(false)\n const setPopoverVisible = useCallback((v: boolean) => { popoverVisibleRef.current = v; _setPopoverVisible(v) }, [])\n const [contextMenu, setContextMenu] = useState<{ booking: CalendarBooking; x: number; y: number } | null>(null)\n const [contextMenuVisible, _setContextMenuVisible] = useState(false)\n const contextMenuVisibleRef = useRef(false)\n const setContextMenuVisible = useCallback((v: boolean) => { contextMenuVisibleRef.current = v; _setContextMenuVisible(v) }, [])\n const [scheduleConfirm, setScheduleConfirm] = useState<{ onConfirm: () => void } | null>(null)\n const [calendarTitle, setCalendarTitle] = useState('')\n const [selectedDate, setSelectedDate] = useState(new Date())\n const [visibleRange, setVisibleRange] = useState<{ start: string; end: string } | null>(null)\n\n // Leaving the calendar ends the booking form with it. The open flag lives in\n // the store, which outlives this screen — without this, navigating away with\n // a half-filled form and coming back reopened it, days later, still holding\n // the slot you abandoned.\n useEffect(() => () => closeModal(), [closeModal])\n\n // Wrap openModal to always dismiss popover/context menu first\n const openModal: typeof _openModal = useCallback((...args) => {\n setPopoverVisible(false); setSelectedBooking(null); setPopoverAnchor(null)\n setContextMenuVisible(false); setContextMenu(null)\n _openModal(...args)\n }, [_openModal])\n\n const statusColors = useMemo(() => {\n const map: Record<string, string> = {}\n for (const s of config.statuses) map[s.value] = s.color\n return map\n }, [config.statuses])\n\n // A unidade em que a tela está muda QUEM tem agenda. Sem isto o seletor\n // continuaria mostrando o quadro da unidade anterior depois da troca.\n const activeUnitId = useActiveUnitId()\n\n useEffect(() => {\n fetchProfessionals(); fetchSchedules()\n if (config.modules.locationSelection) fetchLocations()\n }, [activeUnitId])\n\n // ── O padrão deixa de ser \"todas\" quando \"todas\" são muitas ──────────────\n //\n // Lista vazia sempre significou \"todas\", e numa clínica de seis agendas isso\n // é a resposta certa. Com 739 é uma semana com 739 colunas: a tela congela\n // antes de desenhar a primeira, e não há como escapar porque o seletor está\n // dentro dela.\n //\n // A saída não é recortar em silêncio — seria uma tela dizendo \"todas\" e\n // mostrando doze. É ESCOLHER por padrão: a seleção vira explícita, as doze\n // aparecem marcadas, as outras desmarcadas, e mudar isso é a mesma caixinha\n // de sempre. Só na primeira carga; depois disso quem manda é a pessoa.\n const seededDefault = useRef(false)\n useEffect(() => {\n if (seededDefault.current) return\n if (professionals.length === 0) return\n seededDefault.current = true\n if (selectedProfIds.length > 0) return\n if (professionals.length <= MAX_DEFAULT_AGENDAS) return\n setFilters({ professionalIds: professionals.slice(0, MAX_DEFAULT_AGENDAS).map((p) => p.id) })\n }, [professionals])\n\n // A troca de unidade recomeça a conversa: o quadro é outro, e uma seleção\n // feita sobre o anterior não descreve mais nada.\n useEffect(() => { seededDefault.current = false }, [activeUnitId])\n\n // Busca do seletor. Filtra o que está em memória; quando o servidor cortou no\n // teto (`professionalsTruncated`), quem não veio também precisa ser\n // encontrável, então a busca vai ao banco.\n const [profSearch, setProfSearch] = useState('')\n useEffect(() => {\n if (!professionalsTruncated) return\n const term = profSearch.trim()\n const timer = setTimeout(() => { void fetchProfessionals(term ? { search: term } : undefined) }, 250)\n return () => clearTimeout(timer)\n }, [profSearch, professionalsTruncated])\n\n // Keep the view consistent with resource-capability, in case a stale/shared\n // pref selected the wrong variant. No resources → a resource view is an empty\n // grid that drops the seeded events; resources → a plain timegrid loses the\n // per-professional columns.\n useEffect(() => {\n const api = calendarRef.current?.getApi()\n if (!api) return\n if (!resourceCapable && currentView.startsWith('resource')) {\n api.changeView('dayGridMonth')\n } else if (resourceCapable && (currentView === 'timeGridWeek' || currentView === 'timeGridDay')) {\n api.changeView(viewForResources(currentView))\n }\n }, [resourceCapable, currentView])\n\n // Mobile renders the agenda list (no FullCalendar), so the grid's datesSet —\n // which normally drives fetchBookings — never fires. Fetch a wide upcoming\n // window directly so the list has data.\n useEffect(() => {\n if (!isMobile) return\n const start = new Date(); start.setHours(0, 0, 0, 0); start.setDate(start.getDate() - 1)\n const end = new Date(start); end.setDate(end.getDate() + 91)\n fetchBookings({ start: start.toISOString(), end: end.toISOString() })\n }, [isMobile, fetchBookings])\n\n // A booking created outside the grid — the assistant, the public page,\n // another device — repaints the calendar it belongs to. Without this the\n // manager who just said \"agenda a Maria amanhã às 10\" still sees yesterday's\n // grid and reloads the tab by hand.\n const refreshVisibleBookings = useCallback(() => {\n if (visibleRange) {\n void fetchBookings(visibleRange)\n return\n }\n const start = new Date(); start.setHours(0, 0, 0, 0); start.setDate(start.getDate() - 1)\n const end = new Date(start); end.setDate(end.getDate() + 91)\n void fetchBookings({ start: start.toISOString(), end: end.toISOString() })\n }, [visibleRange, fetchBookings])\n\n useDataChanged({}, refreshVisibleBookings, [refreshVisibleBookings])\n\n // Writes this tab never saw — a Google webhook, another device, the public\n // booking page — arrive through the provider's realtime subscription. The\n // 30s visibility-aware poll is the net for a sleeping/disconnected socket;\n // a hidden tab does no database work, and returning to it refreshes at once.\n useEffect(() => {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n\n let refreshTimer: ReturnType<typeof setTimeout> | undefined\n let unsubscribe: (() => void) | undefined\n\n const scheduleRefresh = (delay = 0) => {\n if (document.visibilityState === 'hidden') return\n if (refreshTimer) clearTimeout(refreshTimer)\n refreshTimer = setTimeout(refreshVisibleBookings, delay)\n }\n\n try {\n unsubscribe = provider.subscribeToBookingChanges?.(() => scheduleRefresh(AGENDA_REALTIME_DEBOUNCE_MS))\n } catch (error) {\n console.warn('[agenda] Realtime unavailable; using the polling fallback.', error)\n }\n\n const pollTimer = window.setInterval(() => scheduleRefresh(), AGENDA_POLL_INTERVAL_MS)\n const onVisibilityChange = () => { if (document.visibilityState === 'visible') scheduleRefresh() }\n const onFocus = () => scheduleRefresh()\n\n document.addEventListener('visibilitychange', onVisibilityChange)\n window.addEventListener('focus', onFocus)\n\n return () => {\n if (refreshTimer) clearTimeout(refreshTimer)\n window.clearInterval(pollTimer)\n document.removeEventListener('visibilitychange', onVisibilityChange)\n window.removeEventListener('focus', onFocus)\n unsubscribe?.()\n }\n }, [provider, refreshVisibleBookings])\n\n const drawnProfessionals = useMemo(() => (\n selectedProfIds.length > 0\n ? professionals.filter((p) => selectedProfIds.includes(p.id))\n : professionals.slice(0, MAX_SELECTED_AGENDAS)\n ), [professionals, selectedProfIds])\n\n const resources = useMemo(() => drawnProfessionals.map((p) => ({\n id: p.id, title: p.name,\n extendedProps: { avatarUrl: p.avatarUrl, locationName: p.locationName },\n })), [drawnProfessionals])\n\n const visibleResourceIds = useMemo(() => resources.map((resource) => resource.id), [resources])\n\n // A largura ABAIXO da qual a grade para de encolher. Acima dela o `min-width`\n // não faz nada e o layout é o de sempre — é só quando a tela aperta que ele\n // segura o piso e a rolagem aparece.\n //\n // `undefined` fora das views de recurso: lá as colunas são os sete dias e\n // sete sempre couberam, e um piso à toa só criaria rolagem sem motivo.\n const gridMinWidth = useMemo(() => {\n if (!currentView.startsWith('resource')) return undefined\n const daysInView = currentView.endsWith('Day') ? 1 : 7\n const columns = Math.max(1, resources.length) * daysInView\n // Mais a régua de horas à esquerda, que não é coluna de dia mas ocupa.\n return columns * MIN_COLUMN_PX + 64\n }, [currentView, resources.length])\n\n const bookingEvents = useMemo(() =>\n bookings.map((b) => bookingToEvent(b, statusColors, visibleResourceIds)),\n [bookings, statusColors, visibleResourceIds])\n\n // Merge static config locations with dynamically fetched locations\n const allLocations = useMemo(() => {\n const map = new Map<string, string>()\n for (const loc of config.locations) map.set(loc.id, loc.name)\n for (const loc of storeLocations) map.set(loc.id, loc.name)\n return map\n }, [config.locations, storeLocations])\n\n const locationMap = useMemo(() => {\n if (!config.modules.locationSelection || allLocations.size === 0) return undefined\n return allLocations\n }, [config.modules.locationSelection, allLocations])\n\n // Só as agendas DESENHADAS: um evento de disponibilidade para uma coluna que\n // não existe não aparece em lugar nenhum, e gerar um por dia por profissional\n // para 739 pessoas custa o mesmo que desenhá-las.\n const availabilityEvents = useMemo(() =>\n generateAvailabilityEvents(schedules, drawnProfessionals, visibleRange, effectiveBusinessHours, locationMap),\n [schedules, drawnProfessionals, visibleRange, effectiveBusinessHours, locationMap])\n\n const events = useMemo(() =>\n [...bookingEvents, ...availabilityEvents], [bookingEvents, availabilityEvents])\n\n const storedView = prefs.get('calendarView')\n const effectiveInitialView = resourceCapable ? viewForResources(storedView) : viewForNoResources(storedView)\n\n // ── Calendar handlers ──\n const handleDatesSet = useCallback((arg: { startStr: string; endStr: string; view: { title: string; type: string } }) => {\n setCalendarTitle(arg.view.title)\n setView(arg.view.type)\n setVisibleRange({ start: arg.startStr, end: arg.endStr })\n fetchBookings({ start: arg.startStr, end: arg.endStr })\n }, [fetchBookings, setView])\n\n // Double-click → open edit directly\n // Right-click → context menu\n const handleEventDidMount = useCallback((arg: { event: any; el: HTMLElement }) => {\n const booking = arg.event.extendedProps?.booking as CalendarBooking | undefined\n if (booking) arg.el.setAttribute('data-booking-id', booking.id)\n arg.el.addEventListener('dblclick', (e) => {\n e.preventDefault()\n e.stopPropagation()\n skipClickRef.current = true\n const booking = arg.event.extendedProps.booking as CalendarBooking\n setSelectedBooking(null)\n setPopoverAnchor(null)\n setContextMenu(null)\n openModal('edit', { bookingId: booking.id })\n })\n arg.el.addEventListener('contextmenu', (e) => {\n e.preventDefault()\n const booking = arg.event.extendedProps.booking as CalendarBooking\n const menuW = 210, menuH = 200\n let x = e.clientX + 4\n let y = e.clientY + 4\n if (x + menuW > window.innerWidth - 12) x = x - menuW\n if (y + menuH > window.innerHeight - 12) y = y - menuH\n setContextMenu({ booking, x, y })\n setContextMenuVisible(true)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n })\n }, [])\n\n // Flag to suppress single-click after a double-click\n const skipClickRef = useRef(false)\n\n // Hover timer — show popover after 4s hover on a booking event\n const hoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n const handleEventMouseEnter = useCallback((arg: { event: any; el: HTMLElement }) => {\n if (arg.event.display === 'background') return\n if (arg.event.extendedProps?.isLocationLabel) return\n const booking = arg.event.extendedProps.booking as CalendarBooking\n if (!booking) return\n\n hoverTimerRef.current = setTimeout(() => {\n const rect = arg.el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (x < 16) x = Math.max(16, rect.left + rect.width / 2 - popW / 2)\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }, 3000)\n }, [])\n\n const handleEventMouseLeave = useCallback(() => {\n if (hoverTimerRef.current) {\n clearTimeout(hoverTimerRef.current)\n hoverTimerRef.current = null\n }\n }, [])\n\n // Single click — open popover instantly, or slide to new position if already open\n const handleEventClick = useCallback((arg: EventClickArg) => {\n if (skipClickRef.current) { skipClickRef.current = false; return }\n // Ignore clicks on background availability events and location labels\n if (arg.event.display === 'background') return\n if (arg.event.extendedProps?.isLocationLabel) return\n setContextMenu(null); setContextMenuVisible(false)\n const booking = arg.event.extendedProps.booking as CalendarBooking\n if (!booking) return\n const rect = arg.el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (x < 16) x = Math.max(16, rect.left + rect.width / 2 - popW / 2)\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n // Always update — if popover is already open it slides to the new position\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }, [])\n\n // Find the schedule block covering a given time slot for a professional\n const findScheduleForSlot = useCallback((professionalId: string | undefined, dateTimeStr: string): Schedule | null => {\n if (!professionalId) return null\n const dt = new Date(dateTimeStr)\n const dateStr = dt.toISOString().slice(0, 10)\n const dayOfWeek = dt.getDay()\n const timeMin = dt.getHours() * 60 + dt.getMinutes()\n\n const profSchedules = schedules.filter((s) => s.assigneeId === professionalId)\n const exceptions = profSchedules.filter((s) => s.specificDate === dateStr && s.isActive)\n const weekly = profSchedules.filter((s) => s.dayOfWeek === dayOfWeek && s.isActive && !s.specificDate)\n const daySchedules = exceptions.length > 0 ? exceptions : weekly\n\n for (const s of daySchedules) {\n const [sh, sm] = s.startsAt.split(':').map(Number)\n const [eh, em] = s.endsAt.split(':').map(Number)\n if (timeMin >= sh * 60 + sm && timeMin < eh * 60 + em) return s\n }\n return null\n }, [schedules])\n\n const handleSelect = useCallback((arg: DateSelectArg) => {\n calendarRef.current?.getApi().unselect()\n\n // Don't open create if popover/context menu is showing — dismiss them instead\n if (popoverVisibleRef.current || contextMenuVisibleRef.current) {\n setPopoverVisible(false); setSelectedBooking(null); setPopoverAnchor(null)\n setContextMenuVisible(false); setContextMenu(null)\n return\n }\n\n const professionalId = arg.resource?.id\n const schedule = findScheduleForSlot(professionalId, arg.startStr)\n\n const proceed = () => {\n const locId = schedule?.locationId ?? (schedule?.metadata?.locationId as string | undefined)\n openModal('create', { prefill: { startsAt: arg.startStr, endsAt: arg.endStr, professionalId, locationId: locId || undefined } })\n }\n\n // Warn if no schedule covers this slot — only when the working-hours module\n // is on (off by default in eventMode:'simple', so simple/Google-Calendar\n // events never surface the \"no open schedule for this professional\" dialog).\n if (config.modules.workingHours && !schedule) {\n setScheduleConfirm({ onConfirm: proceed })\n return\n }\n\n proceed()\n }, [openModal, findScheduleForSlot, config.modules.workingHours])\n\n const handleEventDrop = useCallback(async (arg: EventDropArg) => {\n const booking = arg.event.extendedProps.booking as CalendarBooking\n try { await rescheduleBooking(booking.id, arg.event.startStr, arg.event.endStr, arg.newResource?.id ?? undefined) }\n catch { arg.revert() }\n }, [rescheduleBooking])\n\n const handleViewChange = useCallback((v: string) => {\n calendarRef.current?.getApi().changeView(v)\n prefs.set('calendarView', v)\n }, [prefs])\n // Mobile switcher: swap between the list sentinel and a real grid view. When a\n // grid is picked we also sync the store's currentView so the resource-collapse\n // effect doesn't fight the freshly-mounted mobile calendar; if it's already\n // mounted (grid → grid), changeView animates in place.\n const handleMobileViewChange = useCallback((v: string) => {\n setMobileView(v)\n if (v === MOBILE_LIST_VIEW) return\n setView(v)\n calendarRef.current?.getApi()?.changeView(v)\n }, [setView])\n const handlePrev = useCallback(() => calendarRef.current?.getApi().prev(), [])\n const handleNext = useCallback(() => calendarRef.current?.getApi().next(), [])\n const handleToday = useCallback(() => { calendarRef.current?.getApi().today(); setSelectedDate(new Date()) }, [])\n\n function handleMiniDateSelect(date: Date) {\n setSelectedDate(date)\n calendarRef.current?.getApi().gotoDate(date)\n }\n\n function toggleProfessional(id: string) {\n if (selectedProfIds.includes(id)) {\n setFilters({ professionalIds: selectedProfIds.filter((p) => p !== id) })\n return\n }\n // Recusar é melhor do que aceitar e desenhar ilegível. A alternativa —\n // deixar marcar e mostrar colunas de 14px — foi o que quebrou a tela.\n if (selectedProfIds.length >= MAX_SELECTED_AGENDAS) {\n toast.error(t('agenda.sidebar.tooManyAgendas', { max: String(MAX_SELECTED_AGENDAS) }))\n return\n }\n setFilters({ professionalIds: [...selectedProfIds, id] })\n }\n\n function toggleStatus(value: string) {\n const next = selectedStatuses.includes(value)\n ? selectedStatuses.filter((s) => s !== value)\n : [...selectedStatuses, value]\n setFilters({ statuses: next })\n }\n\n // Alternating resource backgrounds — apply via DOM after render\n const wrapperRef = useRef<HTMLDivElement>(null)\n\n // FullCalendar measures its columns once and only re-measures on a WINDOW\n // resize. Opening/closing the assistant rail (or the sidebar) resizes the\n // container without one, so the grid stayed locked at the narrow width until\n // a real window resize came along. Watch the container and hand FC the new box.\n useEffect(() => {\n const container = wrapperRef.current\n if (!container) return\n let frame = 0\n let lastWidth = container.clientWidth\n let lastHeight = container.clientHeight\n const ro = new ResizeObserver(() => {\n const width = container.clientWidth\n const height = container.clientHeight\n if (width === lastWidth && height === lastHeight) return\n lastWidth = width\n lastHeight = height\n // Next frame, not inline: measuring inside the observer callback reads a\n // mid-layout box (and trips the RO loop warning). The rail animates, so\n // this fires on each frame and the last one settles on the final width.\n cancelAnimationFrame(frame)\n frame = requestAnimationFrame(() => calendarRef.current?.getApi()?.updateSize())\n })\n ro.observe(container)\n return () => { cancelAnimationFrame(frame); ro.disconnect() }\n // Re-attach whenever the calendar branch remounts (skeleton → grid, mobile\n // list → grid), since the observed node is gone on the other branches.\n }, [isMobile, mobileGridActive, professionalsLoading, professionals.length])\n\n // Responsive day headers — collapse weekday names to a single initial (S M T\n // W T F S, Google-Calendar style) when day columns get too narrow. Measured\n // from the actual rendered column width so it adapts to resource count + view.\n const [dayHeaderCompact, setDayHeaderCompact] = useState(false)\n useEffect(() => {\n const container = wrapperRef.current\n if (!container) return\n let frame = 0\n const measure = () => {\n // Measure an actual DAY column ([data-date]) — in resource views the first\n // .fc-col-header-cell is the wide resource header, not a day column.\n const cell = container.querySelector('.fc-col-header-cell[data-date]') as HTMLElement | null\n if (!cell) return\n const colWidth = cell.getBoundingClientRect().width\n // Collapse to single-letter ONLY when the full weekday label can't fit.\n // Measure the widest full line (\"WED\" / \"12/14\") in the header's font so\n // the breakpoint adapts to font + locale instead of a magic number.\n const cushion = (cell.querySelector('.fc-col-header-cell-cushion') as HTMLElement | null) ?? cell\n const cs = getComputedStyle(cushion)\n const probe = document.createElement('span')\n probe.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;top:-9999px'\n probe.style.fontSize = cs.fontSize\n probe.style.fontWeight = cs.fontWeight\n probe.style.fontFamily = cs.fontFamily\n probe.style.letterSpacing = cs.letterSpacing\n probe.style.textTransform = cs.textTransform\n document.body.appendChild(probe)\n probe.textContent = 'Wed'\n const weekdayWidth = probe.getBoundingClientRect().width\n probe.textContent = '12/14'\n const dateWidth = probe.getBoundingClientRect().width\n probe.remove()\n const needed = Math.max(weekdayWidth, dateWidth) + 12 // text + cushion padding\n setDayHeaderCompact(colWidth < needed)\n }\n // FullCalendar reflows its inner day columns on a later tick than the\n // container resize, so re-measure across a few frames to read settled widths.\n const timers: ReturnType<typeof setTimeout>[] = []\n const schedule = () => {\n cancelAnimationFrame(frame)\n frame = requestAnimationFrame(measure)\n timers.forEach(clearTimeout)\n timers.length = 0\n timers.push(setTimeout(measure, 130), setTimeout(measure, 330))\n }\n schedule()\n const ro = new ResizeObserver(schedule)\n ro.observe(container)\n return () => { cancelAnimationFrame(frame); timers.forEach(clearTimeout); ro.disconnect() }\n }, [resources, currentView, visibleRange])\n\n const applyResourceStriping = useCallback(() => {\n const container = wrapperRef.current\n if (!container) return\n const resourceIds = resources.map((r: { id: string }) => r.id)\n if (resourceIds.length < 2) return\n container.querySelectorAll('[data-resource-id]').forEach((el: Element) => {\n const rid = el.getAttribute('data-resource-id')\n const idx = rid ? resourceIds.indexOf(rid) : -1\n el.classList.toggle('fc-resource-alt', idx % 2 === 1)\n })\n }, [resources])\n\n useEffect(() => {\n applyResourceStriping()\n const t1 = setTimeout(applyResourceStriping, 100)\n const t2 = setTimeout(applyResourceStriping, 300)\n return () => { clearTimeout(t1); clearTimeout(t2) }\n }, [applyResourceStriping, currentView, visibleRange, bookings])\n\n // Listen for cross-plugin booking open requests (e.g., from financial invoice detail)\n useEffect(() => {\n function handleOpenBooking(e: Event) {\n const detail = (e as CustomEvent).detail ?? {}\n const externalSource = detail.source\n ? { type: String(detail.source), id: detail.waitlistId, waitlistId: detail.waitlistId }\n : undefined\n if (detail.bookingId) {\n openModal('edit', { bookingId: detail.bookingId, externalSource })\n return\n }\n openModal('create', {\n prefill: detail.prefill ?? {\n clientId: detail.clientId,\n professionalId: detail.professionalId,\n locationId: detail.locationId,\n startsAt: detail.startsAt,\n },\n externalSource,\n })\n }\n window.addEventListener('agenda:open-booking', handleOpenBooking)\n return () => window.removeEventListener('agenda:open-booking', handleOpenBooking)\n }, [openModal])\n\n // Custom day header: weekday + date stacked. When columns get narrow it\n // collapses the weekday to a single initial (S / 16, Google-Calendar style).\n // Always returns explicit content — returning undefined renders an EMPTY\n // header in the React adapter rather than falling back to the default.\n const dayHeaderContent = useCallback((arg: any) => {\n const date: Date = arg.date\n const dateLocale = currentLocale === 'pt-BR' ? 'pt-BR' : 'en'\n // Inline styles (not CSS classes) so stacking is guaranteed regardless of\n // the runtime style-injection state.\n const wrapStyle: React.CSSProperties = { display: 'flex', flexDirection: 'column', alignItems: 'center', lineHeight: 1.15 }\n const dateStyle: React.CSSProperties = { fontSize: '0.65rem', opacity: 0.75 }\n if (dayHeaderCompact) {\n const letter = date.toLocaleDateString(dateLocale, { weekday: 'narrow' })\n return (\n <div style={wrapStyle}>\n <span style={{ fontWeight: 600 }}>{letter}</span>\n <span style={dateStyle}>{date.getDate()}</span>\n </div>\n )\n }\n const weekday = date.toLocaleDateString(dateLocale, { weekday: 'short' })\n return (\n <div style={wrapStyle}>\n <span>{weekday}</span>\n <span style={dateStyle}>{`${date.getMonth() + 1}/${date.getDate()}`}</span>\n </div>\n )\n }, [dayHeaderCompact, currentLocale])\n\n const resourceLabelContent = useCallback((arg: any) => {\n const { id, title, extendedProps } = arg.resource\n const initials = title.split(' ').map((n: string) => n[0]).join('').slice(0, 2)\n return (\n <div className=\"flex items-center gap-2 px-2 py-1.5\" title={title}>\n <div className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary/10 text-[10px] font-bold text-primary\">{initials}</div>\n <div className=\"min-w-0\">\n <PersonLink\n personId={id}\n name={abbreviateName(title)}\n size=\"sm\"\n tab=\"schedule\"\n profileHref={`#/registry/staff/${id}/schedule`}\n />\n {extendedProps?.locationName && <p className=\"text-[10px] text-muted-foreground truncate\">{extendedProps.locationName}</p>}\n </div>\n </div>\n )\n }, [])\n\n const eventContent = useCallback((arg: any) => {\n // Location label events — render as a small tag\n if (arg.event.extendedProps?.isLocationLabel) {\n return (\n <div className=\"px-1.5 py-0.5 overflow-hidden\">\n <p className=\"text-[10px] font-medium truncate\">{arg.event.title}</p>\n </div>\n )\n }\n const serviceNames = arg.event.extendedProps?.serviceNames\n const start = arg.event.start\n const end = arg.event.end\n const fmt = (d: Date) => `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`\n const timeRange = start && end ? `${fmt(start)} – ${fmt(end)}` : start ? fmt(start) : ''\n return (\n <div className=\"px-1.5 py-0.5 overflow-hidden leading-tight h-full\">\n <div className=\"flex items-start justify-between gap-1\">\n <p className=\"text-[11px] font-semibold truncate\">{arg.event.title}</p>\n {serviceNames && <p className=\"text-[10px] opacity-60 truncate shrink-0 max-w-[45%] text-right\">{serviceNames}</p>}\n </div>\n {timeRange && <p className=\"text-[9px] opacity-50\">{timeRange}</p>}\n </div>\n )\n }, [])\n\n return (\n <div ref={shellRef} className=\"flex\" style={{ height: shellHeight ?? undefined }}>\n {/* ═══ LEFT SIDEBAR — hidden on mobile ═══ */}\n <div className=\"hidden md:flex w-[220px] shrink-0 flex-col overflow-y-auto py-4 px-3 mr-4\">\n {/* + Create button */}\n <button\n onClick={() => openModal('create')}\n className=\"flex items-center gap-2 rounded-button bg-primary text-primary-foreground border border-primary pl-3 pr-4 py-1.5 text-sm font-semibold hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-all mb-6 w-fit\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('agenda.sidebar.create')}\n </button>\n\n {/* Mini month calendar */}\n <MiniCalendar selectedDate={selectedDate} onDateSelect={handleMiniDateSelect} />\n\n {/* Agendas (professional filter) — hidden when no booking type uses a\n professional (e.g. eventMode:'simple'). */}\n {config.capabilities.professional && (<>\n <div className=\"h-px bg-border my-4\" />\n <FilterSection title={t('agenda.sidebar.agendas')}>\n <ProfessionalFilterList\n names={professionals.map((p) => ({ id: p.id, label: p.name }))}\n selected={selectedProfIds}\n onToggle={toggleProfessional}\n search={profSearch}\n onSearchChange={setProfSearch}\n searchPlaceholder={t('agenda.sidebar.searchAgendas')}\n maxRows={MAX_PICKER_ROWS}\n />\n </FilterSection>\n </>)}\n\n {/* Status filter — hidden when no booking type uses a status workflow\n (e.g. eventMode:'simple'). */}\n {config.capabilities.status && (<>\n <div className=\"h-px bg-border my-4\" />\n <FilterSection title={t('agenda.sidebar.status')}>\n <StatusFilterList\n statuses={config.statuses}\n selected={selectedStatuses}\n onToggle={toggleStatus}\n />\n </FilterSection>\n </>)}\n </div>\n\n {/* On a phone these two lived in a toolbar row of their own, which left a\n near-empty 48px band under a bar that was already naming the screen.\n The shell's page header has the room and is where every other screen\n puts its actions. */}\n {/* Declared, so the shell decides where they go: a caret on desktop, the\n FAB on a phone. As raw buttons they were a row of their own under a bar\n that already named the screen. */}\n {isMobile && (\n <PageHeaderActions>\n <PageActions\n actions={[\n {\n id: 'new-booking',\n label: t('agenda.calendar.newAppointment'),\n icon: Plus,\n intent: 'primary',\n creates: true,\n onSelect: () => openModal('create'),\n },\n {\n id: 'agenda-settings',\n label: t('agenda.settings.title'),\n icon: Settings,\n // Utility, not an alternative way to book: the shell gives it\n // its own quiet circle above the \"+\" instead of hiding it in a\n // create menu.\n intent: 'utility',\n onSelect: () => { window.location.hash = '/settings/agenda' },\n },\n ]}\n />\n </PageHeaderActions>\n )}\n\n {/* ═══ MAIN AREA ═══ */}\n {/* `min-h-0` junto com `min-w-0`: esta coluna é item de flex da linha de\n altura definida acima, e sem ele ela pode crescer além dela — aí o\n `flex-1` da grade lá dentro resolve contra uma altura errada e sobra\n branco embaixo do calendário. A corrente só funciona se TODO nível\n declarar que pode encolher. */}\n <div className=\"flex-1 flex flex-col min-w-0 min-h-0 overflow-hidden\">\n {/* Toolbar */}\n <div className=\"shrink-0 border-b\">\n {/* Row 1 — create + date nav + title (left), desktop switcher + settings\n (right). Extra right padding on mobile clears the transparent header's\n floating profile avatar, which otherwise overlaps the settings gear. */}\n <div className={`${mobileGridActive ? 'flex' : 'hidden'} md:flex h-12 items-center justify-between pl-4 pr-4`}>\n <div className=\"flex items-center gap-3 min-w-0\">\n {/* Date navigation drives the FullCalendar api — shown on desktop and,\n on mobile, only when a grid view is active (the list paginates\n itself, so it has no grid to page through). */}\n <div className={`${mobileGridActive ? 'flex' : 'hidden'} md:flex items-center gap-3`}>\n <button onClick={handleToday}\n className=\"rounded-md border px-3 py-1 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">\n {t('agenda.toolbar.today')}\n </button>\n <div className=\"flex items-center gap-0.5\">\n <button onClick={handlePrev} className=\"flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <button onClick={handleNext} className=\"flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors\">\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {/* On a phone the shell's page bar already says \"Agenda\"; repeating\n it here cost a line and said nothing. The date range is the one\n thing that bar cannot know, so a grid view still shows it. */}\n {!(isMobile && !mobileGridActive) && (\n <h2 className=\"truncate text-base font-normal sm:text-lg\">{calendarTitle}</h2>\n )}\n </div>\n\n <div className=\"flex items-center gap-1 shrink-0\">\n <div className=\"hidden md:flex items-center gap-1\">\n {viewOptions.map((opt) => (\n <button key={opt.key} onClick={() => handleViewChange(opt.key)}\n className={`rounded-md px-3 py-1 text-sm transition-colors ${\n currentView === opt.key\n ? 'bg-primary/10 text-primary font-medium'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}>\n {t(opt.labelKey)}\n </button>\n ))}\n </div>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => window.location.hash = '/settings/agenda'}\n aria-label={t('agenda.settings.title')}\n title={t('agenda.settings.title')}\n className=\"ml-1 hidden md:inline-flex\"\n >\n <Settings className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Row 2 (mobile only) — compact segmented view switcher on its own row so\n it never collides with the floating avatar. Dia/Semana/Mês mount the\n calendar; Lista returns to the thumb-friendly agenda list. */}\n <div className=\"flex md:hidden items-center gap-1 overflow-x-auto px-3 pb-2\">\n {mobileViewOptions.map((opt) => (\n <button key={opt.key} onClick={() => handleMobileViewChange(opt.key)}\n aria-pressed={mobileView === opt.key}\n className={`flex min-h-[2.75rem] shrink-0 items-center rounded-full px-4 text-sm transition-colors active:scale-[0.98] ${\n mobileView === opt.key\n ? 'bg-primary/10 font-medium text-primary'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}>\n {t(opt.labelKey)}\n </button>\n ))}\n </div>\n </div>\n\n {/* Mobile list view → thumb-friendly agenda list; otherwise (desktop, or a\n mobile grid view the user switched to) → FullCalendar grid.\n\n No wrapper da grade, `min-h-0`/`min-w-0` não são enfeite: um item de\n flex nasce com `min-*: auto` e não encolhe abaixo do conteúdo.\n Enquanto ali era `overflow-hidden` o recorte escondia isso; com a\n rolagem horizontal ligada a caixa passou a CRESCER com a grade e a\n empurrar a página inteira — o vazio embaixo do calendário. */}\n {isMobile && !mobileGridActive ? (\n // The mobile branch used to sit in front of the loading check, so the\n // list rendered empty while the query ran — which on this screen reads\n // as \"nothing scheduled\", the one wrong answer it must not give.\n bookingsLoading && bookings.length === 0 ? (\n <AgendaMobileListSkeleton />\n ) : (\n <AgendaMobileList\n bookings={bookings}\n statusColors={statusColors}\n currencyCode={config.currency.code}\n onSelect={(b) => openModal('edit', { bookingId: b.id })}\n onCreate={() => openModal('create')}\n />\n )\n ) : professionalsLoading && professionals.length === 0 ? (\n <CalendarSkeleton profCount={2} />\n ) : (\n <div ref={wrapperRef} className=\"min-h-0 min-w-0 flex-1 overflow-x-auto overflow-y-hidden agenda-calendar\">\n {/* Em fluxo e `h-full`: tirar este filho do fluxo (`absolute`) quebra a\n medição do FullCalendar, que passa a desenhar na altura natural e\n deixa o resto do contêiner vazio. `h-full` resolve porque o pai é\n um item de flex com `min-h-0` numa coluna de altura definida —\n é o `min-h-0` que torna a altura dele definida, e sem ele nada\n nesta corrente funciona. */}\n <div className=\"h-full\" style={gridMinWidth ? { minWidth: gridMinWidth } : undefined}>\n <FullCalendar\n ref={calendarRef}\n plugins={[dayGridPlugin, timeGridPlugin, resourceTimeGridPlugin, interactionPlugin, listPlugin]}\n initialView={mobileGridActive ? mobileView : effectiveInitialView}\n schedulerLicenseKey=\"CC-Attribution-NonCommercial-NoDerivatives\"\n resources={resourceCapable ? resources : undefined}\n events={events}\n headerToolbar={false}\n locale={fcLocale}\n height=\"100%\"\n slotMinTime={effectiveBusinessHours.startTime + ':00'}\n slotMaxTime={effectiveBusinessHours.endTime + ':00'}\n slotDuration={{ minutes: config.slotDuration }}\n allDaySlot={false}\n nowIndicator={true}\n editable={config.modules.dragAndDrop}\n selectable={true}\n selectMirror={true}\n eventOverlap={false}\n datesSet={handleDatesSet}\n eventDidMount={handleEventDidMount}\n eventClick={handleEventClick}\n eventMouseEnter={handleEventMouseEnter}\n eventMouseLeave={handleEventMouseLeave}\n select={handleSelect}\n eventDrop={handleEventDrop}\n resourceLabelContent={resourceLabelContent}\n dayHeaderContent={dayHeaderContent}\n eventContent={eventContent}\n resourceOrder=\"title\"\n stickyHeaderDates={true}\n expandRows={false}\n eventTimeFormat={{ hour: '2-digit', minute: '2-digit', hour12: false }}\n slotLabelFormat={{ hour: '2-digit', minute: '2-digit', hour12: false }}\n />\n </div>\n </div>\n )}\n </div>\n\n {/* Popover — stays mounted until animation finishes */}\n {selectedBooking && popoverAnchor && popoverVisible && (\n <AppointmentPopover booking={selectedBooking} position={popoverAnchor}\n onClose={() => {\n // Called AFTER the popover's exit animation finishes\n setPopoverVisible(false)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n }}\n onEdit={(id) => {\n setPopoverVisible(false)\n setSelectedBooking(null)\n setPopoverAnchor(null)\n openModal('edit', { bookingId: id })\n }} />\n )}\n\n {/* Context Menu */}\n {contextMenu && (\n <EventContextMenu\n booking={contextMenu.booking}\n position={{ x: contextMenu.x, y: contextMenu.y }}\n onClose={() => { setContextMenuVisible(false); setContextMenu(null) }}\n onEdit={(id) => { setContextMenuVisible(false); setContextMenu(null); openModal('edit', { bookingId: id }) }}\n />\n )}\n\n {/* No-schedule confirm */}\n <ConfirmDialog\n open={!!scheduleConfirm}\n variant=\"warning\"\n title={t('agenda.calendar.noScheduleConfirm')}\n confirmLabel={t('common.confirm')}\n cancelLabel={t('common.cancel')}\n onConfirm={() => { const cb = scheduleConfirm?.onConfirm; setScheduleConfirm(null); cb?.() }}\n onCancel={() => setScheduleConfirm(null)}\n />\n\n {/* Booking form — always mounted; it shows itself in the shell's right\n column (or a sheet, where there is no column) */}\n <AppointmentModal\n open={modalState.open}\n mode={modalState.mode}\n bookingId={modalState.bookingId}\n prefill={modalState.prefill}\n initialTab={modalState.initialTab}\n externalSource={modalState.externalSource}\n onClose={closeModal}\n onCreated={(newId, source) => {\n if (config.onBookingCreated) {\n void Promise.resolve(config.onBookingCreated({ bookingId: newId, source })).catch((error: unknown) => {\n console.error('Failed to run agenda booking-created bridge', error)\n })\n }\n // After a short delay (let calendar re-render), find the event and show popover\n setTimeout(() => {\n const booking = bookings.find((b: CalendarBooking) => b.id === newId)\n if (!booking) return\n const el = document.querySelector(`[data-booking-id=\"${newId}\"]`) as HTMLElement | null\n if (el) {\n const rect = el.getBoundingClientRect()\n const popW = 320, popH = 340\n let x = rect.right + 8\n let y = rect.top + rect.height / 2 - popH / 2\n if (x + popW > window.innerWidth - 16) x = rect.left - popW - 8\n if (y + popH > window.innerHeight - 16) y = window.innerHeight - popH - 16\n if (y < 16) y = 16\n setSelectedBooking(booking)\n setPopoverAnchor({ x, y })\n setPopoverVisible(true)\n }\n }, 400)\n }} />\n </div>\n )\n}\n","let t: string | undefined\nexport function setAgendaTenantId(id: string | undefined){ t = id }\nexport function getAgendaTenantId(): string | undefined { return t }\n","import React from 'react'\nimport { usePluginRuntimeOptional } from '@fayz-ai/core'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { AgendaContextProvider } from '../context'\nimport type { ResolvedAgendaConfig } from '../config'\nimport type { AgendaDataProvider } from '../data/types'\nimport type { AgendaUIState } from '../store'\nimport { CalendarView } from './CalendarView'\nimport { setAgendaTenantId } from '../lib/tenant'\n\n// ---------------------------------------------------------------------------\n// Main page — clean single-page calendar, no module nav wrapper\n// ---------------------------------------------------------------------------\n\nexport function AgendaPage({ config, provider, store }: {\n config: ResolvedAgendaConfig\n provider: AgendaDataProvider\n store: StoreApi<AgendaUIState>\n}) {\n const runtime = usePluginRuntimeOptional()\n const tenantId = runtime?.context.tenant?.id\n\n React.useEffect(() => {\n setAgendaTenantId(tenantId)\n return () => setAgendaTenantId(undefined)\n }, [tenantId])\n\n return (\n <AgendaContextProvider config={config} provider={provider} store={store}>\n <CalendarView />\n </AgendaContextProvider>\n )\n}\n","import React from 'react'\nimport { CheckCircle2, CircleAlert, CircleDollarSign, Clock, User } from 'lucide-react'\nimport { RightRailPage } from '@fayz-ai/admin'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Conferência de check-in.\n//\n// Receber alguém não é mudar um status. No V1 o clique em \"Check-in\" NÃO grava:\n// ele abre esta conferência, e o único PUT sai do botão do fim. Entre um e outro\n// a recepção resolve o que estaria faltando — cadastro, formulário, cobrança —\n// enquanto a pessoa ainda está na frente dela. Depois que ela senta, ninguém\n// mais volta atrás.\n//\n// Três blocos, na ordem em que a recepção olha: quem é o atendimento, se o\n// cadastro está de pé, e se o dinheiro está resolvido.\n//\n// E vai na COLUNA DA DIREITA da casca — a mesma que o assistente ocupa —, não\n// num modal nem numa gaveta própria. A fila continua visível ao lado enquanto se\n// confere uma pessoa, que é como a recepção trabalha: atende quem está na frente\n// sem perder de vista quem espera. `RightRailPage` já resolve isso e cai para\n// gaveta sozinho onde não existe rail; abrir a minha seria uma segunda gramática\n// disputando a mesma borda da tela.\n// ---------------------------------------------------------------------------\n\nexport interface CheckinRequirement {\n /** Nome do que falta — \"Anamnese\", \"Termo de consentimento\". */\n label: string\n /** Por que aparece: nunca preenchido, ou venceu. */\n detail: string\n /** Impede concluir, ou só avisa. */\n blocking?: boolean\n}\n\nexport interface CheckinDialogProps {\n booking: CalendarBooking\n statusLabel: string\n /** O que o cadastro do cliente ainda deve. Vazio = \"dados obrigatórios completos\". */\n requirements?: CheckinRequirement[]\n /** Abre a cobrança deste atendimento. Ausente = o host não tem para onde levar. */\n onReceive?: (b: CalendarBooking) => void\n /** Grava. É o ÚNICO que grava. */\n onConfirm: (b: CalendarBooking) => Promise<void>\n onClose: () => void\n formatCurrency?: (n: number) => string\n}\n\nconst brl = (n: number) => n.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })\n\nexport function CheckinDialog({\n booking, statusLabel, requirements = [], onReceive, onConfirm, onClose, formatCurrency = brl,\n}: CheckinDialogProps) {\n const [busy, setBusy] = React.useState(false)\n const blocking = requirements.filter((r) => r.blocking)\n const paid = booking.paymentStatus === 'paid'\n const hasBill = !!booking.paymentStatus && booking.paymentStatus !== 'none'\n\n const when = new Date(booking.startsAt).toLocaleString('pt-BR', {\n weekday: 'long', day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit',\n })\n\n return (\n <RightRailPage\n title={`Check-in — ${booking.clientName ?? 'Sem cliente'}`}\n open\n onClose={onClose}\n width=\"max-w-md\"\n >\n <div className=\"space-y-3 px-4 py-3\">\n <p className=\"truncate text-xs text-muted-foreground\">\n {when}{booking.professionalName ? ` · ${booking.professionalName}` : ''}\n </p>\n {/* 1. o atendimento */}\n <section className=\"rounded-xl border px-3 py-2\">\n <p className=\"text-[10px] font-medium uppercase text-muted-foreground\">Agendamento</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"inline-flex items-center gap-1\"><Clock className=\"h-3 w-3\" />\n {new Date(booking.startsAt).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}</span>\n <span className=\"rounded-full bg-muted px-2 py-0.5 font-medium\">{statusLabel}</span>\n {booking.services?.length ? (\n <span className=\"text-muted-foreground\">\n {booking.services.map((s) => s.name).join(', ')}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">Serviço não informado</span>\n )}\n </div>\n </section>\n\n {/* 2. o cadastro — e o que ele ainda deve */}\n <section className=\"rounded-xl border px-3 py-2\">\n <p className=\"text-[10px] font-medium uppercase text-muted-foreground\">Cadastro do cliente</p>\n {requirements.length === 0 ? (\n <p className=\"mt-1 inline-flex items-center gap-1.5 text-xs text-success\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" /> Dados obrigatórios completos\n </p>\n ) : (\n <ul className=\"mt-1 space-y-1\">\n {requirements.map((r) => (\n <li key={r.label} className=\"flex items-start gap-1.5 text-xs\">\n <CircleAlert className={`mt-0.5 h-3.5 w-3.5 shrink-0 ${r.blocking ? 'text-destructive' : 'text-warning'}`} />\n <span><span className=\"font-medium\">{r.label}</span>\n <span className=\"text-muted-foreground\"> — {r.detail}</span></span>\n </li>\n ))}\n </ul>\n )}\n </section>\n\n {/* 3. o dinheiro */}\n <section className=\"rounded-xl border px-3 py-2\">\n <p className=\"text-[10px] font-medium uppercase text-muted-foreground\">Pagamento</p>\n <div className=\"mt-1 flex items-center justify-between gap-2\">\n <p className=\"text-xs text-muted-foreground\">\n {paid\n ? 'Este atendimento já está pago.'\n : hasBill\n ? `Em aberto${booking.orderTotal ? ` · ${formatCurrency(booking.orderTotal)}` : ''}.`\n : 'Nenhuma fatura vinculada a este agendamento.'}\n </p>\n {onReceive && !paid && (\n <button\n onClick={() => onReceive(booking)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-button border border-input px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n <CircleDollarSign className=\"h-3.5 w-3.5\" /> Receber\n </button>\n )}\n </div>\n </section>\n <div className=\"flex items-center justify-between gap-2 border-t pt-3\">\n {/* Um bloqueio se explica onde ele acontece, e não depois do clique. */}\n <p className=\"text-[11px] text-muted-foreground\">\n {blocking.length ? `Falta ${blocking.map((r) => r.label).join(', ')}.` : ''}\n </p>\n <button\n disabled={busy || blocking.length > 0}\n onClick={async () => { setBusy(true); try { await onConfirm(booking) } finally { setBusy(false) } }}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n <User className=\"h-3.5 w-3.5\" /> {busy ? 'Concluindo…' : 'Concluir check-in'}\n </button>\n </div>\n </div>\n </RightRailPage>\n )\n}\n","import React from 'react'\nimport {\n PaymentStatusBadge as SharedPaymentStatusBadge,\n type PaymentStatusBadgeProps as SharedProps,\n type PaymentDetailLine,\n} from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { BookingPaymentStatus } from '../bridges/financial-bridge'\n\n// ---------------------------------------------------------------------------\n// O selo mora agora em `@fayz-ai/admin`: \"ja foi pago?\" e a mesma pergunta num\n// atendimento, num pedido do quadro e num ticket da cozinha, e a resposta sai\n// da mesma view do Financeiro. O que fica aqui e a UNICA parte que era da\n// agenda — os rotulos traduzidos por `agenda.payment.*`.\n//\n// O call site (CheckinView) nao muda: mesmo nome, mesmas props.\n// ---------------------------------------------------------------------------\n\nexport type { PaymentDetailLine }\n\nexport function PaymentStatusBadge(\n props: Omit<SharedProps, 'status' | 'labels'> & { status: BookingPaymentStatus },\n) {\n const t = useTranslation()\n const labels = React.useMemo(() => ({\n none: t('agenda.payment.title'),\n pending: t('agenda.payment.pending'),\n partial: t('agenda.payment.partial'),\n paid: t('agenda.payment.paid'),\n overdue: t('agenda.payment.overdue'),\n cancelled: t('agenda.payment.cancelled'),\n }), [t])\n\n return <SharedPaymentStatusBadge {...props} labels={labels} />\n}\n","import React from 'react'\nimport { LogIn, Clock, User, CheckCircle2, CircleDollarSign, Search, CalendarDays } from 'lucide-react'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { usePermissionOptional, PersonLink } from '@fayz-ai/admin'\nimport { CheckinDialog, type CheckinRequirement } from '../components/CheckinDialog'\nimport { AppointmentModal } from '../components/AppointmentModal'\nimport { PaymentStatusBadge, type PaymentDetailLine } from '../components/PaymentStatusBadge'\nimport { FilterSection, StatusFilterList, ProfessionalFilterList } from '../components/FilterRail'\nimport { ClientAccountModal } from '@fayz-ai/plugin-financial'\nimport { useAgendaStore, useAgendaConfig } from '../context'\nimport type { CalendarBooking } from '../types'\n\n// ---------------------------------------------------------------------------\n// Check-in: quem chega HOJE.\n//\n// A recepção não trabalha num calendário. Ela trabalha numa fila: quem já\n// chegou, quem está devendo, quem pode sentar. O calendário responde \"o que\n// acontece esta semana\"; esta tela responde \"quem está na minha frente agora\",\n// que é outra pergunta e merece outra tela.\n//\n// AS TRÊS COISAS QUE ELA MOSTRA, e por quê:\n//\n// · só HOJE. Um check-in de amanhã não existe, e uma lista que inclui\n// amanhã obriga a recepção a filtrar com os olhos a cada cliente.\n// · o estado de PAGAMENTO em cada cartão. É o que a recepção precisa saber\n// ANTES de a cliente sentar — depois do serviço, cobrar é constrangimento.\n// · o botão de receber ao lado do de check-in, não numa tela adiante.\n//\n// E O QUE ELA NÃO FAZ: pagamento NÃO bloqueia o check-in. É decisão do V1 e é\n// a certa — a cliente está na porta, e recusar a entrada de quem tem saldo em\n// aberto transforma a recepcionista em cobradora. Quem chegou, chegou; o que\n// se deve continua devido e visível.\n// ---------------------------------------------------------------------------\n\n/** As quatro que interessam a quem recebe. `completed` já saiu; `cancelled` e\n * `no_show` não vão chegar. */\nconst CHECKIN_STATUSES = ['scheduled', 'confirmed', 'waiting', 'in_progress'] as const\n\nconst STATUS_TONE: Record<string, string> = {\n scheduled: 'bg-muted text-muted-foreground',\n confirmed: 'bg-primary/10 text-primary',\n waiting: 'bg-warning/15 text-warning-foreground',\n in_progress: 'bg-success/15 text-success',\n}\n\n/** O que a recepção precisa ler de relance. `none` é o caso de quem ainda não\n * foi faturado — silêncio, não alarme. */\nconst PAYMENT_TEXT: Record<string, { label: string; tone: string }> = {\n paid: { label: 'Pago', tone: 'text-success' },\n partial: { label: 'Parcial', tone: 'text-warning' },\n pending: { label: 'Em aberto', tone: 'text-destructive' },\n overdue: { label: 'Vencido', tone: 'text-destructive' },\n}\n\nfunction todayRange() {\n const start = new Date(); start.setHours(0, 0, 0, 0)\n const end = new Date(); end.setHours(23, 59, 59, 999)\n return { start: start.toISOString(), end: end.toISOString() }\n}\n\n/** Há quanto tempo ela espera. O V1 mostra isto e é o que ordena a atenção da\n * recepção: quem chegou primeiro e ainda não sentou. */\nfunction waitedFor(iso: string): string {\n const min = Math.floor((Date.now() - new Date(iso).getTime()) / 60000)\n if (min < 1) return 'agora mesmo'\n if (min < 60) return `há ${min} min`\n const h = Math.floor(min / 60)\n return `há ${h}h${min % 60 ? ` ${min % 60}min` : ''}`\n}\n\nfunction hourOf(iso: string) {\n return new Date(iso).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })\n}\n\nexport interface CheckinViewProps {\n /** Abre o agendamento para EDITAR. O V1 tem esta ação na linha — a recepção\n * corrige um horário ou troca o profissional sem sair da fila. O host decide\n * COMO abrir porque o formulário de agendamento é da tela de agenda. */\n onOpenBooking?: (booking: CalendarBooking) => void\n /** Abre o recebimento para esta reserva. O host decide COMO — modal do\n * financeiro, ficha do pedido — porque quem tem o modal é ele. */\n onReceive?: (booking: CalendarBooking) => void\n}\n\nexport function CheckinView({ onReceive, onOpenBooking }: CheckinViewProps) {\n const config = useAgendaConfig()\n // E a PALAVRA vem de lá também. Enquanto a fila tinha o seu próprio\n // dicionário, \"Agendada\" aqui e \"Agendado\" na agenda eram o mesmo estado com\n // dois nomes, e trocar de aba obrigava a reaprender o vocabulário.\n const statusLabel = (v: string) => config.statuses.find((x) => x.value === v)?.label ?? v\n // Os quatro estados da fila, montados a partir da configuração da agenda —\n // mesma ordem, mesma cor, mesma palavra. Um estado que a casa não usa não\n // vira caixa de seleção aqui.\n const checkinStatuses = React.useMemo(\n () => CHECKIN_STATUSES\n .map((v) => config.statuses.find((x) => x.value === v))\n .filter((x): x is NonNullable<typeof x> => !!x),\n [config.statuses],\n )\n const bookings = useAgendaStore((s) => s.bookings)\n const loading = useAgendaStore((s) => s.bookingsLoading)\n const fetchBookings = useAgendaStore((s) => s.fetchBookings)\n const updateBookingStatus = useAgendaStore((s) => s.updateBookingStatus)\n const [term, setTerm] = React.useState('')\n const [busyId, setBusyId] = React.useState<string | null>(null)\n // O clique na linha NÃO grava: abre a conferência. O PUT sai de lá.\n // UM painel por vez. A coluna da direita tem UMA página (`RightRailPage` usa\n // um slot só), e três estados independentes conseguiam reivindicá-la juntos —\n // o título vinha de um painel e o corpo de outro, de clientes diferentes.\n // Estados separados descrevem três coisas; a coluna é uma.\n const [panel, setPanel] = React.useState<\n { kind: 'review' | 'edit' | 'charge'; booking: CalendarBooking } | null\n >(null)\n const reviewing = panel?.kind === 'review' ? panel.booking : null\n const editing = panel?.kind === 'edit' ? panel.booking : null\n const charging = panel?.kind === 'charge' ? panel.booking : null\n const setReviewing = (b: CalendarBooking | null) => setPanel(b ? { kind: 'review', booking: b } : null)\n const setEditing = (b: CalendarBooking | null) => setPanel(b ? { kind: 'edit', booking: b } : null)\n const setCharging = (b: CalendarBooking | null) => setPanel(b ? { kind: 'charge', booking: b } : null)\n // Cobrar acontece AQUI, com a conta do cliente à vista — não numa lista de\n // contas a receber do outro lado do app.\n // Editar o agendamento acontece SEM SAIR da fila.\n // Receber levanta a fatura, e isso é do Financeiro. Sem a permissão a RPC\n // recusa com 42501 e a rota do Financeiro responde \"acesso restrito\" — não se\n // oferece um botão cujo único desfecho é uma porta fechada.\n const can = usePermissionOptional()\n const canReceive = can('financial', 'create') || can('financial.receivables', 'create')\n\n // A fila pede os SEUS estados, não os do calendário. `getCurrentBookingQuery`\n // injeta os chips de status da agenda, e `waiting` não está entre eles — então\n // a cliente que acabou de fazer check-in sumia da tela feita para acompanhá-la.\n React.useEffect(() => {\n void fetchBookings(todayRange(), [...CHECKIN_STATUSES])\n }, [fetchBookings])\n\n // Os estados que a recepção QUER ver, e não os que o código escolheu por ela.\n // O V1 deixa isso em caixas de seleção porque o dia muda: de manhã interessa\n // quem ainda vem, no fim da tarde interessa quem faltou.\n const [shownStatuses, setShownStatuses] = React.useState<string[]>([])\n const [shownPros, setShownPros] = React.useState<string[]>([])\n\n // Os profissionais de HOJE, tirados da própria fila — a lista completa da casa\n // teria gente que não trabalha hoje, e a recepção filtraria por um nome que\n // nunca vai aparecer.\n const prosToday = React.useMemo(() => {\n const seen = new Map<string, string>()\n for (const b of bookings) if (b.professionalName) seen.set(b.professionalName, b.professionalName)\n return [...seen.keys()].sort()\n }, [bookings])\n\n const cards = React.useMemo(() => {\n const q = term.trim().toLowerCase()\n return bookings\n // Nenhum marcado = todos, como na agenda.\n .filter((b) => !shownStatuses.length || shownStatuses.includes(b.status))\n // Nenhum marcado = todos aparecem, como no V1: um filtro vazio é \"não\n // filtrei\", não \"não quero ninguém\".\n .filter((b) => !shownPros.length || (b.professionalName && shownPros.includes(b.professionalName)))\n .filter((b) => !q || (b.clientName ?? '').toLowerCase().includes(q)\n || (b.professionalName ?? '').toLowerCase().includes(q))\n // Pela hora, que é a ordem em que as pessoas chegam.\n .sort((a, b) => a.startsAt.localeCompare(b.startsAt))\n }, [bookings, term, shownStatuses, shownPros])\n\n const waiting = cards.filter((b) => b.status === 'waiting').length\n\n /**\n * O que o cadastro do cliente ainda deve.\n *\n * O V1 pergunta ao catálogo de formulários quais são exigidos no atendimento\n * (`require_on_attendance`), quais avisam quando faltam e por quantos dias a\n * resposta vale — anamnese VENCE. O V2 ainda não tem esse catálogo, então\n * aqui só entra o que a própria reserva sabe dizer. O bloco existe e cresce\n * quando o catálogo chegar; o que ele não faz é inventar um \"tudo certo\".\n */\n function requirementsFor(b: CalendarBooking): CheckinRequirement[] {\n const out: CheckinRequirement[] = []\n if (!b.clientName) out.push({ label: 'Cliente', detail: 'o agendamento não nomeia ninguém', blocking: true })\n if (!b.professionalName) out.push({ label: 'Profissional', detail: 'ninguém para executar' })\n if (!b.services?.length) out.push({ label: 'Serviço', detail: 'nada a executar nem a cobrar' })\n return out\n }\n\n const money = (n: number) => n.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })\n\n /** As baixas já registradas, do mesmo elo que enriquece a fila. */\n async function loadPaymentLines(orderId: string): Promise<PaymentDetailLine[]> {\n const detail = await config.financialBridge?.getPaymentDetail(orderId)\n return (detail?.movements ?? [])\n .filter((m) => m.paymentDate)\n .map((m) => ({\n label: [m.paymentMethodTypeName, m.cardBrand, m.cardInstallments && m.cardInstallments > 1 ? `${m.cardInstallments}x` : null]\n .filter(Boolean).join(' · ') || 'Pagamento',\n date: m.paymentDate ?? null,\n amount: m.paidAmount,\n }))\n }\n\n async function confirmCheckin(b: CalendarBooking) {\n setBusyId(b.id)\n try {\n await updateBookingStatus(b.id, 'waiting')\n await fetchBookings(todayRange(), [...CHECKIN_STATUSES])\n setReviewing(null)\n } finally { setBusyId(null) }\n }\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader\n title=\"Check-in\"\n subtitle={`Quem chega hoje${waiting ? ` · ${waiting} aguardando` : ''}`}\n />\n\n {/* Duas colunas, como no V1: os filtros ficam PARADOS à esquerda e a fila\n rola ao lado. Numa barra sobre a lista, cada toque num filtro empurra a\n fila para baixo e a recepção perde a linha que estava lendo.\n O DESENHO É O DA AGENDA — mesmas caixas, mesmas iniciais, mesmo ponto\n de cor no status. Duas telas vizinhas com dois vocabulários de filtro\n fazem a pessoa reaprender a mesma coisa ao trocar de aba. */}\n <div className=\"grid gap-4 lg:grid-cols-[248px_1fr]\">\n <aside className=\"space-y-6 lg:sticky lg:top-4 lg:self-start\">\n {/* A busca é um filtro como os outros: mora na mesma coluna. */}\n <div className=\"relative\">\n <Search className=\"absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" aria-hidden />\n <input\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n placeholder=\"Buscar cliente ou profissional\"\n className=\"w-full rounded-input border border-input bg-card py-2 pl-8 pr-3 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n\n <div>\n <FilterSection title=\"Agendas\">\n {/* A lista de profissionais também vem da busca: sem esqueleto, a\n coluna nasce vazia e cresce, empurrando o Status para baixo\n depois que a pessoa já mirou nele. */}\n {loading && prosToday.length === 0 && [0, 1, 2].map((i) => (\n <div key={i} className=\"flex items-center gap-2.5 px-1 py-1\">\n <div className=\"h-4 w-4 animate-pulse rounded-sm bg-muted\" />\n <div className=\"h-3.5 w-24 animate-pulse rounded bg-muted/70\" />\n </div>\n ))}\n <ProfessionalFilterList\n names={prosToday.map((name) => ({ id: name, label: name }))}\n selected={shownPros}\n onToggle={(name) => setShownPros((cur) =>\n cur.includes(name) ? cur.filter((x) => x !== name) : [...cur, name])}\n />\n </FilterSection>\n </div>\n\n <div>\n <FilterSection title=\"Status\">\n <StatusFilterList\n statuses={checkinStatuses}\n selected={shownStatuses}\n onToggle={(value) => setShownStatuses((cur) =>\n cur.includes(value) ? cur.filter((x) => x !== value) : [...cur, value])}\n />\n </FilterSection>\n </div>\n\n <p className=\"px-2 text-xs tabular-nums text-muted-foreground\">\n {cards.length} de {bookings.length}\n </p>\n </aside>\n\n <div className=\"min-w-0 space-y-2\">\n\n {loading && cards.length === 0 ? (\n /* Esqueleto com a FORMA da linha: a fila não salta quando os dados\n chegam, e a recepção já sabe onde olhar antes de haver o que ler. */\n <ul className=\"space-y-2\" aria-busy=\"true\" aria-label=\"Carregando a fila de hoje\">\n {[0, 1, 2, 3].map((i) => (\n <li key={i} className=\"flex items-center gap-3 rounded-2xl border border-border bg-card px-4 py-3\">\n <div className=\"h-4 w-12 animate-pulse rounded bg-muted\" />\n <div className=\"min-w-0 flex-1 space-y-1.5\">\n <div className=\"h-3.5 w-40 animate-pulse rounded bg-muted\" />\n <div className=\"h-3 w-24 animate-pulse rounded bg-muted/70\" />\n </div>\n <div className=\"h-4 w-16 animate-pulse rounded bg-muted\" />\n <div className=\"h-6 w-20 animate-pulse rounded-full bg-muted\" />\n <div className=\"h-7 w-24 animate-pulse rounded-button bg-muted\" />\n </li>\n ))}\n </ul>\n ) : cards.length === 0 ? (\n <div className=\"rounded-2xl border-2 border-dashed border-muted px-6 py-12 text-center\">\n <div className=\"mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-muted text-muted-foreground\">\n <LogIn className=\"h-6 w-6\" />\n </div>\n <p className=\"text-sm font-medium\">Ninguém na fila</p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {term ? 'Nenhum atendimento de hoje casa com a busca.' : 'Não há atendimentos para hoje.'}\n </p>\n </div>\n ) : (\n <ul className=\"space-y-2\">\n {cards.map((b) => {\n const payment = b.paymentStatus ? PAYMENT_TEXT[b.paymentStatus] : undefined\n // Já chegou: `waiting` e `in_progress` não voltam para a fila.\n const arrived = b.status === 'waiting' || b.status === 'in_progress'\n return (\n <li\n key={b.id}\n className=\"flex flex-wrap items-center gap-3 rounded-2xl border border-border bg-card px-4 py-3\"\n >\n {/* Hora e status EMPILHADOS, como no V1: a recepção lê a coluna\n da esquerda de cima a baixo para saber a ordem do dia, e o\n status pertence à mesma linha de leitura que a hora. */}\n <div className=\"flex w-16 shrink-0 flex-col items-start gap-1\">\n <span className=\"text-sm font-semibold tabular-nums\">{hourOf(b.startsAt)}</span>\n <span className={`rounded-full px-1.5 py-0.5 text-[10px] font-medium ${STATUS_TONE[b.status] ?? ''}`}>\n {statusLabel(b.status)}\n </span>\n </div>\n\n <div className=\"min-w-0 flex-1\">\n {/* O nome abre a ficha ao passar o mouse: a recepção confere\n telefone e alerta sem sair da fila. */}\n <p className=\"truncate text-sm font-medium\">\n {b.clientId\n ? <PersonLink personId={b.clientId} name={b.clientName ?? 'Sem cliente'} kind=\"customer\" />\n : (b.clientName ?? 'Sem cliente')}\n </p>\n <p className=\"flex items-center gap-1 truncate text-xs text-muted-foreground\">\n <User className=\"h-3 w-3\" aria-hidden />\n {b.professionalName ?? 'Sem profissional'}\n {arrived && b.checkedInAt && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-warning\">\n <Clock className=\"h-3 w-3\" aria-hidden />{waitedFor(b.checkedInAt)}\n </span>\n )}\n </p>\n </div>\n\n {/* Quanto é. A recepção cobra na saída e precisa do valor na\n linha; procurá-lo abrindo o agendamento é um clique por\n cliente numa tela feita para não ter nenhum. */}\n {/* Valor e estado num selo só — o MESMO que o popover do\n agendamento usa —, e ele abre com a forma, a data e o que\n falta. Sem fatura levantada mostra só o número: um silêncio é\n mais honesto que \"em aberto\". */}\n {b.orderTotal != null && b.orderTotal > 0 && (\n <PaymentStatusBadge\n status={b.paymentStatus ?? 'none'}\n totalAmount={b.orderTotal}\n formatCurrency={money}\n compact\n onLoadDetails={b.orderId ? () => loadPaymentLines(b.orderId!) : undefined}\n onReceive={canReceive ? () => setCharging(b) : undefined}\n // Pago também abre — a conta do cliente é onde se confere o\n // que foi pago, e não só onde se cobra.\n onOpenDetails={() => setCharging(b)}\n />\n )}\n\n <div className=\"flex items-center gap-2\">\n {/* O \"Receber\" saiu da LINHA e foi para dentro da conferência.\n Cobrar é uma das coisas que se resolve com a pessoa na\n frente — junto com cadastro e formulário —, e não uma ação\n solta ao lado de um botão que faz outra coisa. */}\n {(\n <button\n type=\"button\"\n onClick={() => (onOpenBooking ? onOpenBooking(b) : setEditing(b))}\n title=\"Abrir agendamento\"\n aria-label=\"Abrir agendamento\"\n className=\"inline-flex items-center justify-center rounded-button border border-input p-1.5 hover:bg-muted\"\n >\n <CalendarDays className=\"h-3.5 w-3.5\" aria-hidden />\n </button>\n )}\n <button\n type=\"button\"\n disabled={arrived || busyId === b.id}\n onClick={() => setReviewing(b)}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-foreground px-3 py-1.5 text-xs font-semibold text-background disabled:opacity-40\"\n >\n {arrived ? <CheckCircle2 className=\"h-3.5 w-3.5\" aria-hidden /> : <LogIn className=\"h-3.5 w-3.5\" aria-hidden />}\n {arrived ? 'Chegou' : 'Check-in'}\n </button>\n </div>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n </div>\n\n {reviewing && (\n <CheckinDialog\n booking={reviewing}\n statusLabel={statusLabel(reviewing.status)}\n requirements={requirementsFor(reviewing)}\n onReceive={canReceive ? (b) => { setReviewing(null); setCharging(b) } : undefined}\n onConfirm={confirmCheckin}\n onClose={() => setReviewing(null)}\n />\n )}\n\n {editing && (\n <AppointmentModal\n open\n mode=\"edit\"\n bookingId={editing.id}\n onClose={() => {\n setEditing(null)\n void fetchBookings(todayRange(), [...CHECKIN_STATUSES])\n }}\n />\n )}\n\n {charging?.clientId && (\n <ClientAccountModal\n personId={charging.clientId}\n orderId={charging.orderId}\n clientName={charging.clientName}\n onGenerate={async () => {\n // O host sabe COMO levantar a cobrança (a ponte pedido→fatura é\n // dele); o plugin só sabe quando pedir.\n if (onReceive) await onReceive(charging)\n await fetchBookings(todayRange(), [...CHECKIN_STATUSES])\n }}\n onClose={() => {\n setCharging(null)\n // Pagar acontece DENTRO deste painel, e a linha da fila mostra o\n // estado do pagamento: sem recarregar, a cliente que acabou de\n // pagar continua \"em aberto\" na tela de quem a atendeu.\n void fetchBookings(todayRange(), [...CHECKIN_STATUSES])\n }}\n />\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { usePluginRuntimeOptional } from '@fayz-ai/core'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { AgendaContextProvider } from '../context'\nimport type { ResolvedAgendaConfig } from '../config'\nimport type { AgendaDataProvider } from '../data/types'\nimport type { AgendaUIState } from '../store'\nimport { CheckinView, type CheckinViewProps } from './CheckinView'\nimport { setAgendaTenantId } from '../lib/tenant'\n\n// The same shell AgendaPage puts around the calendar: config, provider and\n// store come from the factory, not from a second wiring that could drift.\nexport function CheckinPage({ config, provider, store, onReceive, onOpenBooking }: {\n config: ResolvedAgendaConfig\n provider: AgendaDataProvider\n store: StoreApi<AgendaUIState>\n} & CheckinViewProps) {\n const runtime = usePluginRuntimeOptional()\n const tenantId = runtime?.context.tenant?.id\n\n React.useEffect(() => {\n setAgendaTenantId(tenantId)\n return () => setAgendaTenantId(undefined)\n }, [tenantId])\n\n return (\n <AgendaContextProvider config={config} provider={provider} store={store}>\n <CheckinView onReceive={onReceive} onOpenBooking={onOpenBooking} />\n </AgendaContextProvider>\n )\n}\n","import type { AgendaDataProvider } from './types'\nimport type {\n CalendarBooking, Professional, Schedule, TimeSlot,\n CreateBookingInput, UpdateBookingInput, SaveScheduleInput,\n BookingQuery, ConflictCheckParams, AvailableSlotsParams, BookingStatus,\n ProfessionalQuery,\n} from '../types'\nimport { getSupabaseClientOptional, getActiveTenantId, getActiveUnitId } from '@fayz-ai/core'\nimport { getAgendaTenantId } from '../lib/tenant'\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * A leitura da agenda sobre pessoas (020). Não é `people`: é `people` mais\n * `unit_ids`, o array de onde cada uma efetivamente atende. Escrita continua\n * indo para a tabela.\n */\nconst PEOPLE_UNITS_VIEW = 'v_bookable_people'\n\nfunction getTenantId(): string | undefined {\n // Plugin-local override wins; else fall back to the app's active tenant so\n // writes stamp the right tenant_id and pass orders/bookings RLS.\n return getAgendaTenantId() ?? getActiveTenantId()\n}\n\nfunction snakeToCamel(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n result[key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] = value\n }\n return result\n}\n\nfunction getClients() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n // Core v1 lives in PUBLIC — a single client serves both core and view reads.\n return { core: supabase, pub: supabase }\n}\n\nfunction mapBooking(row: Record<string, unknown>): CalendarBooking {\n return snakeToCamel(row) as unknown as CalendarBooking\n}\n\nfunction mapSchedule(row: Record<string, unknown>): Schedule {\n return snakeToCamel(row) as unknown as Schedule\n}\n\nfunction addMinutes(iso: string, minutes: number): string {\n const d = new Date(iso)\n d.setMinutes(d.getMinutes() + minutes)\n return d.toISOString()\n}\n\nfunction unique(values: Array<string | null | undefined>): string[] {\n return Array.from(new Set(values.filter((value): value is string => !!value)))\n}\n\nfunction indexById(rows: any[] | null | undefined): Map<string, any> {\n return new Map((rows ?? []).filter((row) => row?.id).map((row) => [row.id, row]))\n}\n\nfunction groupBy<T>(rows: T[], getKey: (row: T) => string | null | undefined): Map<string, T[]> {\n const grouped = new Map<string, T[]>()\n for (const row of rows) {\n const key = getKey(row)\n if (!key) continue\n grouped.set(key, [...(grouped.get(key) ?? []), row])\n }\n return grouped\n}\n\nfunction getDurationMinutes(startsAt: string, endsAt: string | null | undefined): number | null {\n if (!endsAt) return null\n return Math.round((new Date(endsAt).getTime() - new Date(startsAt).getTime()) / 60000)\n}\n\nfunction mergeBookings(viewBookings: CalendarBooking[], canonicalBookings: CalendarBooking[]): CalendarBooking[] {\n const canonicalIds = new Set(canonicalBookings.map((booking) => booking.id))\n const canonicalOrderIds = new Set(canonicalBookings.map((booking) => booking.orderId).filter(Boolean))\n const merged = [\n ...canonicalBookings,\n ...viewBookings.filter((booking) => {\n if (canonicalIds.has(booking.id)) return false\n if (booking.orderId && canonicalOrderIds.has(booking.orderId)) return false\n if (canonicalOrderIds.has(booking.id)) return false\n return true\n }),\n ]\n\n return merged.sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n}\n\nasync function hydrateCanonicalBookings(core: any, bookings: any[]): Promise<CalendarBooking[]> {\n const personIds = unique(bookings.flatMap((booking) => [booking.party_id, booking.assignee_id]))\n const locationIds = unique(bookings.map((booking) => booking.location_id))\n const orderIds = unique(bookings.map((booking) => booking.order_id))\n const bookingIds = unique(bookings.map((booking) => booking.id))\n\n const [\n { data: persons, error: personsError },\n { data: locations, error: locationsError },\n { data: orders, error: ordersError },\n { data: items, error: itemsError },\n ] = await Promise.all([\n personIds.length\n ? core.from('people').select('id, name, phone, email, avatar_url').in('id', personIds)\n : Promise.resolve({ data: [], error: null }),\n locationIds.length\n ? core.from('v_units').select('id, name').in('id', locationIds)\n : Promise.resolve({ data: [], error: null }),\n // The core's read model, not the table: public.orders belongs to the core,\n // and v_orders is what it publishes (spine 184). It also carries the DERIVED\n // fulfilment state, which the table never had.\n orderIds.length\n ? core.from('v_orders').select('id, total, status, fulfillment_status').in('id', orderIds)\n : Promise.resolve({ data: [], error: null }),\n orderIds.length\n ? core.from('items').select('id, order_id, product_id, name, duration_minutes, unit_price, assignee_id, sort_order').in('order_id', orderIds)\n : Promise.resolve({ data: [], error: null }),\n ])\n\n if (personsError) throw personsError\n if (locationsError) throw locationsError\n if (ordersError) throw ordersError\n if (itemsError) throw itemsError\n\n const personsById = indexById(persons)\n const locationsById = indexById(locations)\n const ordersById = indexById(orders)\n // S4: line items come from public.items (the one line table, spine 187), keyed by order_id.\n const itemsByOrderId = groupBy(items ?? [], (item: any) => item.order_id)\n\n return bookings.map((booking) => {\n const client = booking.party_id ? personsById.get(booking.party_id) : null\n const professional = booking.assignee_id ? personsById.get(booking.assignee_id) : null\n const location = booking.location_id ? locationsById.get(booking.location_id) : null\n const order = booking.order_id ? ordersById.get(booking.order_id) : null\n const bookingItems = ((booking.order_id ? itemsByOrderId.get(booking.order_id) : null) ?? [])\n .sort((a: any, b: any) => (a.sort_order ?? 0) - (b.sort_order ?? 0))\n .map((item: any) => ({\n id: item.id,\n serviceId: item.product_id,\n name: item.name,\n durationMinutes: item.duration_minutes,\n price: item.unit_price,\n assigneeId: item.assignee_id,\n }))\n const itemDuration = bookingItems.reduce((sum: number, item: any) => sum + (item.durationMinutes ?? 0), 0)\n\n return {\n id: booking.id,\n tenantId: booking.tenant_id,\n kind: booking.kind,\n startsAt: booking.starts_at,\n endsAt: booking.ends_at,\n status: booking.status,\n notes: booking.notes,\n orderId: booking.order_id,\n locationId: booking.location_id,\n metadata: booking.metadata ?? {},\n clientId: booking.party_id,\n // Simple events (no party) fall back to the title stored in metadata;\n // partyless blocks/tasks (e.g. imported Google events) get their notes or\n // a kind label so the calendar never renders an unnamed chip.\n clientName: client?.name\n ?? (booking.metadata?.title as string | undefined)\n ?? (booking.kind === 'appointment'\n ? null\n : booking.notes || (booking.kind === 'task' ? 'Tarefa' : 'Bloqueio')),\n clientPhone: client?.phone ?? null,\n clientEmail: client?.email ?? null,\n clientAvatarUrl: client?.avatar_url ?? null,\n professionalId: booking.assignee_id,\n professionalName: professional?.name ?? null,\n professionalAvatarUrl: professional?.avatar_url ?? null,\n locationName: location?.name ?? null,\n orderTotal: order?.total ?? null,\n orderStatus: order?.status ?? null,\n services: bookingItems.length ? bookingItems : null,\n totalDurationMinutes: itemDuration || getDurationMinutes(booking.starts_at, booking.ends_at),\n checkedInAt: booking.checked_in_at ?? null,\n createdAt: booking.created_at,\n updatedAt: booking.updated_at,\n } satisfies CalendarBooking\n })\n}\n\nasync function getCanonicalBookings(core: any, query: BookingQuery): Promise<CalendarBooking[]> {\n let q = core.from('appointments')\n .select('id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, checked_in_at, created_at, updated_at')\n .gte('starts_at', query.dateRange.start)\n .lte('starts_at', query.dateRange.end)\n\n if (query.kind) q = q.eq('kind', query.kind)\n if (query.statuses?.length) q = q.in('status', query.statuses)\n if (query.professionalIds?.length) q = q.in('assignee_id', query.professionalIds)\n if (query.locationId) q = q.eq('location_id', query.locationId)\n\n const { data, error } = await q.order('starts_at', { ascending: true })\n if (error) throw error\n return hydrateCanonicalBookings(core, data ?? [])\n}\n\nasync function getCanonicalBookingById(core: any, id: string): Promise<CalendarBooking | null> {\n const columns = 'id, tenant_id, kind, starts_at, ends_at, status, notes, order_id, location_id, metadata, party_id, assignee_id, checked_in_at, created_at, updated_at'\n let { data, error } = await core.from('appointments').select(columns).eq('id', id).maybeSingle()\n if (error) throw error\n\n if (!data) {\n const fallback = await core.from('appointments').select(columns).eq('order_id', id).maybeSingle()\n if (fallback.error) throw fallback.error\n data = fallback.data\n }\n\n if (!data) return null\n const [booking] = await hydrateCanonicalBookings(core, [data])\n return booking ?? null\n}\n\n// ---------------------------------------------------------------------------\n// Supabase Agenda Provider\n// ---------------------------------------------------------------------------\n\nexport interface SupabaseAgendaProviderOptions {\n /** people.kind used for calendar resources/professionals (default 'staff' — schools use 'teacher'). */\n professionalKind?: string\n}\n\nlet bookingChangesChannelSequence = 0\n\nexport function createSupabaseAgendaProvider(providerOptions?: SupabaseAgendaProviderOptions): AgendaDataProvider {\n const professionalKind = providerOptions?.professionalKind ?? 'staff'\n return {\n subscribeToBookingChanges(onChange) {\n const { core } = getClients()\n const tenantId = getTenantId() ?? 'active'\n const channelName = `agenda:appointments:${tenantId}:${++bookingChangesChannelSequence}`\n const channel = core\n .channel(channelName)\n .on('postgres_changes', { event: '*', schema: 'public', table: 'appointments' }, onChange)\n .subscribe()\n\n // No tenant_id filter on purpose: RLS already scopes Postgres Changes to\n // the caller's tenants, and Supabase cannot filter DELETE events. The\n // callback only refetches — it never trusts the payload.\n return () => { void core.removeChannel(channel) }\n },\n\n // v_appointments is in public schema (PostgREST default)\n async getBookings(query: BookingQuery): Promise<CalendarBooking[]> {\n const { core, pub } = getClients()\n let q = pub.from('v_appointments').select('*')\n .gte('starts_at', query.dateRange.start)\n .lte('starts_at', query.dateRange.end)\n\n if (query.kind) q = q.eq('kind', query.kind)\n if (query.statuses?.length) q = q.in('status', query.statuses)\n if (query.professionalIds?.length) q = q.in('professional_id', query.professionalIds)\n if (query.locationId) q = q.eq('location_id', query.locationId)\n\n q = q.order('starts_at', { ascending: true })\n\n const { data, error } = await q\n if (error) throw error\n const viewBookings = (data ?? []).map(mapBooking)\n const canonicalBookings = await getCanonicalBookings(core, query)\n return mergeBookings(viewBookings, canonicalBookings)\n },\n\n async getBookingById(id: string): Promise<CalendarBooking | null> {\n const { core, pub } = getClients()\n const { data, error } = await pub.from('v_appointments').select('*').eq('id', id).maybeSingle()\n if (error) throw error\n if (data) {\n const booking = mapBooking(data as Record<string, unknown>)\n // v_appointments is a FLAT read model — it exposes no line items. The\n // calendar list path merges in the canonical hydration (which carries\n // `services` from items), but this single-record lookup used by the\n // edit modal previously returned the bare view row. That dropped\n // `services`, so a booking whose type has `requiresServices` reopened with\n // an empty service list and kept the \"Update\" button permanently disabled\n // (canSubmit stayed false). Hydrate the line items here to stay consistent\n // with getBookings.\n if (booking.orderId) {\n const { data: items } = await core.from('items')\n .select('id, service_id, name, duration_minutes, unit_price, assignee_id, sort_order')\n .eq('order_id', booking.orderId)\n .order('sort_order', { ascending: true })\n if (items && items.length) {\n const services = items.map((item: any) => ({\n id: item.id,\n serviceId: item.product_id,\n name: item.name,\n durationMinutes: item.duration_minutes,\n price: item.unit_price,\n assigneeId: item.assignee_id,\n }))\n booking.services = services\n const itemDuration = services.reduce((sum: number, s: any) => sum + (s.durationMinutes ?? 0), 0)\n if (itemDuration) booking.totalDurationMinutes = itemDuration\n }\n }\n return booking\n }\n return getCanonicalBookingById(core, id)\n },\n\n async createBooking(input: CreateBookingInput): Promise<CalendarBooking> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('No active tenant')\n\n const hasServices = input.services.length > 0\n const totalDuration = input.services.reduce((sum, s) => sum + s.durationMinutes, 0)\n const totalPrice = input.services.reduce((sum, s) => sum + s.price, 0)\n const endsAt = addMinutes(input.startsAt, totalDuration || 30)\n const serviceNames = input.services.map((s: any) => s.name).join(', ')\n\n // Resolve client name for metadata (used by financial detail view)\n let contactName: string | undefined\n if (input.clientId) {\n const { data: person } = await core.from('people').select('name').eq('id', input.clientId).single()\n contactName = person?.name as string | undefined\n }\n\n // Simple / Google-Calendar-style events have no client party — persist the\n // free-text title in metadata so the read model can surface it as the name.\n const eventTitle = input.title?.trim() || undefined\n\n // ONE call, ONE transaction (PRD 06). This used to be three writes from\n // the browser — order, appointment, lines — and every gap between them was\n // a way to end up with half a booking that nothing reconciled afterwards.\n // public.orders belongs to the core, so the agenda asks the core's door\n // (agenda_booking_create → order_create) instead of writing the table.\n const metadata = {\n source: 'agenda',\n ...(serviceNames ? { serviceNames, itemsSummary: serviceNames } : {}),\n ...(contactName ? { contactName } : {}),\n ...(eventTitle ? { title: eventTitle } : {}),\n }\n\n const { data: created, error: rpcErr } = await core.rpc('agenda_booking_create', {\n p_starts_at: input.startsAt,\n p_ends_at: endsAt,\n p_lines: hasServices\n ? input.services.map((s, i) => ({\n service_id: s.serviceId,\n name: s.name,\n quantity: 1,\n unit_price: s.price,\n sort_order: i,\n duration_minutes: s.durationMinutes,\n assignee_id: s.assigneeId || input.professionalId || null,\n }))\n : [],\n p_party_id: input.clientId || null,\n p_assignee_id: input.professionalId || null,\n p_location_id: input.locationId ?? null,\n p_kind: input.kind ?? 'appointment',\n p_notes: input.notes ?? null,\n p_metadata: metadata,\n })\n if (rpcErr) throw rpcErr\n const booking = { id: (created as { appointment_id: string }).appointment_id }\n\n const createdBooking = await this.getBookingById(booking.id)\n if (!createdBooking) throw new Error('Created booking did not resolve from agenda read model')\n return createdBooking\n },\n\n async updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking> {\n const { core } = getClients()\n const { data: existing, error: existingErr } = await core.from('appointments')\n .select('id, order_id, starts_at, assignee_id, metadata')\n .eq('id', id)\n .single()\n if (existingErr) throw existingErr\n\n const updates: Record<string, unknown> = {}\n if (data.startsAt) updates.starts_at = data.startsAt\n if (data.endsAt) updates.ends_at = data.endsAt\n // Simple-event title lives in metadata (no client party) — merge, don't clobber.\n if (data.title !== undefined) {\n updates.metadata = { ...(existing?.metadata as Record<string, unknown> ?? {}), title: data.title }\n }\n if (data.status) {\n // Only update the agenda status — never touch the financial stage\n updates.status = data.status\n }\n if (data.notes !== undefined) updates.notes = data.notes\n if (data.professionalId) updates.assignee_id = data.professionalId\n if (data.clientId) updates.party_id = data.clientId\n if (data.locationId) updates.location_id = data.locationId\n\n // Recalculate totals when services are updated\n if (data.services) {\n const totalDuration = data.services.reduce((s, svc) => s + svc.durationMinutes, 0)\n const totalPrice = data.services.reduce((s, svc) => s + svc.price, 0)\n // Recalculate ends_at from startsAt + total duration\n const startsAt = data.startsAt ?? (existing?.starts_at as string | undefined)\n if (startsAt) {\n const ends = new Date(new Date(startsAt).getTime() + totalDuration * 60000)\n updates.ends_at = ends.toISOString()\n }\n }\n\n const effectiveAssigneeId = data.professionalId ?? (existing?.assignee_id as string | null | undefined) ?? null\n\n const { error } = await core.from('appointments').update(updates).eq('id', id)\n if (error) throw error\n\n // S4: services are updated only in items below (booking_items deprecated).\n const orderId = existing?.order_id as string | null | undefined\n if (orderId) {\n const orderUpdates: Record<string, unknown> = {}\n if (data.notes !== undefined) orderUpdates.notes = data.notes\n if (data.professionalId) orderUpdates.assignee_id = data.professionalId\n if (data.clientId) orderUpdates.party_id = data.clientId\n if (data.locationId) orderUpdates.location_id = data.locationId\n\n if (data.services) {\n const totalPrice = data.services.reduce((s, svc) => s + svc.price, 0)\n orderUpdates.subtotal = totalPrice\n orderUpdates.total = totalPrice\n }\n\n if (Object.keys(orderUpdates).length > 0) {\n const { error: orderErr } = await core.from('orders').update(orderUpdates).eq('id', orderId)\n if (orderErr) throw orderErr\n }\n\n if (data.services) {\n await core.from('items').delete().eq('order_id', orderId)\n if (data.services.length > 0) {\n const items = data.services.map((svc, idx) => ({\n order_id: orderId,\n service_id: svc.serviceId || null,\n name: svc.name,\n quantity: 1,\n unit_price: svc.price,\n total: svc.price,\n sort_order: idx,\n duration_minutes: svc.durationMinutes,\n assignee_id: svc.assigneeId ?? effectiveAssigneeId,\n }))\n const { error: itemErr } = await core.from('items').insert(items)\n if (itemErr) throw itemErr\n }\n }\n }\n\n return (await this.getBookingById(id))!\n },\n\n async deleteBooking(id: string): Promise<void> {\n const { core, pub } = getClients()\n const { data: booking, error: bookingErr } = await core.from('appointments')\n .select('order_id')\n .eq('id', id)\n .single()\n if (bookingErr) throw bookingErr\n\n const orderId = booking?.order_id as string | null | undefined\n // Financial movements live in the financial plugin's tables. Pools that\n // don't provision that plugin (e.g. school/event agendas) have no\n // plg_financial_movements table, and the probe below returns a PostgREST\n // \"relation does not exist\" error. Previously that error was rethrown,\n // which aborted the ENTIRE delete — the modal caught it and left the\n // booking in place, so \"Delete\" looked like a silent no-op (works in\n // beauty, which has the table; fails in school, which doesn't). Treat any\n // probe failure as \"no linked movements\" and fall through to a plain delete.\n let movementCount = 0\n if (orderId) {\n const { count, error: movementErr } = await pub\n .from('plg_financial_movements')\n .select('id', { count: 'exact', head: true })\n .eq('invoice_id', orderId)\n if (!movementErr) movementCount = count ?? 0\n }\n\n if (orderId && movementCount > 0) {\n // Cancel movements + order (don't delete financial records)\n await pub.from('plg_financial_movements').update({ status: 'cancelled' }).eq('invoice_id', orderId)\n await core.from('orders').update({ status: 'cancelled' }).eq('id', orderId)\n const { error } = await core.from('appointments').update({ status: 'cancelled' }).eq('id', id)\n if (error) throw error\n } else {\n // Safe to delete — remove any movements first (FK constraint)\n if (orderId) {\n await pub.from('plg_financial_movements').delete().eq('invoice_id', orderId)\n }\n const { error } = await core.from('appointments').delete().eq('id', id)\n if (error) throw error\n if (orderId) {\n const { error: orderErr } = await core.from('orders').delete().eq('id', orderId)\n if (orderErr) throw orderErr\n }\n }\n },\n\n async updateBookingStatus(id: string, status: string): Promise<CalendarBooking> {\n return this.updateBooking(id, { status: status as BookingStatus })\n },\n\n async checkConflict(params: ConflictCheckParams): Promise<boolean> {\n const { core } = getClients()\n let q = core.from('appointments').select('id', { count: 'exact', head: true })\n .eq('assignee_id', params.assigneeId)\n .eq('kind', 'appointment')\n .not('status', 'in', '(\"cancelled\",\"no_show\")')\n .not('starts_at', 'is', null)\n .lt('starts_at', params.endsAt)\n .gt('ends_at', params.startsAt)\n\n if (params.excludeBookingId) {\n q = q.neq('id', params.excludeBookingId)\n }\n\n const { count, error } = await q\n if (error) throw error\n return (count ?? 0) > 0\n },\n\n async getAvailableSlots(params: AvailableSlotsParams): Promise<TimeSlot[]> {\n const { pub } = getClients()\n const { data, error } = await pub.rpc('get_available_slots', {\n p_tenant_id: getTenantId(),\n p_assignee_id: params.assigneeId,\n p_date: params.date,\n p_duration_minutes: params.durationMinutes,\n p_slot_interval: params.slotInterval ?? 30,\n })\n if (error) throw error\n return (data ?? []).map((row: any) => ({ start: row.slot_start, end: row.slot_end }))\n },\n\n async getSchedules(professionalId?: string): Promise<Schedule[]> {\n const { core } = getClients()\n let q = core.from('schedules').select('*').eq('kind', 'working_hours')\n if (professionalId) q = q.eq('assignee_id', professionalId)\n q = q.order('day_of_week').order('starts_at')\n\n const { data, error } = await q\n if (error) throw error\n return (data ?? []).map(mapSchedule)\n },\n\n async saveSchedule(input: SaveScheduleInput): Promise<Schedule> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('No active tenant')\n\n const { data, error } = await core.from('schedules').insert({\n tenant_id: tenantId,\n kind: 'working_hours',\n assignee_id: input.assigneeId,\n location_id: input.locationId ?? null,\n day_of_week: input.dayOfWeek ?? null,\n specific_date: input.specificDate ?? null,\n starts_at: input.startsAt,\n ends_at: input.endsAt,\n is_active: input.isActive !== false,\n metadata: input.metadata ?? {},\n }).select('*').single()\n if (error) throw error\n return mapSchedule(data as Record<string, unknown>)\n },\n\n async deleteSchedule(id: string): Promise<void> {\n const { core } = getClients()\n const { error } = await core.from('schedules').delete().eq('id', id)\n if (error) throw error\n },\n\n async getProfessionals(query?: ProfessionalQuery): Promise<Professional[]> {\n const { core } = getClients()\n // ONDE a pessoa atende não cabe numa coluna. `people.unit_id` guarda uma\n // unidade; quem atende em várias se descreve por tuplas `available_in`, e\n // filtrar só pela coluna deixava 128 profissionais aparecerem em TODA\n // unidade da rede. `v_bookable_people` (020) junta as duas formas num\n // `unit_ids uuid[]`, e o filtro vira contenção de array — sem enumerar\n // unidade nenhuma no navegador.\n //\n // `unit_ids IS NULL` volta junto, e isso NÃO é descuido.\n //\n // Tentei o contrário primeiro — esconder quem não tem unidade — e isso\n // esvaziou a agenda de todo tenant que ligou unidades mas ainda não\n // lotou ninguém: no Espaço Renova Rio, standing em Ideale 633, as duas\n // profissionais marcadas como \"aparece na agenda\" sumiram, porque\n // NENHUMA das seis tem unidade.\n //\n // Sem unidade é \"da rede inteira\", que é a semântica que `people` já\n // declara em `public.scoped_resources` (shareable) e que o resto do SDK\n // obedece. Quem quer tirar alguém da agenda tem a chave certa para isso,\n // que é `is_bookable` — uma decisão explícita, na ficha, e não um efeito\n // colateral de um cadastro incompleto.\n const unitId = query?.unitId ?? getActiveUnitId()\n const base = () => {\n let qb = core.from(PEOPLE_UNITS_VIEW)\n .select('id, name, avatar_url, is_active, unit_ids')\n .eq('kind', professionalKind)\n .eq('is_active', true)\n // \"desta unidade OU da rede\". Um `or=` do PostgREST, que compõe com o\n // `ilike` da busca abaixo em vez de brigar com ele.\n if (unitId) qb = qb.or(`unit_ids.is.null,unit_ids.cs.{${unitId}}`)\n // A busca é do SELETOR de agendas: com centenas de nomes, rolar não é\n // uma forma de achar ninguém.\n if (query?.search) qb = qb.ilike('name', `%${query.search}%`)\n // Um teto explícito. Sem ele o PostgREST devolve o que houver, e o que\n // houver vira coluna na grade — o custo não é a consulta, é o desenho.\n if (query?.limit) qb = qb.limit(query.limit)\n return qb\n }\n\n // Trabalhar aqui não é atender cliente. Desde que todo login ganha ficha,\n // o contador e o administrador entram em `people` com o mesmo kind de\n // quem atende — e sem este filtro viram coluna na grade semanal, com\n // horário livre para alguém marcar em cima.\n let { data, error } = await base().eq('is_bookable', true).order('name')\n\n // Pool que ainda não recebeu a coluna responde 42703; pool sem a 020 não\n // tem a view e responde 42P01. Nos dois casos voltar para `people` é a\n // resposta certa: lá o problema não existe, e derrubar a agenda inteira\n // por causa de um objeto que falta seria trocar um incômodo por uma tela\n // quebrada.\n if (error && ((error as any).code === '42703' || (error as any).code === '42P01')) {\n let qb = core.from('people')\n .select('id, name, avatar_url, is_active')\n .eq('kind', professionalKind)\n .eq('is_active', true)\n if (query?.search) qb = qb.ilike('name', `%${query.search}%`)\n if (query?.limit) qb = qb.limit(query.limit)\n ;({ data, error } = await qb.order('name'))\n }\n if (error) throw error\n return (data ?? []).map((p: any) => ({\n id: p.id, name: p.name, avatarUrl: p.avatar_url,\n locationId: null, locationName: null, isActive: p.is_active,\n }))\n },\n\n async getLocations(): Promise<Array<{ id: string; name: string }>> {\n const { core } = getClients()\n // ONDE o atendimento acontece, e a resposta é a unidade em que a tela\n // está. Sem este recorte o \"Selecionar local…\" de um agendamento novo\n // abre com as 65 unidades da rede — e marcar em Treinamento um horário\n // que a pessoa acha que está marcando na Tijuca é o erro mais caro que\n // este campo consegue produzir.\n //\n // Uma REGIÃO não entra: ela agrupa, não é lugar onde alguém é atendido.\n // Sem unidade escolhida (\"todas as unidades\") a lista volta inteira, que\n // é a resposta certa para quem está olhando a rede.\n const unitId = getActiveUnitId()\n let qb = core.from('v_units').select('id, name, kind').eq('is_active', true)\n if (unitId) qb = qb.eq('id', unitId)\n const { data, error } = await qb.order('name')\n if (error) throw error\n return (data ?? [])\n .filter((l: any) => l.kind !== 'region')\n .map((l: any) => ({ id: l.id, name: l.name }))\n },\n\n async getConfirmationsPending(daysAhead = 2): Promise<CalendarBooking[]> {\n const { pub } = getClients()\n const now = new Date().toISOString()\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() + daysAhead)\n\n const { data, error } = await pub.from('v_appointments').select('*')\n .eq('status', 'scheduled')\n .gte('starts_at', now)\n .lte('starts_at', cutoff.toISOString())\n .order('starts_at')\n if (error) throw error\n return (data ?? []).map(mapBooking)\n },\n\n async sendConfirmation(bookingId: string, channel: string): Promise<void> {\n const { core } = getClients()\n const { data: booking } = await core.from('appointments').select('metadata').eq('id', bookingId).single()\n const metadata = (booking?.metadata ?? {}) as Record<string, unknown>\n const confirmations = (metadata.confirmations as any[] ?? [])\n confirmations.push({ channel, sentAt: new Date().toISOString(), status: 'sent' })\n await core.from('appointments').update({ metadata: { ...metadata, confirmations } }).eq('id', bookingId)\n },\n\n async completeBooking(bookingId: string): Promise<{ booking: CalendarBooking; orderId: string }> {\n const { core } = getClients()\n const { data: existing, error: existingErr } = await core.from('appointments')\n .select('order_id')\n .eq('id', bookingId)\n .single()\n if (existingErr) throw existingErr\n\n const { error } = await core.from('appointments')\n .update({ status: 'completed' })\n .eq('id', bookingId)\n if (error) throw error\n\n const orderId = existing?.order_id as string | null | undefined\n const booking = await this.getBookingById(bookingId)\n if (!booking) throw new Error('Booking not found')\n return { booking, orderId: orderId ?? bookingId }\n },\n }\n}\n","import { emitDomainEvent, getActiveTenantId } from '@fayz-ai/core'\nimport { getAgendaTenantId } from './tenant'\nimport type { CalendarBooking } from '../types'\n\n// Emissores dos fatos declarados em message-events.ts. `agenda.booking_reminder`\n// não tem emissor de propósito: a véspera é disparada por agendador no servidor.\n\nconst STATUS_EVENT: Record<string, string> = {\n cancelled: 'agenda.booking_cancelled',\n completed: 'agenda.booking_completed',\n no_show: 'agenda.booking_no_show',\n}\n\n/** O evento específico de uma transição de status, se ela tiver um. */\nexport function bookingStatusEventKey(status: string): string | undefined {\n return STATUS_EVENT[status]\n}\n\n// Data e hora no formato dos exemplos do catálogo: '12/08/2026', '14:30'.\nfunction bookingPayload(booking: CalendarBooking): Record<string, unknown> {\n const starts = new Date(booking.startsAt)\n return {\n customer_name: booking.clientName ?? '',\n // O destino do WhatsApp, exatamente como está na ficha do cliente — máscara,\n // DDD solto, o que houver. Normalizar é trabalho de quem envia\n // (normalizeBrPhoneToE164), e adivinhar aqui só criaria uma quinta versão da\n // mesma regra. Vazio quando a ficha não tem telefone: a automação pula, e um\n // envio pulado é melhor que um envio para o número de outra pessoa.\n customer_phone: booking.clientPhone ?? '',\n service_name: (booking.services ?? []).map((s) => s.name).join(' + '),\n professional_name: booking.professionalName ?? '',\n booking_date: starts.toLocaleDateString('pt-BR'),\n booking_time: starts.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }),\n location_name: booking.locationName ?? '',\n }\n}\n\nexport function emitBookingEvent(key: string, booking: CalendarBooking): void {\n emitDomainEvent(key, bookingPayload(booking), {\n tenantId: booking.tenantId || getAgendaTenantId() || getActiveTenantId() || null,\n subject: { type: 'booking', id: booking.id },\n })\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { emitDataChanged } from '@fayz-ai/core'\nimport { dedup } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport { getScheduleBlockConfig, setScheduleBlockConfig } from '@fayz-ai/admin'\nimport type { AgendaDataProvider } from './data/types'\nimport { bookingStatusEventKey, emitBookingEvent } from './lib/booking-events'\nimport type { AgendaFinancialBridge } from './bridges/financial-bridge'\nimport type { ExternalBookingSource } from './config'\nimport type {\n CalendarBooking, Professional, Schedule,\n CreateBookingInput, UpdateBookingInput, BookingQuery, ProfessionalQuery,\n} from './types'\n\n/**\n * Quantas agendas a tela carrega de uma vez.\n *\n * Não é uma estimativa de quantas cabem na grade (essa é bem menor, e mora na\n * CalendarView) — é o quanto vale ter em memória para o seletor filtrar sem ir\n * ao servidor a cada tecla. Acima disto a busca passa a consultar.\n */\nconst PROFESSIONAL_LIMIT = 200\n\n// ---------------------------------------------------------------------------\n// Store state\n// ---------------------------------------------------------------------------\n\nexport interface AgendaUIState {\n // Calendar data\n bookings: CalendarBooking[]\n bookingsLoading: boolean\n dateRange: { start: string; end: string }\n currentView: string\n selectedDate: string\n\n // Resources\n professionals: Professional[]\n professionalsLoading: boolean\n /** A lista voltou no teto — existe mais quadro do que o que está aqui, e a\n * busca do seletor tem que ir ao servidor em vez de filtrar o que carregou. */\n professionalsTruncated: boolean\n\n // Filters\n selectedProfessionalIds: string[]\n selectedLocationId: string | null\n selectedStatuses: string[]\n\n // Locations\n locations: Array<{ id: string; name: string }>\n\n // Schedules\n schedules: Schedule[]\n schedulesLoading: boolean\n\n // Confirmations\n pendingConfirmations: CalendarBooking[]\n confirmationsLoading: boolean\n\n // Modal state\n appointmentModal: {\n open: boolean\n mode: 'create' | 'edit'\n bookingId?: string\n prefill?: Partial<CreateBookingInput> & { endsAt?: string }\n initialTab?: string\n externalSource?: ExternalBookingSource\n }\n\n // Actions\n /** `statuses` overrides the calendar's chip selection — a screen with its own\n * notion of which bookings belong (the check-in queue) must not inherit it. */\n fetchBookings(range: { start: string; end: string }, statuses?: string[]): Promise<void>\n fetchProfessionals(query?: ProfessionalQuery): Promise<void>\n fetchLocations(): Promise<void>\n fetchSchedules(professionalId?: string): Promise<void>\n fetchConfirmations(): Promise<void>\n createBooking(input: CreateBookingInput): Promise<CalendarBooking>\n updateBooking(id: string, data: UpdateBookingInput): Promise<CalendarBooking>\n deleteBooking(id: string): Promise<void>\n updateBookingStatus(id: string, status: string): Promise<void>\n rescheduleBooking(id: string, newStart: string, newEnd: string, newProfessionalId?: string): Promise<void>\n setFilters(filters: Partial<{ professionalIds: string[]; locationId: string | null; statuses: string[] }>): void\n setView(view: string): void\n setSelectedDate(date: string): void\n openAppointmentModal(mode: 'create' | 'edit', options?: { bookingId?: string; prefill?: Partial<CreateBookingInput> & { endsAt?: string }; initialTab?: string; externalSource?: ExternalBookingSource }): void\n closeAppointmentModal(): void\n}\n\n// ---------------------------------------------------------------------------\n// Store factory\n// ---------------------------------------------------------------------------\n\nfunction getCurrentBookingQuery(state: AgendaUIState, dateRange = state.dateRange): BookingQuery {\n return {\n dateRange,\n professionalIds: state.selectedProfessionalIds.length ? state.selectedProfessionalIds : undefined,\n locationId: state.selectedLocationId ?? undefined,\n statuses: state.selectedStatuses.length ? state.selectedStatuses : undefined,\n }\n}\n\nexport function createAgendaStore(provider: AgendaDataProvider, financialBridge?: AgendaFinancialBridge): StoreApi<AgendaUIState> {\n return createStore<AgendaUIState>((set, get) => ({\n bookings: [],\n bookingsLoading: false,\n dateRange: { start: '', end: '' },\n currentView: 'resourceTimeGridDay',\n selectedDate: new Date().toISOString().slice(0, 10),\n\n professionals: [],\n professionalsLoading: false,\n professionalsTruncated: false,\n\n selectedProfessionalIds: [],\n selectedLocationId: null,\n selectedStatuses: ['scheduled', 'confirmed', 'in_progress', 'completed'],\n\n locations: [],\n\n schedules: [],\n schedulesLoading: false,\n\n pendingConfirmations: [],\n confirmationsLoading: false,\n\n appointmentModal: { open: false, mode: 'create' },\n\n async fetchBookings(range, statuses) {\n const key = `agenda:bookings:${range.start}:${range.end}:${statuses?.join(',') ?? ''}`\n return dedup(key, async () => {\n set({ bookingsLoading: true, dateRange: range })\n const state = get()\n const query = statuses?.length\n ? { ...getCurrentBookingQuery(state, range), statuses }\n : getCurrentBookingQuery(state, range)\n let bookings = await provider.getBookings(query)\n\n // Enrich with payment status if financial bridge is available\n if (financialBridge) {\n const orderIds = bookings.map((b) => b.orderId).filter((id): id is string => !!id)\n if (orderIds.length > 0) {\n try {\n const statuses = await financialBridge.resolvePaymentStatuses(orderIds)\n bookings = bookings.map((b) => {\n if (!b.orderId) return b\n const summary = statuses.get(b.orderId)\n return summary ? { ...b, paymentStatus: summary.status } : b\n })\n } catch { /* non-blocking */ }\n }\n }\n\n set({ bookings, bookingsLoading: false })\n })\n },\n\n async fetchProfessionals(query) {\n // O TETO É DE PROPÓSITO. Numa rede de franquia `people` guarda o quadro\n // inteiro — 739 agendáveis no Espaço Facial — e cada linha daqui vira uma\n // coluna na grade da semana. O que trava a tela não é a consulta, é o\n // desenho, então o corte tem que acontecer antes de a lista existir.\n //\n // `professionalsTruncated` diz ao seletor que filtrar o que está em\n // memória não responde: quem não veio também precisa ser encontrável.\n const limit = query?.limit ?? PROFESSIONAL_LIMIT\n const effective: ProfessionalQuery = { ...query, limit }\n return dedup('agenda:professionals:' + JSON.stringify(effective), async () => {\n set({ professionalsLoading: true })\n const professionals = await provider.getProfessionals(effective)\n set({\n professionals,\n professionalsTruncated: professionals.length >= limit,\n professionalsLoading: false,\n })\n })\n },\n\n async fetchLocations() {\n return dedup('agenda:locations', async () => {\n if (!provider.getLocations) return\n const locations = await provider.getLocations()\n set({ locations })\n // Update global schedule block config so ScheduleEditor picks up locations\n const current = getScheduleBlockConfig()\n if (current) {\n setScheduleBlockConfig({ ...current, locations })\n }\n })\n },\n\n async fetchSchedules(professionalId) {\n return dedup('agenda:schedules:' + (professionalId ?? 'all'), async () => {\n set({ schedulesLoading: true })\n const schedules = await provider.getSchedules(professionalId)\n set({ schedules, schedulesLoading: false })\n })\n },\n\n async fetchConfirmations() {\n return dedup('agenda:confirmations', async () => {\n set({ confirmationsLoading: true })\n const pendingConfirmations = await provider.getConfirmationsPending()\n set({ pendingConfirmations, confirmationsLoading: false })\n })\n },\n\n async createBooking(input) {\n try {\n const booking = await provider.createBooking(input)\n emitBookingEvent('agenda.booking_created', booking)\n // Refresh bookings for current range\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'create', id: booking.id, source: 'ui' })\n toast.success('Appointment created')\n return booking\n } catch (err: any) {\n toast.error('Failed to create appointment', { description: err?.message })\n throw err\n }\n },\n\n async updateBooking(id, data) {\n try {\n const prev = get().bookings.find((b) => b.id === id)\n const booking = await provider.updateBooking(id, data)\n // Um fato por salvamento: transição de status ganha o evento específico;\n // senão, mudança de horário é remarcação.\n const statusKey = prev && booking.status !== prev.status ? bookingStatusEventKey(booking.status) : undefined\n if (statusKey) {\n emitBookingEvent(statusKey, booking)\n } else if (prev && new Date(booking.startsAt).getTime() !== new Date(prev.startsAt).getTime()) {\n emitBookingEvent('agenda.booking_rescheduled', booking)\n }\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })\n toast.success('Appointment updated')\n return booking\n } catch (err: any) {\n toast.error('Failed to update appointment', { description: err?.message })\n throw err\n }\n },\n\n async deleteBooking(id) {\n try {\n await provider.deleteBooking(id)\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'delete', id, source: 'ui' })\n toast.success('Appointment deleted')\n } catch (err: any) {\n toast.error('Failed to delete appointment', { description: err?.message })\n throw err\n }\n },\n\n async updateBookingStatus(id, status) {\n // Optimistic update — change color immediately\n const prev = get().bookings\n const prevStatus = prev.find((b) => b.id === id)?.status\n set({ bookings: prev.map((b) => b.id === id ? { ...b, status: status as any } : b) })\n try {\n const updated = await provider.updateBookingStatus(id, status)\n // Só na transição real — reaplicar o mesmo status não é um fato novo.\n const key = prevStatus !== status ? bookingStatusEventKey(status) : undefined\n if (key) emitBookingEvent(key, updated)\n // Refresh from server to get full data\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n emitDataChanged({ table: 'appointments', op: 'update', id, source: 'ui' })\n toast.success('Status updated')\n } catch (err: any) {\n // Rollback on failure\n set({ bookings: prev })\n toast.error('Failed to update status', { description: err?.message })\n throw err\n }\n },\n\n async rescheduleBooking(id, newStart, newEnd, newProfessionalId) {\n try {\n // Check for conflicts\n const existing = get().bookings.find((b) => b.id === id)\n const assigneeId = newProfessionalId ?? existing?.professionalId\n if (assigneeId) {\n const hasConflict = await provider.checkConflict({\n assigneeId,\n startsAt: newStart,\n endsAt: newEnd,\n excludeBookingId: id,\n })\n if (hasConflict) {\n toast.error('Time conflict detected', { description: 'This professional already has an appointment at this time.' })\n throw new Error('Time conflict')\n }\n }\n const updated = await provider.updateBooking(id, {\n startsAt: newStart,\n endsAt: newEnd,\n ...(newProfessionalId && { professionalId: newProfessionalId }),\n })\n emitBookingEvent('agenda.booking_rescheduled', updated)\n const state = get()\n if (state.dateRange.start && state.dateRange.end) {\n const bookings = await provider.getBookings(getCurrentBookingQuery(state))\n set({ bookings })\n }\n toast.success('Appointment rescheduled')\n } catch (err: any) {\n if (err?.message !== 'Time conflict') {\n toast.error('Failed to reschedule', { description: err?.message })\n }\n throw err\n }\n },\n\n setFilters(filters) {\n set({\n ...(filters.professionalIds !== undefined && { selectedProfessionalIds: filters.professionalIds }),\n ...(filters.locationId !== undefined && { selectedLocationId: filters.locationId }),\n ...(filters.statuses !== undefined && { selectedStatuses: filters.statuses }),\n })\n // Re-fetch with new filters\n const { dateRange } = get()\n if (dateRange.start && dateRange.end) {\n get().fetchBookings(dateRange)\n }\n },\n\n setView(view) { set({ currentView: view }) },\n setSelectedDate(date) { set({ selectedDate: date }) },\n\n openAppointmentModal(mode, options) {\n set({ appointmentModal: { open: true, mode, bookingId: options?.bookingId, prefill: options?.prefill, initialTab: options?.initialTab, externalSource: options?.externalSource } })\n },\n\n closeAppointmentModal() {\n // Only toggle open — keep mode/bookingId/prefill intact so layout\n // doesn't shift during the close animation\n set((state) => ({ appointmentModal: { ...state.appointmentModal, open: false } }))\n },\n }))\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Holidays (public.holidays — tenant-scoped)\n// ---------------------------------------------------------------------------\n\nconst holidayEntity: EntityDef = {\n name: 'Holiday',\n namePlural: 'Holidays',\n icon: 'TreePalm',\n displayField: 'name',\n defaultSort: 'date',\n defaultSortDir: 'asc',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'date', label: 'Date', type: 'date', required: true, showInTable: true, sortable: true },\n { key: 'recurring', label: 'Recurring Annually', type: 'boolean', showInTable: true, defaultValue: false },\n { key: 'description', label: 'Description', type: 'text', showInTable: false },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: {\n table: 'holidays',\n tenantScoped: true,\n },\n}\n\nexport const agendaRegistries: PluginRegistryDef[] = [\n {\n id: 'holidays',\n entity: holidayEntity,\n icon: 'TreePalm',\n description: 'Non-working days and recurring holidays',\n },\n]\n","import React from 'react'\nimport { SettingsGroup, ToggleRow, SelectRow, useTenantPluginSettings } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useAgendaSettings } from '../hooks/useAgendaSettings'\n\nconst HOUR_OPTIONS = Array.from({ length: 18 }, (_, i) => {\n const h = (5 + i).toString().padStart(2, '0')\n return { value: `${h}:00`, label: `${h}:00` }\n})\n\n// Per-tenant toggle defaults = the values that used to be hardcoded here.\n// NOTE: these are persisted + re-hydrated per tenant; actually consuming them to\n// change agenda behaviour is a follow-up (see useTenantPluginSettings docs).\nconst AGENDA_TOGGLE_DEFAULTS = {\n conflictDetection: true,\n dragDrop: true,\n autoCreateOrder: true,\n enableLocation: false,\n enableWorkingHours: true,\n blockOutside: false,\n enableConfirmations: true,\n autoConfirm: false,\n reminder: true,\n showCancelled: false,\n showNoShow: true,\n compact: false,\n newBookingNotif: true,\n cancelAlerts: true,\n noShowTracking: false,\n}\n\nexport function AgendaGeneralSettings() {\n const t = useTranslation()\n const { startTime, endTime, setStartTime, setEndTime } = useAgendaSettings()\n const s = useTenantPluginSettings('agenda', AGENDA_TOGGLE_DEFAULTS)\n return (\n <div className=\"space-y-4\">\n <SettingsGroup title={t('agenda.settings.scheduling')} description={t('agenda.settings.schedulingDesc')}>\n <ToggleRow label={t('agenda.settings.conflictDetection')} description={t('agenda.settings.conflictDetectionDesc')} checked={s.get('conflictDetection')} onChange={(v) => s.set('conflictDetection', v)} />\n <ToggleRow label={t('agenda.settings.dragDrop')} description={t('agenda.settings.dragDropDesc')} checked={s.get('dragDrop')} onChange={(v) => s.set('dragDrop', v)} />\n <ToggleRow label={t('agenda.settings.autoCreateOrder')} description={t('agenda.settings.autoCreateOrderDesc')} checked={s.get('autoCreateOrder')} onChange={(v) => s.set('autoCreateOrder', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.locations')} description={t('agenda.settings.locationsDesc')}>\n <ToggleRow label={t('agenda.settings.enableLocation')} description={t('agenda.settings.enableLocationDesc')} checked={s.get('enableLocation')} onChange={(v) => s.set('enableLocation', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.workingHours')} description={t('agenda.settings.workingHoursDesc')}>\n <ToggleRow label={t('agenda.settings.enableWorkingHours')} description={t('agenda.settings.enableWorkingHoursDesc')} checked={s.get('enableWorkingHours')} onChange={(v) => s.set('enableWorkingHours', v)} />\n <ToggleRow label={t('agenda.settings.blockOutside')} description={t('agenda.settings.blockOutsideDesc')} checked={s.get('blockOutside')} onChange={(v) => s.set('blockOutside', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.confirmations')} description={t('agenda.settings.confirmationsDesc')}>\n <ToggleRow label={t('agenda.settings.enableConfirmations')} description={t('agenda.settings.enableConfirmationsDesc')} checked={s.get('enableConfirmations')} onChange={(v) => s.set('enableConfirmations', v)} />\n <ToggleRow label={t('agenda.settings.autoConfirm')} description={t('agenda.settings.autoConfirmDesc')} checked={s.get('autoConfirm')} onChange={(v) => s.set('autoConfirm', v)} />\n <ToggleRow label={t('agenda.settings.reminder')} description={t('agenda.settings.reminderDesc')} checked={s.get('reminder')} onChange={(v) => s.set('reminder', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.calendarDisplay')} description={t('agenda.settings.calendarDisplayDesc')}>\n <SelectRow\n label={t('agenda.settings.dayStartTime')}\n description={t('agenda.settings.dayStartTimeDesc')}\n value={startTime}\n options={HOUR_OPTIONS}\n onChange={setStartTime}\n />\n <SelectRow\n label={t('agenda.settings.dayEndTime')}\n description={t('agenda.settings.dayEndTimeDesc')}\n value={endTime}\n options={HOUR_OPTIONS}\n onChange={setEndTime}\n />\n <ToggleRow label={t('agenda.settings.showCancelled')} description={t('agenda.settings.showCancelledDesc')} checked={s.get('showCancelled')} onChange={(v) => s.set('showCancelled', v)} />\n <ToggleRow label={t('agenda.settings.showNoShow')} description={t('agenda.settings.showNoShowDesc')} checked={s.get('showNoShow')} onChange={(v) => s.set('showNoShow', v)} />\n <ToggleRow label={t('agenda.settings.compact')} description={t('agenda.settings.compactDesc')} checked={s.get('compact')} onChange={(v) => s.set('compact', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('agenda.settings.notifications')} description={t('agenda.settings.notificationsDesc')}>\n <ToggleRow label={t('agenda.settings.newBookingNotif')} description={t('agenda.settings.newBookingNotifDesc')} checked={s.get('newBookingNotif')} onChange={(v) => s.set('newBookingNotif', v)} />\n <ToggleRow label={t('agenda.settings.cancelAlerts')} description={t('agenda.settings.cancelAlertsDesc')} checked={s.get('cancelAlerts')} onChange={(v) => s.set('cancelAlerts', v)} />\n <ToggleRow label={t('agenda.settings.noShowTracking')} description={t('agenda.settings.noShowTrackingDesc')} checked={s.get('noShowTracking')} onChange={(v) => s.set('noShowTracking', v)} />\n </SettingsGroup>\n </div>\n )\n}\n","// agenda.* — merged plugin-own + saas-core central i18n\nexport const en: Record<string, string> = {\n \"agenda.appointment.addDescription\": \"Add description...\",\n \"agenda.appointment.addService\": \"Add service\",\n \"agenda.appointment.cancel\": \"Cancel\",\n \"agenda.appointment.clientTab\": \"Client\",\n \"agenda.appointment.noClientData\": \"No client data available\",\n \"agenda.appointment.client\": \"Client\",\n \"agenda.appointment.conflict\": \"Time conflict — this professional is already booked at this time.\",\n \"agenda.appointment.create\": \"Create\",\n \"agenda.appointment.createClientFailed\": \"Failed to create client\",\n \"agenda.appointment.creating\": \"Creating...\",\n \"agenda.appointment.delete\": \"Delete\",\n \"agenda.appointment.deleteConfirm\": \"Delete this appointment?\",\n \"agenda.appointment.confirmDelete\": \"Delete\",\n \"agenda.appointment.deleting\": \"Deleting…\",\n \"agenda.appointment.edit\": \"Edit Appointment\",\n \"agenda.appointment.emailOptional\": \"Email (optional)\",\n \"agenda.appointment.location\": \"Location\",\n \"agenda.appointment.name\": \"Name\",\n \"agenda.appointment.new\": \"New Appointment\",\n \"agenda.appointment.newClient\": \"New client\",\n \"agenda.appointment.required\": \"Required\",\n \"agenda.appointment.newService\": \"New service\",\n \"agenda.appointment.notes\": \"Notes\",\n \"agenda.appointment.phone\": \"Phone\",\n \"agenda.appointment.professional\": \"Professional\",\n \"agenda.appointment.save\": \"Save\",\n \"agenda.appointment.saving\": \"Saving...\",\n \"agenda.appointment.searchClient\": \"Search client...\",\n \"agenda.appointment.searchService\": \"Search service to add...\",\n \"agenda.appointment.selectLocation\": \"Select location...\",\n \"agenda.appointment.selectProfessional\": \"Select professional...\",\n \"agenda.appointment.services\": \"Services\",\n \"agenda.appointment.status\": \"Status\",\n \"agenda.appointment.to\": \"to\",\n \"agenda.appointment.total\": \"Total\",\n \"agenda.appointment.update\": \"Update\",\n \"agenda.payment.title\": \"Payment\",\n \"agenda.payment.generateInvoice\": \"Generate invoice\",\n \"agenda.payment.generating\": \"Generating…\",\n \"agenda.payment.pending\": \"Pending\",\n \"agenda.payment.partial\": \"Partial\",\n \"agenda.payment.paid\": \"Paid\",\n \"agenda.payment.collect\": \"Collect\",\n \"agenda.payment.overdue\": \"Overdue\",\n \"agenda.payment.cancelled\": \"Cancelled\",\n \"agenda.payment.none\": \"Payment\",\n \"agenda.payment.pay\": \"Pay\",\n \"agenda.payment.paying\": \"Paying…\",\n \"agenda.payment.remaining\": \"Remaining\",\n \"agenda.payment.installment\": \"Installment\",\n \"agenda.payment.total\": \"Total\",\n \"agenda.payment.noInvoice\": \"No invoice generated\",\n \"agenda.payment.selectAccount\": \"Select account\",\n \"agenda.payment.registerPayment\": \"Register payment\",\n \"agenda.payment.registerPaymentHint\": \"Record a payment for this appointment\",\n \"agenda.payment.pendingHint\": \"Invoice generated, awaiting payment\",\n \"agenda.payment.partialHint\": \"Partially paid, tap to complete\",\n \"agenda.payment.paidHint\": \"Payment completed\",\n \"agenda.payment.overdueHint\": \"Payment overdue\",\n \"agenda.payment.backToAppointment\": \"Back to appointment\",\n \"agenda.payment.checkout\": \"Confirm\",\n \"agenda.payment.checkingOut\": \"Processing…\",\n \"agenda.payment.serviceSummary\": \"Service summary\",\n \"agenda.payment.paymentMethod\": \"Payment method\",\n \"agenda.payment.noMethods\": \"No payment methods configured.\",\n \"agenda.payment.configureMethods\": \"Set up payment methods\",\n \"agenda.payment.checkoutComplete\": \"Payment confirmed\",\n \"agenda.payment.card\": \"Card\",\n \"agenda.payment.method\": \"Method\",\n \"agenda.payment.select\": \"Select…\",\n \"agenda.payment.cardBrand\": \"Brand\",\n \"agenda.payment.selectBrand\": \"Select brand…\",\n \"agenda.payment.cardInstallments\": \"Installments\",\n \"agenda.payment.bankAccount\": \"Account\",\n \"agenda.payment.viewInvoice\": \"View invoice details\",\n \"agenda.calendar.agendas\": \"Agendas\",\n \"agenda.calendar.create\": \"Create\",\n \"agenda.calendar.next\": \"Next\",\n \"agenda.calendar.previous\": \"Previous\",\n \"agenda.calendar.status\": \"Status\",\n \"agenda.calendar.today\": \"Today\",\n \"agenda.calendar.viewAgenda\": \"Agenda\",\n \"agenda.calendar.viewDay\": \"Day\",\n \"agenda.calendar.viewList\": \"List\",\n \"agenda.calendar.viewMonth\": \"Month\",\n \"agenda.calendar.viewWeek\": \"Week\",\n \"agenda.list.today\": \"Today\",\n \"agenda.list.tomorrow\": \"Tomorrow\",\n \"agenda.list.empty\": \"No upcoming items\",\n \"agenda.confirmations.confirmed\": \"Confirmed:\",\n \"agenda.confirmations.empty\": \"No pending confirmations\",\n \"agenda.confirmations.emptySubtitle\": \"All upcoming appointments have been confirmed\",\n \"agenda.confirmations.loading\": \"Loading...\",\n \"agenda.confirmations.subtitle\": \"Upcoming appointments pending confirmation\",\n \"agenda.confirmations.unknownClient\": \"Unknown client\",\n \"agenda.confirmations.sendWhatsApp\": \"Send WhatsApp\",\n \"agenda.confirmations.call\": \"Call\",\n \"agenda.confirmations.markConfirmed\": \"Mark Confirmed\",\n \"agenda.confirmations.markCancelled\": \"Mark Cancelled\",\n \"agenda.cancellation.loadingReasons\": \"Loading reasons...\",\n \"agenda.cancellation.notesOptional\": \"Cancellation notes (optional)\",\n \"agenda.cancellation.notesRequired\": \"Cancellation notes required\",\n \"agenda.cancellation.selectReason\": \"Select cancellation reason\",\n \"agenda.contextMenu.changeStatus\": \"Change status\",\n \"agenda.contextMenu.delete\": \"Delete\",\n \"agenda.contextMenu.edit\": \"Edit\",\n \"agenda.contextMenu.notAvailable\": \"(not available)\",\n \"agenda.index.settingsSubtitle\": \"Working hours, scheduling preferences, and confirmations\",\n \"agenda.index.settingsTitle\": \"Agenda Settings\",\n \"settings.plugin.agenda-working-hours\": \"Working Hours\",\n \"agenda.popover.unknown\": \"Unknown\",\n \"agenda.settings.autoConfirm\": \"Auto-confirm\",\n \"agenda.settings.autoConfirmDesc\": \"Automatically confirm new bookings\",\n \"agenda.settings.autoCreateOrder\": \"Auto-create Order\",\n \"agenda.settings.autoCreateOrderDesc\": \"Automatically create a financial order for new bookings\",\n \"agenda.settings.blockOutside\": \"Block Outside Hours\",\n \"agenda.settings.blockOutsideDesc\": \"Prevent bookings outside working hours\",\n \"agenda.settings.calendarDisplay\": \"Calendar Display\",\n \"agenda.settings.calendarDisplayDesc\": \"Visual settings for the calendar\",\n \"agenda.settings.cancelAlerts\": \"Cancellation Alerts\",\n \"agenda.settings.cancelAlertsDesc\": \"Notify when a booking is cancelled\",\n \"agenda.settings.compact\": \"Compact Mode\",\n \"agenda.settings.compactDesc\": \"Use smaller event blocks\",\n \"agenda.settings.confirmations\": \"Confirmations\",\n \"agenda.settings.confirmationsDesc\": \"Booking confirmation settings\",\n \"agenda.settings.conflictDetection\": \"Conflict Detection\",\n \"agenda.settings.conflictDetectionDesc\": \"Warn when bookings overlap\",\n \"agenda.settings.dragDrop\": \"Drag & Drop\",\n \"agenda.settings.dragDropDesc\": \"Allow rescheduling by dragging events\",\n \"agenda.settings.enableConfirmations\": \"Enable Confirmations\",\n \"agenda.settings.enableConfirmationsDesc\": \"Require confirmation for new bookings\",\n \"agenda.settings.enableLocation\": \"Enable Location Selection\",\n \"agenda.settings.enableLocationDesc\": \"Show location picker in booking modal\",\n \"agenda.settings.enableWorkingHours\": \"Enable Working Hours\",\n \"agenda.settings.enableWorkingHoursDesc\": \"Show working hours overlay on calendar\",\n \"agenda.settings.locations\": \"Locations\",\n \"agenda.settings.locationsDesc\": \"Multi-location settings\",\n \"agenda.settings.newBookingNotif\": \"New Booking Alerts\",\n \"agenda.settings.newBookingNotifDesc\": \"Notify when a new booking is created\",\n \"agenda.settings.noShowTracking\": \"No-show Tracking\",\n \"agenda.settings.noShowTrackingDesc\": \"Track and alert on no-shows\",\n \"agenda.settings.notifications\": \"Notifications\",\n \"agenda.settings.notificationsDesc\": \"Notification preferences\",\n \"agenda.settings.reminder\": \"Reminders\",\n \"agenda.settings.reminderDesc\": \"Send reminders before appointments\",\n \"agenda.settings.scheduling\": \"Scheduling\",\n \"agenda.settings.schedulingDesc\": \"Configure scheduling behavior\",\n \"agenda.settings.showCancelled\": \"Show Cancelled\",\n \"agenda.settings.showCancelledDesc\": \"Display cancelled bookings on calendar\",\n \"agenda.settings.showNoShow\": \"Show No-shows\",\n \"agenda.settings.showNoShowDesc\": \"Display no-show bookings on calendar\",\n \"agenda.settings.workingHours\": \"Working Hours\",\n \"agenda.settings.workingHoursDesc\": \"Working hours and availability\",\n \"agenda.sidebar.agendas\": \"Agendas\",\n \"agenda.sidebar.searchAgendas\": \"Find an agenda\",\n \"agenda.sidebar.tooManyAgendas\": \"Up to {max} agendas at a time — uncheck one to add another.\",\n \"agenda.sidebar.allLocations\": \"All locations\",\n \"agenda.sidebar.create\": \"Create\",\n \"agenda.sidebar.location\": \"Location\",\n \"agenda.sidebar.status\": \"Status\",\n \"agenda.toolbar.next\": \"Next\",\n \"agenda.toolbar.previous\": \"Previous\",\n \"agenda.toolbar.today\": \"Today\",\n \"agenda.workingHours.addBreak\": \"Add break\",\n \"agenda.workingHours.copyToAll\": \"Copy to all\",\n \"agenda.workingHours.dayOff\": \"Day off\",\n \"agenda.workingHours.removePeriod\": \"Remove period\",\n \"agenda.workingHours.professional\": \"Professional\",\n \"agenda.workingHours.save\": \"Save\",\n \"agenda.workingHours.saveFailed\": \"Failed to save\",\n \"agenda.workingHours.saved\": \"Working hours saved\",\n \"agenda.workingHours.saving\": \"Saving...\",\n \"agenda.workingHours.subtitle\": \"Manage working hours per professional\",\n \"agenda.workingHours.to\": \"to\",\n \"agenda.title\": \"Agenda\",\n \"agenda.calendar.title\": \"Calendar\",\n \"agenda.calendar.noScheduleConfirm\": \"This time slot has no open schedule for this professional. Do you want to book anyway?\",\n \"agenda.calendar.newAppointment\": \"New Appointment\",\n \"agenda.booking.create\": \"New Appointment\",\n \"agenda.booking.edit\": \"Edit Appointment\",\n \"agenda.booking.delete\": \"Delete Appointment\",\n \"agenda.booking.deleteConfirm\": \"Are you sure you want to delete this appointment?\",\n \"agenda.booking.client\": \"Client\",\n \"agenda.booking.professional\": \"Professional\",\n \"agenda.booking.services\": \"Services\",\n \"agenda.booking.date\": \"Date\",\n \"agenda.booking.time\": \"Time\",\n \"agenda.booking.duration\": \"Duration\",\n \"agenda.booking.notes\": \"Notes\",\n \"agenda.booking.status\": \"Status\",\n \"agenda.booking.save\": \"Save Appointment\",\n \"agenda.booking.saving\": \"Saving...\",\n \"agenda.confirmations.title\": \"Confirmations\",\n \"agenda.confirmations.pending\": \"Pending Confirmations\",\n \"agenda.confirmations.emptyDescription\": \"All upcoming appointments have been confirmed\",\n \"agenda.confirmations.confirm\": \"Confirm\",\n \"agenda.confirmations.cancel\": \"Cancel\",\n \"agenda.workingHours.title\": \"Working Hours\",\n \"agenda.workingHours.addPeriod\": \"Add period\",\n \"agenda.workingHours.loading\": \"Loading...\",\n \"agenda.appointment.addClient\": \"Add client\",\n \"agenda.appointment.addServiceFirst\": \"Add service\",\n \"agenda.appointment.addNotes\": \"Add notes\",\n \"agenda.appointment.duration\": \"Duration (minutes)\",\n \"agenda.appointment.price\": \"Price\",\n \"agenda.appointment.title\": \"Title\",\n \"agenda.appointment.addTitle\": \"Add a title\",\n \"agenda.appointment.untitled\": \"(no title)\",\n \"agenda.bookingType.appointment\": \"Appointment\",\n \"agenda.bookingType.event\": \"Event\",\n \"agenda.bookingType.task\": \"Task\",\n \"agenda.bookingType.out_of_office\": \"Out of Office\",\n \"agenda.bookingType.block\": \"Block\",\n \"agenda.settings.title\": \"Agenda Settings\",\n \"agenda.settings.slotDuration\": \"Slot Duration\",\n \"agenda.settings.bookingKind\": \"Booking Kind\",\n \"agenda.settings.dayStartTime\": \"Day Start Time\",\n \"agenda.settings.dayStartTimeDesc\": \"First hour shown on the calendar\",\n \"agenda.settings.dayEndTime\": \"Day End Time\",\n \"agenda.settings.dayEndTimeDesc\": \"Last hour shown on the calendar\",\n}\n","// agenda.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"agenda.appointment.addDescription\": \"Adicionar descrição...\",\n \"agenda.appointment.addService\": \"Adicionar serviço\",\n \"agenda.appointment.cancel\": \"Cancelar\",\n \"agenda.appointment.clientTab\": \"Cliente\",\n \"agenda.appointment.noClientData\": \"Dados do cliente não disponíveis\",\n \"agenda.appointment.client\": \"Cliente\",\n \"agenda.appointment.conflict\": \"Conflito de horário — este profissional já está reservado neste horário.\",\n \"agenda.appointment.create\": \"Criar\",\n \"agenda.appointment.createClientFailed\": \"Falha ao criar cliente\",\n \"agenda.appointment.creating\": \"Criando...\",\n \"agenda.appointment.delete\": \"Excluir\",\n \"agenda.appointment.deleteConfirm\": \"Excluir este agendamento?\",\n \"agenda.appointment.confirmDelete\": \"Excluir\",\n \"agenda.appointment.deleting\": \"Excluindo…\",\n \"agenda.appointment.edit\": \"Editar Agendamento\",\n \"agenda.appointment.emailOptional\": \"E-mail (opcional)\",\n \"agenda.appointment.location\": \"Local\",\n \"agenda.appointment.name\": \"Nome\",\n \"agenda.appointment.new\": \"Novo Agendamento\",\n \"agenda.appointment.newClient\": \"Novo cliente\",\n \"agenda.appointment.required\": \"Obrigatório\",\n \"agenda.appointment.newService\": \"Novo serviço\",\n \"agenda.appointment.notes\": \"Observações\",\n \"agenda.appointment.phone\": \"Telefone\",\n \"agenda.appointment.professional\": \"Profissional\",\n \"agenda.appointment.save\": \"Salvar\",\n \"agenda.appointment.saving\": \"Salvando...\",\n \"agenda.appointment.searchClient\": \"Buscar cliente...\",\n \"agenda.appointment.searchService\": \"Buscar serviço para adicionar...\",\n \"agenda.appointment.selectLocation\": \"Selecionar local...\",\n \"agenda.appointment.selectProfessional\": \"Selecionar profissional...\",\n \"agenda.appointment.services\": \"Serviços\",\n \"agenda.appointment.status\": \"Status\",\n \"agenda.appointment.to\": \"até\",\n \"agenda.appointment.total\": \"Total\",\n \"agenda.appointment.update\": \"Atualizar\",\n \"agenda.payment.title\": \"Recebimento\",\n \"agenda.payment.generateInvoice\": \"Gerar recebimento\",\n \"agenda.payment.generating\": \"Gerando…\",\n \"agenda.payment.pending\": \"Pendente\",\n \"agenda.payment.partial\": \"Parcial\",\n \"agenda.payment.paid\": \"Pago\",\n \"agenda.payment.collect\": \"Receber\",\n \"agenda.payment.overdue\": \"Vencido\",\n \"agenda.payment.cancelled\": \"Cancelado\",\n \"agenda.payment.none\": \"Recebimento\",\n \"agenda.payment.pay\": \"Pagar\",\n \"agenda.payment.paying\": \"Pagando…\",\n \"agenda.payment.remaining\": \"Restante\",\n \"agenda.payment.installment\": \"Parcela\",\n \"agenda.payment.total\": \"Total\",\n \"agenda.payment.noInvoice\": \"Sem recebimento gerado\",\n \"agenda.payment.selectAccount\": \"Selecionar conta\",\n \"agenda.payment.registerPayment\": \"Registrar recebimento\",\n \"agenda.payment.registerPaymentHint\": \"Registrar pagamento deste agendamento\",\n \"agenda.payment.pendingHint\": \"Fatura gerada, aguardando pagamento\",\n \"agenda.payment.partialHint\": \"Parcialmente pago, toque para completar\",\n \"agenda.payment.paidHint\": \"Pagamento realizado\",\n \"agenda.payment.overdueHint\": \"Pagamento vencido\",\n \"agenda.payment.backToAppointment\": \"Voltar ao agendamento\",\n \"agenda.payment.checkout\": \"Confirmar\",\n \"agenda.payment.checkingOut\": \"Processando…\",\n \"agenda.payment.serviceSummary\": \"Resumo do atendimento\",\n \"agenda.payment.paymentMethod\": \"Forma de pagamento\",\n \"agenda.payment.noMethods\": \"Nenhuma forma de pagamento configurada.\",\n \"agenda.payment.configureMethods\": \"Configurar formas de pagamento\",\n \"agenda.payment.checkoutComplete\": \"Pagamento confirmado\",\n \"agenda.payment.card\": \"Cartão\",\n \"agenda.payment.method\": \"Método\",\n \"agenda.payment.select\": \"Selecionar…\",\n \"agenda.payment.cardBrand\": \"Bandeira\",\n \"agenda.payment.selectBrand\": \"Selecionar bandeira…\",\n \"agenda.payment.cardInstallments\": \"Parcelas\",\n \"agenda.payment.bankAccount\": \"Conta\",\n \"agenda.payment.viewInvoice\": \"Ver detalhes da fatura\",\n \"agenda.calendar.agendas\": \"Agendas\",\n \"agenda.calendar.create\": \"Criar\",\n \"agenda.calendar.next\": \"Próximo\",\n \"agenda.calendar.previous\": \"Anterior\",\n \"agenda.calendar.status\": \"Status\",\n \"agenda.calendar.today\": \"Hoje\",\n \"agenda.calendar.viewAgenda\": \"Agenda\",\n \"agenda.calendar.viewDay\": \"Dia\",\n \"agenda.calendar.viewList\": \"Lista\",\n \"agenda.calendar.viewMonth\": \"Mês\",\n \"agenda.calendar.viewWeek\": \"Semana\",\n \"agenda.list.today\": \"Hoje\",\n \"agenda.list.tomorrow\": \"Amanhã\",\n \"agenda.list.empty\": \"Nenhum item próximo\",\n \"agenda.confirmations.confirmed\": \"Confirmado:\",\n \"agenda.confirmations.empty\": \"Nenhuma confirmação pendente\",\n \"agenda.confirmations.emptySubtitle\": \"Todos os agendamentos futuros foram confirmados\",\n \"agenda.confirmations.loading\": \"Carregando...\",\n \"agenda.confirmations.subtitle\": \"Agendamentos futuros pendentes de confirmação\",\n \"agenda.confirmations.unknownClient\": \"Cliente desconhecido\",\n \"agenda.confirmations.sendWhatsApp\": \"Enviar WhatsApp\",\n \"agenda.confirmations.call\": \"Ligar\",\n \"agenda.confirmations.markConfirmed\": \"Marcar Confirmado\",\n \"agenda.confirmations.markCancelled\": \"Marcar Cancelado\",\n \"agenda.cancellation.loadingReasons\": \"Carregando motivos...\",\n \"agenda.cancellation.notesOptional\": \"Observações do cancelamento (opcional)\",\n \"agenda.cancellation.notesRequired\": \"Observações do cancelamento obrigatórias\",\n \"agenda.cancellation.selectReason\": \"Selecionar motivo do cancelamento\",\n \"agenda.contextMenu.changeStatus\": \"Alterar status\",\n \"agenda.contextMenu.delete\": \"Excluir\",\n \"agenda.contextMenu.edit\": \"Editar\",\n \"agenda.contextMenu.notAvailable\": \"(indisponível)\",\n \"agenda.index.settingsSubtitle\": \"Horários de funcionamento, preferências de agendamento e confirmações\",\n \"agenda.index.settingsTitle\": \"Configurações da Agenda\",\n \"settings.plugin.agenda-working-hours\": \"Horário de Funcionamento\",\n \"agenda.popover.unknown\": \"Desconhecido\",\n \"agenda.settings.autoConfirm\": \"Confirmar Automaticamente\",\n \"agenda.settings.autoConfirmDesc\": \"Confirmar automaticamente novos agendamentos\",\n \"agenda.settings.autoCreateOrder\": \"Criar Pedido Automaticamente\",\n \"agenda.settings.autoCreateOrderDesc\": \"Criar automaticamente um pedido financeiro para novos agendamentos\",\n \"agenda.settings.blockOutside\": \"Bloquear Fora do Horário\",\n \"agenda.settings.blockOutsideDesc\": \"Impedir agendamentos fora do horário de funcionamento\",\n \"agenda.settings.calendarDisplay\": \"Exibição do Calendário\",\n \"agenda.settings.calendarDisplayDesc\": \"Configurações visuais do calendário\",\n \"agenda.settings.cancelAlerts\": \"Alertas de Cancelamento\",\n \"agenda.settings.cancelAlertsDesc\": \"Notificar quando um agendamento é cancelado\",\n \"agenda.settings.compact\": \"Modo Compacto\",\n \"agenda.settings.compactDesc\": \"Usar blocos de eventos menores\",\n \"agenda.settings.confirmations\": \"Confirmações\",\n \"agenda.settings.confirmationsDesc\": \"Configurações de confirmação de agendamento\",\n \"agenda.settings.conflictDetection\": \"Detecção de Conflitos\",\n \"agenda.settings.conflictDetectionDesc\": \"Alertar quando agendamentos se sobrepõem\",\n \"agenda.settings.dragDrop\": \"Arrastar e Soltar\",\n \"agenda.settings.dragDropDesc\": \"Permitir reagendamento arrastando eventos\",\n \"agenda.settings.enableConfirmations\": \"Habilitar Confirmações\",\n \"agenda.settings.enableConfirmationsDesc\": \"Exigir confirmação para novos agendamentos\",\n \"agenda.settings.enableLocation\": \"Habilitar Seleção de Local\",\n \"agenda.settings.enableLocationDesc\": \"Mostrar seletor de local no modal de agendamento\",\n \"agenda.settings.enableWorkingHours\": \"Habilitar Horário de Funcionamento\",\n \"agenda.settings.enableWorkingHoursDesc\": \"Mostrar sobreposição de horário de funcionamento no calendário\",\n \"agenda.settings.locations\": \"Locais\",\n \"agenda.settings.locationsDesc\": \"Configurações de múltiplos locais\",\n \"agenda.settings.newBookingNotif\": \"Alertas de Novo Agendamento\",\n \"agenda.settings.newBookingNotifDesc\": \"Notificar quando um novo agendamento é criado\",\n \"agenda.settings.noShowTracking\": \"Rastreamento de Ausências\",\n \"agenda.settings.noShowTrackingDesc\": \"Rastrear e alertar sobre ausências\",\n \"agenda.settings.notifications\": \"Notificações\",\n \"agenda.settings.notificationsDesc\": \"Preferências de notificação\",\n \"agenda.settings.reminder\": \"Lembretes\",\n \"agenda.settings.reminderDesc\": \"Enviar lembretes antes dos compromissos\",\n \"agenda.settings.scheduling\": \"Agendamento\",\n \"agenda.settings.schedulingDesc\": \"Configurar comportamento do agendamento\",\n \"agenda.settings.showCancelled\": \"Mostrar Cancelados\",\n \"agenda.settings.showCancelledDesc\": \"Exibir agendamentos cancelados no calendário\",\n \"agenda.settings.showNoShow\": \"Mostrar Ausências\",\n \"agenda.settings.showNoShowDesc\": \"Exibir ausências no calendário\",\n \"agenda.settings.workingHours\": \"Horário de Funcionamento\",\n \"agenda.settings.workingHoursDesc\": \"Horários e disponibilidade\",\n \"agenda.sidebar.agendas\": \"Agendas\",\n \"agenda.sidebar.searchAgendas\": \"Buscar agenda\",\n \"agenda.sidebar.tooManyAgendas\": \"Até {max} agendas por vez — desmarque uma para incluir outra.\",\n \"agenda.sidebar.allLocations\": \"Todos os locais\",\n \"agenda.sidebar.create\": \"Criar\",\n \"agenda.sidebar.location\": \"Local\",\n \"agenda.sidebar.status\": \"Status\",\n \"agenda.toolbar.next\": \"Próximo\",\n \"agenda.toolbar.previous\": \"Anterior\",\n \"agenda.toolbar.today\": \"Hoje\",\n \"agenda.workingHours.addBreak\": \"Adicionar intervalo\",\n \"agenda.workingHours.copyToAll\": \"Copiar para todos\",\n \"agenda.workingHours.dayOff\": \"Folga\",\n \"agenda.workingHours.removePeriod\": \"Remover período\",\n \"agenda.workingHours.professional\": \"Profissional\",\n \"agenda.workingHours.save\": \"Salvar\",\n \"agenda.workingHours.saveFailed\": \"Falha ao salvar\",\n \"agenda.workingHours.saved\": \"Horários de trabalho salvos\",\n \"agenda.workingHours.saving\": \"Salvando...\",\n \"agenda.workingHours.subtitle\": \"Gerenciar horários de trabalho por profissional\",\n \"agenda.workingHours.to\": \"até\",\n \"agenda.title\": \"Agenda\",\n \"agenda.calendar.title\": \"Calendário\",\n \"agenda.calendar.noScheduleConfirm\": \"Este horário não possui agenda aberta para este profissional. Deseja agendar mesmo assim?\",\n \"agenda.calendar.newAppointment\": \"Novo Agendamento\",\n \"agenda.booking.create\": \"Novo Agendamento\",\n \"agenda.booking.edit\": \"Editar Agendamento\",\n \"agenda.booking.delete\": \"Excluir Agendamento\",\n \"agenda.booking.deleteConfirm\": \"Tem certeza que deseja excluir este agendamento?\",\n \"agenda.booking.client\": \"Cliente\",\n \"agenda.booking.professional\": \"Profissional\",\n \"agenda.booking.services\": \"Serviços\",\n \"agenda.booking.date\": \"Data\",\n \"agenda.booking.time\": \"Horário\",\n \"agenda.booking.duration\": \"Duração\",\n \"agenda.booking.notes\": \"Observações\",\n \"agenda.booking.status\": \"Status\",\n \"agenda.booking.save\": \"Salvar Agendamento\",\n \"agenda.booking.saving\": \"Salvando...\",\n \"agenda.confirmations.title\": \"Confirmações\",\n \"agenda.confirmations.pending\": \"Confirmações Pendentes\",\n \"agenda.confirmations.emptyDescription\": \"Todos os agendamentos futuros foram confirmados\",\n \"agenda.confirmations.confirm\": \"Confirmar\",\n \"agenda.confirmations.cancel\": \"Cancelar\",\n \"agenda.workingHours.title\": \"Horário de Trabalho\",\n \"agenda.workingHours.addPeriod\": \"Adicionar período\",\n \"agenda.workingHours.loading\": \"Carregando...\",\n \"agenda.appointment.addClient\": \"Adicionar cliente\",\n \"agenda.appointment.addServiceFirst\": \"Adicionar serviço\",\n \"agenda.appointment.addNotes\": \"Adicionar observações\",\n \"agenda.appointment.duration\": \"Duração (minutos)\",\n \"agenda.appointment.price\": \"Preço\",\n \"agenda.appointment.title\": \"Título\",\n \"agenda.appointment.addTitle\": \"Adicionar um título\",\n \"agenda.appointment.untitled\": \"(sem título)\",\n \"agenda.bookingType.appointment\": \"Agendamento\",\n \"agenda.bookingType.event\": \"Evento\",\n \"agenda.bookingType.task\": \"Tarefa\",\n \"agenda.bookingType.out_of_office\": \"Ausência\",\n \"agenda.bookingType.block\": \"Bloqueio\",\n \"agenda.settings.title\": \"Configurações da Agenda\",\n \"agenda.settings.slotDuration\": \"Duração do Intervalo\",\n \"agenda.settings.bookingKind\": \"Tipo de Agendamento\",\n \"agenda.settings.dayStartTime\": \"Horário de Início\",\n \"agenda.settings.dayStartTimeDesc\": \"Primeiro horário exibido no calendário\",\n \"agenda.settings.dayEndTime\": \"Horário de Término\",\n \"agenda.settings.dayEndTimeDesc\": \"Último horário exibido no calendário\",\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const agendaLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_the_connector_definers_keep_a_pinned_path.sql, 002_the_appointment_names_the_unit.sql, 003_the_client_arrives_before_being_served.sql, 004_the_appointment_carries_its_unit.sql, 005_the_queue_knows_how_long_she_waited.sql, 006_the_agenda_stops_pricing_every_invoice.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- ============================================================================\n-- plugins/plugin-agenda/src/migrations/000_baseline.sql — what installing this provisions, as one file.\n--\n-- GENERATED by scripts/emit-unit-baselines.mjs (#338). Do not edit by hand:\n-- change the schema, regenerate, and let scripts/check-chain-equivalence.mjs\n-- prove the result still matches.\n--\n-- This replaced 23 migration files. They are kept, unapplied, in\n-- migrations.archive/ — a year of decisions is worth reading even when it is no\n-- longer worth replaying.\n--\n-- Object order is fixed rather than dependency-sorted: schemas, types,\n-- sequences, tables, defaults, functions, constraints, views, indexes, foreign\n-- keys, triggers, row security, policies, grants. Dependencies BETWEEN units\n-- are carried by the order packages/db/chain.json declares.\n-- ============================================================================\n\n-- A LANGUAGE sql function binds its body at CREATE time, and 570 functions\n-- sorted by name are not sorted by who calls whom. This is what lets them load\n-- in any order; every body is still compiled on first call, so a genuinely\n-- broken reference surfaces then rather than never. Session-scoped.\nSET check_function_bodies = false;\n\n\n\n-- ── default privileges: reset ───────────────────────────────────────────\n-- Cleared BEFORE anything is created, so every object below gets the ACL the\n-- dump describes rather than the image's defaults on top of it. Restored at\n-- the end of this file.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\n\n-- ── function ────────────────────────────────────────────────────────────\n\nCREATE FUNCTION public.agenda_assert_service_is_public(p_tenant_id uuid, p_service_id uuid) RETURNS void\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n IF EXISTS (SELECT 1 FROM app.resource_grants g\n WHERE g.tenant_id = p_tenant_id\n AND g.resource_type = 'catalog.product'\n AND g.resource_id = p_service_id\n AND g.relation = 'available_in') THEN\n RAISE EXCEPTION 'este serviço não está disponível para agendamento online'\n USING ERRCODE = '42501',\n HINT = 'The service is released to specific units; the public booking path is tenant-wide and cannot honour a unit release (#201).';\n END IF;\nEND $$;\n\nCREATE FUNCTION public.agenda_booking_cancel(p_appointment_id uuid, p_hard boolean DEFAULT false) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $_$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_appt public.appointments%ROWTYPE;\n v_money integer := 0;\nBEGIN\n SELECT * INTO v_appt FROM public.appointments a WHERE a.id = p_appointment_id AND a.tenant_id = v_tenant;\n IF v_appt.id IS NULL THEN\n RAISE EXCEPTION 'agenda_booking_cancel: appointment % not found', p_appointment_id USING ERRCODE = 'P0002';\n END IF;\n IF NOT (select app.has_permission('agenda.delete', v_appt.unit_id)) THEN\n RAISE EXCEPTION 'agenda_booking_cancel: agenda.delete is required' USING ERRCODE = '42501';\n END IF;\n\n -- Money that exists is never deleted. A booking that raised a Título is\n -- CANCELLED, both sides, in one transaction.\n IF v_appt.order_id IS NOT NULL AND to_regclass('public.plg_financial_invoices') IS NOT NULL THEN\n EXECUTE 'SELECT count(*)::int FROM public.plg_financial_invoices WHERE order_id = $1 AND cancelled_at IS NULL'\n INTO v_money USING v_appt.order_id;\n END IF;\n\n IF v_money > 0 OR NOT p_hard THEN\n UPDATE public.appointments SET status = 'cancelled' WHERE id = p_appointment_id;\n IF v_appt.order_id IS NOT NULL THEN\n UPDATE public.orders SET status = 'cancelled' WHERE id = v_appt.order_id AND status <> 'completed';\n END IF;\n RETURN jsonb_build_object('cancelled', true, 'deleted', false, 'order_id', v_appt.order_id);\n END IF;\n\n DELETE FROM public.appointments WHERE id = p_appointment_id;\n IF v_appt.order_id IS NOT NULL THEN\n DELETE FROM public.orders WHERE id = v_appt.order_id;\n END IF;\n RETURN jsonb_build_object('cancelled', true, 'deleted', true, 'order_id', v_appt.order_id);\nEND $_$;\n\nCREATE FUNCTION public.agenda_booking_create(p_starts_at timestamp with time zone, p_ends_at timestamp with time zone DEFAULT NULL::timestamp with time zone, p_lines jsonb DEFAULT '[]'::jsonb, p_party_id uuid DEFAULT NULL::uuid, p_assignee_id uuid DEFAULT NULL::uuid, p_unit_id uuid DEFAULT NULL::uuid, p_location_id uuid DEFAULT NULL::uuid, p_kind text DEFAULT 'appointment'::text, p_notes text DEFAULT NULL::text, p_metadata jsonb DEFAULT '{}'::jsonb, p_idempotency_key text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_order uuid;\n v_booking uuid;\n v_ends timestamptz;\n v_minutes integer;\n v_line jsonb;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'agenda_booking_create: no active tenant' USING ERRCODE = '42501';\n END IF;\n IF NOT (select app.has_permission('agenda.create', p_unit_id)) THEN\n RAISE EXCEPTION 'agenda_booking_create: agenda.create is required' USING ERRCODE = '42501';\n END IF;\n\n IF p_idempotency_key IS NOT NULL THEN\n SELECT a.id, a.order_id INTO v_booking, v_order FROM public.appointments a\n WHERE a.tenant_id = v_tenant AND a.metadata ->> 'idempotencyKey' = p_idempotency_key\n LIMIT 1;\n IF v_booking IS NOT NULL THEN\n RETURN jsonb_build_object('appointment_id', v_booking, 'order_id', v_order, 'replayed', true);\n END IF;\n END IF;\n\n SELECT coalesce(sum(coalesce((l ->> 'duration_minutes')::integer, 0)), 0)\n INTO v_minutes FROM jsonb_array_elements(coalesce(p_lines, '[]'::jsonb)) l;\n v_ends := coalesce(p_ends_at, p_starts_at + (greatest(v_minutes, 30) || ' minutes')::interval);\n\n -- The core's door, not a direct write. One statement, and the lines come with\n -- it: there is no window in which the Venda exists without them.\n v_order := public.order_create(\n p_kind => p_kind,\n p_lines => coalesce(p_lines, '[]'::jsonb),\n p_party_id => p_party_id,\n p_unit_id => p_unit_id,\n p_status => 'scheduled',\n p_assignee_id => p_assignee_id,\n p_notes => p_notes,\n p_metadata => coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('source', 'agenda'),\n p_idempotency_key => p_idempotency_key);\n\n INSERT INTO public.appointments (tenant_id, unit_id, kind, party_id, assignee_id, location_id,\n order_id, starts_at, ends_at, status, notes, metadata)\n VALUES (v_tenant, p_unit_id, p_kind, p_party_id, p_assignee_id, p_location_id,\n v_order, p_starts_at, v_ends, 'scheduled', p_notes,\n coalesce(p_metadata, '{}'::jsonb) || jsonb_build_object('source', 'agenda')\n || CASE WHEN p_idempotency_key IS NULL THEN '{}'::jsonb\n ELSE jsonb_build_object('idempotencyKey', p_idempotency_key) END)\n RETURNING id INTO v_booking;\n\n -- The agenda's own per-line columns (001 added them to the line table): who\n -- performs it and how long it takes.\n FOR v_line IN SELECT * FROM jsonb_array_elements(coalesce(p_lines, '[]'::jsonb)) LOOP\n UPDATE public.items oi\n SET duration_minutes = nullif(v_line ->> 'duration_minutes', '')::integer,\n assignee_id = coalesce(nullif(v_line ->> 'assignee_id', '')::uuid, p_assignee_id)\n WHERE oi.order_id = v_order\n AND oi.product_id IS NOT DISTINCT FROM nullif(v_line ->> 'service_id', '')::uuid\n AND oi.name = coalesce(nullif(btrim(coalesce(v_line ->> 'name', '')), ''), 'Item');\n END LOOP;\n\n RETURN jsonb_build_object('appointment_id', v_booking, 'order_id', v_order, 'replayed', false);\nEND $$;\n\nCREATE FUNCTION public.agenda_booking_invoice(p_appointment_id uuid, p_installments integer DEFAULT 1, p_due_date date DEFAULT NULL::date) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_order uuid;\nBEGIN\n SELECT a.order_id INTO v_order FROM public.appointments a\n WHERE a.id = p_appointment_id AND a.tenant_id = v_tenant;\n IF v_order IS NULL THEN\n RAISE EXCEPTION 'agenda_booking_invoice: appointment % has no Venda to bill', p_appointment_id\n USING ERRCODE = 'P0002',\n HINT = 'A booking created through agenda_booking_create always carries one; v_appointments_sem_order lists the rest.';\n END IF;\n\n IF to_regprocedure('public.fn_invoice_from_order(uuid, date, text, integer, text)') IS NULL THEN\n RAISE EXCEPTION 'agenda_booking_invoice: the financial plugin is not installed' USING ERRCODE = '0A000';\n END IF;\n\n PERFORM public.fn_invoice_from_order(v_order, p_due_date, 'invoiced', greatest(coalesce(p_installments, 1), 1), 'credit');\n RETURN jsonb_build_object('order_id', v_order, 'appointment_id', p_appointment_id);\nEND $$;\n\nCREATE FUNCTION public.agenda_booking_update(p_appointment_id uuid, p_starts_at timestamp with time zone DEFAULT NULL::timestamp with time zone, p_ends_at timestamp with time zone DEFAULT NULL::timestamp with time zone, p_status text DEFAULT NULL::text, p_party_id uuid DEFAULT NULL::uuid, p_assignee_id uuid DEFAULT NULL::uuid, p_location_id uuid DEFAULT NULL::uuid, p_notes text DEFAULT NULL::text, p_metadata jsonb DEFAULT NULL::jsonb, p_lines jsonb DEFAULT NULL::jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_appt public.appointments%ROWTYPE;\n v_line jsonb;\n v_n integer := 0;\n v_sub numeric := 0;\n v_qty numeric;\n v_price numeric;\nBEGIN\n SELECT * INTO v_appt FROM public.appointments a WHERE a.id = p_appointment_id AND a.tenant_id = v_tenant;\n IF v_appt.id IS NULL THEN\n RAISE EXCEPTION 'agenda_booking_update: appointment % not found', p_appointment_id USING ERRCODE = 'P0002';\n END IF;\n IF NOT (select app.has_permission('agenda.edit', v_appt.unit_id)) THEN\n RAISE EXCEPTION 'agenda_booking_update: agenda.edit is required' USING ERRCODE = '42501';\n END IF;\n\n UPDATE public.appointments SET\n starts_at = coalesce(p_starts_at, starts_at),\n ends_at = coalesce(p_ends_at, ends_at),\n status = coalesce(p_status, status),\n party_id = coalesce(p_party_id, party_id),\n assignee_id = coalesce(p_assignee_id, assignee_id),\n location_id = coalesce(p_location_id, location_id),\n notes = coalesce(p_notes, notes),\n metadata = coalesce(metadata, '{}'::jsonb) || coalesce(p_metadata, '{}'::jsonb)\n WHERE id = p_appointment_id;\n\n IF v_appt.order_id IS NOT NULL THEN\n UPDATE public.orders SET\n party_id = coalesce(p_party_id, party_id),\n assignee_id = coalesce(p_assignee_id, assignee_id),\n location_id = coalesce(p_location_id, location_id),\n notes = coalesce(p_notes, notes)\n WHERE id = v_appt.order_id;\n\n IF p_lines IS NOT NULL THEN\n -- Replacing the lines and the header total in the SAME statement pair is\n -- the point: a total that disagrees with its lines is what two browser\n -- calls left behind whenever the second one did not land.\n DELETE FROM public.items WHERE order_id = v_appt.order_id;\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_n := v_n + 1;\n v_qty := coalesce((v_line ->> 'quantity')::numeric, 1);\n v_price := round(coalesce((v_line ->> 'unit_price')::numeric, 0), 2);\n INSERT INTO public.items (order_id, product_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_appt.order_id, nullif(v_line ->> 'service_id', '')::uuid,\n coalesce(nullif(btrim(coalesce(v_line ->> 'name', '')), ''), 'Item'),\n v_qty, v_price, round(v_qty * v_price, 2),\n coalesce((v_line ->> 'sort_order')::integer, v_n - 1),\n nullif(v_line ->> 'duration_minutes', '')::integer,\n coalesce(nullif(v_line ->> 'assignee_id', '')::uuid, p_assignee_id, v_appt.assignee_id));\n v_sub := v_sub + round(v_qty * v_price, 2);\n END LOOP;\n UPDATE public.orders SET subtotal = v_sub, total = v_sub WHERE id = v_appt.order_id;\n END IF;\n END IF;\n\n RETURN jsonb_build_object('appointment_id', p_appointment_id, 'order_id', v_appt.order_id);\nEND $$;\n\nCREATE FUNCTION public.agenda_working_windows(p_tenant_id uuid, p_date date, p_assignee_id uuid DEFAULT NULL::uuid) RETURNS TABLE(assignee_id uuid, win_start time without time zone, win_end time without time zone)\n LANGUAGE sql STABLE\n SET search_path TO 'public'\n AS $$\n WITH exc AS (\n -- Every specific-date row for the date, ACTIVE OR NOT: the inactive day-off\n -- sentinel must still suppress the weekly rows below.\n SELECT sc.assignee_id, sc.starts_at, sc.ends_at, sc.is_active\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.specific_date = p_date\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n )\n SELECT e.assignee_id, e.starts_at, e.ends_at\n FROM exc e\n WHERE e.is_active\n UNION ALL\n SELECT sc.assignee_id, sc.starts_at, sc.ends_at\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND sc.specific_date IS NULL\n AND sc.day_of_week = EXTRACT(dow FROM p_date)::smallint\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND NOT EXISTS (SELECT 1 FROM exc e WHERE e.assignee_id = sc.assignee_id)\n$$;\n\nCREATE FUNCTION public.agent_agenda_create_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $_$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_client_id uuid;\n v_service_id uuid;\n v_professional uuid;\n v_starts timestamptz;\n v_starts_raw text;\n v_notes text;\n v_service record;\n v_client record;\n v_ends timestamptz;\n v_tz text;\n v_order uuid;\n v_booking uuid;\nBEGIN\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown tenant');\n END IF;\n\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_client_id := (p_payload->>'client_id')::uuid;\n v_service_id := (p_payload->>'service_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts_raw := p_payload->>'starts_at';\n IF v_starts_raw ~ '(Z|[+-][0-9]{2}:?[0-9]{2})$' THEN\n v_starts := v_starts_raw::timestamptz; -- explicit offset\n ELSE\n v_starts := (v_starts_raw::timestamp) AT TIME ZONE v_tz; -- tenant-local\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_notes := left(p_payload->>'notes', 500);\n IF v_client_id IS NULL OR v_service_id IS NULL OR v_starts IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'client_id, service_id and starts_at are required');\n END IF;\n IF v_starts <= now() OR v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be in the future (max 1 year)');\n END IF;\n\n -- ── authorization: role → plan → bookings_month cap ──────────────────────\n SELECT count(*) INTO v_used FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.created_at >= date_trunc('month', now());\n v_denial := agent_guard(p_tenant_id, p_actor_user_id,\n 'appointments', 'create', 'bookings_month', v_used, 1);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- ── invariants ───────────────────────────────────────────────────────────\n SELECT p.id, p.name INTO v_client\n FROM people p\n WHERE p.id = v_client_id AND p.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown client for this tenant');\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = v_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown or inactive service');\n END IF;\n\n v_ends := v_starts + make_interval(mins => v_service.duration_minutes);\n\n -- exception-aware windows (007); still prefer a professional who is FREE at\n -- the slot when the user did not name one\n SELECT w.assignee_id INTO v_professional\n FROM agenda_working_windows(\n p_tenant_id, (v_starts AT TIME ZONE v_tz)::date, v_professional) w\n WHERE (v_starts AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n AND NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = w.assignee_id\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n )\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_professional IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'no professional is available at that slot (outside working hours or already booked). Suggest a different time. Times are tenant-local, tz ' || v_tz);\n END IF;\n\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error', 'slot no longer available');\n END IF;\n\n -- ── write + audit ────────────────────────────────────────────────────────\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_client_id, v_professional,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_client_id, v_professional, v_order,\n v_starts, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'agent', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_professional);\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.createAppointment', 'appointment', v_booking::text,\n jsonb_build_object('payload', p_payload, 'order_id', v_order));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_booking,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_booking, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_starts,\n 'ends_at', v_ends,\n 'starts_at_local', to_char(v_starts AT TIME ZONE v_tz, 'YYYY-MM-DD (Dy) HH24:MI') || ' ' || v_tz,\n 'ends_at_local', to_char(v_ends AT TIME ZONE v_tz, 'HH24:MI'),\n 'client_name', v_client.name,\n 'service_name', v_service.name,\n 'price', v_service.price,\n 'status', 'scheduled'\n )\n );\nEND;\n$_$;\n\nCREATE FUNCTION public.agent_agenda_update_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $_$\nDECLARE\n v_denial jsonb;\n v_id uuid;\n v_tz text;\n v_row record;\n v_starts_raw text;\n v_starts timestamptz;\n v_ends timestamptz;\n v_duration int;\n v_professional uuid;\n v_status text;\n v_notes text;\n v_wants_move boolean;\n v_wants_status boolean;\nBEGIN\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown tenant');\n END IF;\n\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_id := (p_payload->>'appointment_id')::uuid;\n v_professional := (p_payload->>'professional_id')::uuid;\n v_starts_raw := p_payload->>'starts_at';\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid payload: ' || SQLERRM);\n END;\n v_status := nullif(trim(lower(p_payload->>'status')), '');\n v_notes := left(p_payload->>'notes', 500);\n v_wants_move := v_starts_raw IS NOT NULL OR v_professional IS NOT NULL;\n v_wants_status := v_status IS NOT NULL;\n\n IF v_id IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'appointment_id is required — search the agenda first and reuse the id of the appointment to change');\n END IF;\n IF NOT v_wants_move AND NOT v_wants_status AND v_notes IS NULL THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'nothing to change: send starts_at, professional_id, status or notes');\n END IF;\n IF v_status IS NOT NULL\n AND v_status NOT IN ('scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show') THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'status must be one of scheduled, confirmed, in_progress, completed, cancelled, no_show');\n END IF;\n\n -- ── the appointment must exist, in THIS tenant ───────────────────────────\n SELECT b.id, b.starts_at, b.ends_at, b.assignee_id, b.status, b.party_id, b.order_id\n INTO v_row\n FROM appointments b\n WHERE b.id = v_id AND b.tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown appointment for this tenant');\n END IF;\n\n -- ── authorization: role → plan. No cap: editing frees nothing and buys\n -- nothing, so charging bookings_month for a reschedule would be wrong.\n v_denial := agent_guard(p_tenant_id, p_actor_user_id, 'appointments', 'edit');\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n -- Duration is preserved across a move — a 60-minute appointment stays 60.\n v_duration := GREATEST(\n COALESCE(EXTRACT(EPOCH FROM (v_row.ends_at - v_row.starts_at)) / 60, 30)::int, 5);\n v_professional := COALESCE(v_professional, v_row.assignee_id);\n\n IF v_wants_move THEN\n IF v_starts_raw IS NOT NULL THEN\n BEGIN\n IF v_starts_raw ~ '(Z|[+-][0-9]{2}:?[0-9]{2})$' THEN\n v_starts := v_starts_raw::timestamptz; -- explicit offset\n ELSE\n v_starts := (v_starts_raw::timestamp) AT TIME ZONE v_tz; -- tenant-local\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid starts_at: ' || SQLERRM);\n END;\n ELSE\n v_starts := v_row.starts_at;\n END IF;\n v_ends := v_starts + make_interval(mins => v_duration);\n\n IF v_starts > now() + interval '365 days' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'starts_at must be within the next year');\n END IF;\n\n -- Working window (exception-aware, 007) for the target professional.\n IF NOT EXISTS (\n SELECT 1\n FROM agenda_working_windows(\n p_tenant_id, (v_starts AT TIME ZONE v_tz)::date, v_professional) w\n WHERE w.assignee_id = v_professional\n AND (v_starts AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'that slot is outside the professional''s working hours. Suggest a different time. Times are tenant-local, tz ' || v_tz);\n END IF;\n\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_professional::text, 0));\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_professional\n AND b.id <> v_id -- never conflicts with itself\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > v_starts\n ) THEN\n RETURN jsonb_build_object('ok', false, 'error',\n 'that slot is already taken. Suggest a different time.');\n END IF;\n END IF;\n\n -- ── write + audit ────────────────────────────────────────────────────────\n UPDATE appointments b SET\n starts_at = COALESCE(v_starts, b.starts_at),\n ends_at = COALESCE(v_ends, b.ends_at),\n assignee_id = v_professional,\n status = COALESCE(v_status, b.status),\n notes = COALESCE(v_notes, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || jsonb_build_object('lastAgentEdit', now()),\n updated_at = now()\n WHERE b.id = v_id AND b.tenant_id = p_tenant_id;\n\n -- The order mirrors the appointment's assignee/status so the financial side\n -- does not drift from the calendar.\n IF v_row.order_id IS NOT NULL THEN\n UPDATE orders o SET\n assignee_id = v_professional,\n status = CASE WHEN v_status = 'cancelled' THEN 'cancelled' ELSE o.status END,\n updated_at = now()\n WHERE o.id = v_row.order_id AND o.tenant_id = p_tenant_id;\n END IF;\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id, 'agent.updateAppointment', 'appointment', v_id::text,\n jsonb_build_object('payload', p_payload,\n 'previous', jsonb_build_object(\n 'starts_at', v_row.starts_at,\n 'ends_at', v_row.ends_at,\n 'assignee_id', v_row.assignee_id,\n 'status', v_row.status)));\n\n SELECT a.id, a.starts_at, a.ends_at, a.status, a.client_name, a.professional_name\n INTO v_row\n FROM v_appointments a WHERE a.id = v_id;\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_id,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_id, 'resource', 'appointments',\n 'archetype', 'schedule:appointment'),\n 'starts_at', v_row.starts_at,\n 'ends_at', v_row.ends_at,\n 'starts_at_local', to_char(v_row.starts_at AT TIME ZONE v_tz, 'YYYY-MM-DD (Dy) HH24:MI') || ' ' || v_tz,\n 'ends_at_local', to_char(v_row.ends_at AT TIME ZONE v_tz, 'HH24:MI'),\n 'client_name', v_row.client_name,\n 'professional_name', v_row.professional_name,\n 'status', v_row.status\n )\n );\nEND;\n$_$;\n\nCREATE FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text DEFAULT NULL::text, p_notes text DEFAULT NULL::text, p_assignee_id uuid DEFAULT NULL::uuid) RETURNS TABLE(booking_id uuid, starts_at timestamp with time zone, ends_at timestamp with time zone)\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $_$\nDECLARE\n v_service record;\n v_person_id uuid;\n v_assignee uuid;\n v_requested uuid;\n v_ends timestamptz;\n v_order uuid;\n v_booking uuid;\n v_phone text;\n v_tz text;\n v_notes text;\n v_client_kind text;\nBEGIN\n -- validation: anon-callable, everything tight\n IF p_name IS NULL OR length(trim(p_name)) NOT BETWEEN 2 AND 120 THEN\n RAISE EXCEPTION 'invalid name';\n END IF;\n v_phone := regexp_replace(COALESCE(p_phone, ''), '\\\\D', '', 'g');\n IF length(v_phone) NOT BETWEEN 8 AND 15 THEN\n RAISE EXCEPTION 'invalid phone';\n END IF;\n IF p_email IS NOT NULL AND (length(p_email) > 254 OR p_email !~ '^[^@\\\\s]+@[^@\\\\s]+\\\\.[^@\\\\s]+$') THEN\n RAISE EXCEPTION 'invalid email';\n END IF;\n v_notes := left(p_notes, 500);\n IF p_starts_at IS NULL OR p_starts_at <= now() OR p_starts_at > now() + interval '90 days' THEN\n RAISE EXCEPTION 'invalid start';\n END IF;\n\n SELECT s.id, s.name, s.price, COALESCE(s.duration_minutes, 30) AS duration_minutes\n INTO v_service\n FROM services s\n WHERE s.id = p_service_id AND s.tenant_id = p_tenant_id\n AND s.is_active AND s.status = 'active';\n IF NOT FOUND THEN RAISE EXCEPTION 'unknown service'; END IF;\n -- …and it must be a PUBLIC service, not merely an existing one. A service\n -- released to particular units is not a tenant-wide offering, and this path has\n -- no unit to honour the release in; without this an id from a cached page still\n -- booked what the catalog no longer lists (#201).\n PERFORM public.agenda_assert_service_is_public(p_tenant_id, p_service_id);\n\n v_ends := p_starts_at + make_interval(mins => v_service.duration_minutes);\n\n -- tenant config: timezone + client kind (admin-set; sanitized, never caller input)\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo'),\n COALESCE(NULLIF(trim(t.settings->'booking'->>'client_kind'), ''), 'customer')\n INTO v_tz, v_client_kind\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RAISE EXCEPTION 'unknown tenant'; END IF;\n IF v_client_kind !~ '^[a-z_]{2,32}$' THEN v_client_kind := 'customer'; END IF;\n\n -- resolve the professional, in order of trust:\n -- 1. the id the caller sent (the one the visitor actually saw)\n -- 2. the tenant's configured default (settings->>'defaultAssigneeId')\n -- 3. whoever's working hours cover the slot\n --\n -- Step 2 is why this migration exists. Older published clients call this with\n -- 7 named args, leaving p_assignee_id NULL, and step 3 then resolved to\n -- \"lowest assignee UUID\" — an arbitrary instructor who had nothing to do with\n -- the name the site displayed on the confirmation screen. The default gives\n -- those clients a correct answer without waiting for a redeploy.\n v_requested := COALESCE(\n p_assignee_id,\n (SELECT NULLIF(t.settings ->> 'defaultAssigneeId', '')::uuid\n FROM tenants t WHERE t.id = p_tenant_id)\n );\n\n SELECT w.assignee_id INTO v_assignee\n FROM agenda_working_windows(\n p_tenant_id, (p_starts_at AT TIME ZONE v_tz)::date, v_requested) w\n WHERE (p_starts_at AT TIME ZONE v_tz)::time >= w.win_start\n AND (v_ends AT TIME ZONE v_tz)::time <= w.win_end\n ORDER BY w.assignee_id\n LIMIT 1;\n IF v_assignee IS NULL THEN RAISE EXCEPTION 'slot outside working hours'; END IF;\n\n -- serialize per (tenant, assignee) to kill the double-book race\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || v_assignee::text, 0));\n\n IF EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.assignee_id = v_assignee\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < v_ends\n AND COALESCE(b.ends_at, b.starts_at) > p_starts_at\n ) THEN\n RAISE EXCEPTION 'slot no longer available';\n END IF;\n\n -- anti-spam: cap open future public bookings per phone per tenant\n IF (\n SELECT count(*) FROM appointments b\n JOIN people p ON p.id = b.party_id\n WHERE b.tenant_id = p_tenant_id\n AND p.phone = v_phone\n AND b.starts_at > now()\n AND b.status = 'scheduled'\n ) >= 3 THEN\n RAISE EXCEPTION 'too many open bookings for this phone';\n END IF;\n\n -- upsert the client by (tenant, kind, phone), serialized by advisory lock\n -- (kind is tenant-configured, so the customer-only partial index can't\n -- arbitrate)\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || v_phone, 1));\n\n SELECT p.id INTO v_person_id\n FROM people p\n WHERE p.tenant_id = p_tenant_id AND p.kind = v_client_kind AND p.phone = v_phone\n ORDER BY p.created_at\n LIMIT 1;\n\n IF v_person_id IS NOT NULL THEN\n UPDATE people SET\n name = trim(p_name),\n email = COALESCE(p_email, people.email),\n updated_at = now()\n WHERE id = v_person_id;\n ELSE\n INSERT INTO people (tenant_id, kind, name, phone, email, metadata)\n VALUES (p_tenant_id, v_client_kind, trim(p_name), v_phone, p_email,\n jsonb_build_object('source', 'public_booking'))\n RETURNING id INTO v_person_id;\n END IF;\n\n -- order + booking + order_item (statuses hardcoded — caller cannot set)\n INSERT INTO orders (tenant_id, kind, status, party_id, assignee_id, subtotal, total, notes, metadata)\n VALUES (p_tenant_id, 'appointment', 'scheduled', v_person_id, v_assignee,\n v_service.price, v_service.price, v_notes,\n jsonb_build_object('source', 'public_booking',\n 'serviceNames', v_service.name,\n 'contactName', trim(p_name)))\n RETURNING id INTO v_order;\n\n INSERT INTO appointments (tenant_id, kind, party_id, assignee_id, order_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, 'appointment', v_person_id, v_assignee, v_order,\n p_starts_at, v_ends, 'scheduled', v_notes,\n jsonb_build_object('source', 'public_booking', 'serviceNames', v_service.name))\n RETURNING id INTO v_booking;\n\n INSERT INTO items (order_id, service_id, name, quantity, unit_price, total,\n sort_order, duration_minutes, assignee_id)\n VALUES (v_order, v_service.id, v_service.name, 1, v_service.price, v_service.price,\n 0, v_service.duration_minutes, v_assignee);\n\n RETURN QUERY SELECT v_booking, p_starts_at, v_ends;\nEND;\n$_$;\n\nCREATE FUNCTION public.get_available_slots(p_tenant_id uuid, p_date date, p_duration_minutes integer, p_assignee_id uuid DEFAULT NULL::uuid, p_slot_interval integer DEFAULT 30) RETURNS TABLE(slot_start timestamp with time zone, slot_end timestamp with time zone)\n LANGUAGE plpgsql STABLE SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_tz text;\nBEGIN\n -- tight validation: this function is anon-callable\n IF p_duration_minutes IS NULL OR p_duration_minutes NOT BETWEEN 5 AND 480 THEN\n RAISE EXCEPTION 'invalid duration';\n END IF;\n IF p_slot_interval IS NULL OR p_slot_interval NOT BETWEEN 5 AND 240 THEN\n RAISE EXCEPTION 'invalid interval';\n END IF;\n IF p_date IS NULL OR p_date < current_date OR p_date > current_date + 90 THEN\n RETURN;\n END IF;\n\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RETURN; END IF; -- unknown tenant → empty, not an error\n\n RETURN QUERY\n WITH day_schedules AS (\n SELECT w.assignee_id, w.win_start, w.win_end\n FROM agenda_working_windows(p_tenant_id, p_date, p_assignee_id) w\n ),\n candidate AS (\n SELECT\n ds.assignee_id,\n gs AS s_start,\n gs + make_interval(mins => p_duration_minutes) AS s_end\n FROM day_schedules ds\n CROSS JOIN LATERAL generate_series(\n (p_date + ds.win_start) AT TIME ZONE v_tz,\n ((p_date + ds.win_end) AT TIME ZONE v_tz) - make_interval(mins => p_duration_minutes),\n make_interval(mins => p_slot_interval)\n ) AS gs\n )\n SELECT DISTINCT c.s_start, c.s_end\n FROM candidate c\n WHERE NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n -- SMART SYNC (gcal 002): this professional's own bookings OR any\n -- tenant-wide BLOCK (assignee_id IS NULL AND kind='block') busy the slot.\n AND (b.assignee_id = c.assignee_id\n OR (b.assignee_id IS NULL AND b.kind = 'block'))\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < c.s_end\n AND COALESCE(b.ends_at, b.starts_at) > c.s_start\n )\n ORDER BY 1;\nEND;\n$$;\n\nCREATE FUNCTION public.plg_booking_apply_channel_reply(p_booking_id uuid, p_action text, p_expect_tenant_id uuid DEFAULT NULL::uuid) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_action text := nullif(trim(lower(p_action)), '');\n v_target text;\n v_row record;\n v_tz text;\n v_starts timestamptz;\n v_event text;\n v_payload jsonb;\nBEGIN\n IF v_action IS NULL OR v_action NOT IN ('confirm', 'cancel') THEN\n RETURN jsonb_build_object('result', 'not_allowed', 'reason', 'unknown_action');\n END IF;\n IF p_booking_id IS NULL THEN\n RETURN jsonb_build_object('result', 'not_found', 'reason', 'no_booking_id');\n END IF;\n\n v_target := CASE WHEN v_action = 'confirm' THEN 'confirmed' ELSE 'cancelled' END;\n\n -- FOR UPDATE, because two deliveries of the same tap race each other and the\n -- loser must read the state the winner wrote, not the state both started from.\n SELECT b.id, b.tenant_id, b.status, b.starts_at\n INTO v_row\n FROM public.appointments b\n WHERE b.id = p_booking_id\n FOR UPDATE;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('result', 'not_found', 'booking_id', p_booking_id);\n END IF;\n\n IF p_expect_tenant_id IS NOT NULL AND v_row.tenant_id <> p_expect_tenant_id THEN\n RETURN jsonb_build_object('result', 'not_found', 'booking_id', p_booking_id);\n END IF;\n\n -- Already there. The answer is the outcome, not an error: the customer sees\n -- \"confirmado\" either way, and a webhook that 500s on a duplicate is a\n -- webhook Tyxter retries eight times over a day and a half.\n IF v_row.status = v_target THEN\n RETURN jsonb_build_object(\n 'result', v_target, 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n -- Confirming is only meaningful from the two states that mean \"not settled\n -- yet\". 'pending' is the table's own DEFAULT and 'scheduled' is what every\n -- write path sets, so both are live appointments awaiting the customer.\n -- Confirming a completed or cancelled one would rewrite history.\n IF v_action = 'confirm' AND v_row.status NOT IN ('pending', 'scheduled') THEN\n RETURN jsonb_build_object(\n 'result', 'not_allowed', 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n -- Cancelling is allowed from anything that has not already ENDED. A confirmed\n -- appointment can still be cancelled — that is the ordinary case — but one\n -- already cancelled or already completed cannot.\n IF v_action = 'cancel' AND v_row.status IN ('cancelled', 'completed') THEN\n RETURN jsonb_build_object(\n 'result', 'not_allowed', 'changed', false,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id, 'status', v_row.status);\n END IF;\n\n UPDATE public.appointments\n SET status = v_target, updated_at = now()\n WHERE id = v_row.id;\n\n -- ── the fact ──────────────────────────────────────────────────────────────\n -- Emitted HERE and not by the caller. The write happened in the database, so\n -- the browser emitter never sees it (packages/db/migrations/027 is the whole\n -- argument), and a webhook that updated the row and then failed to post the\n -- event would leave a confirmed appointment nobody was told about.\n --\n -- The payload is BOOKING_FIELDS from plugin-agenda's message-events.ts, field\n -- for field, so an automation reacting to a WhatsApp confirmation renders the\n -- same message as one reacting to a confirmation made in the app.\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM public.tenants t WHERE t.id = v_row.tenant_id;\n v_tz := COALESCE(v_tz, 'America/Sao_Paulo');\n v_starts := v_row.starts_at;\n\n SELECT jsonb_build_object(\n 'customer_name', COALESCE(a.client_name, ''),\n 'service_name', COALESCE((\n SELECT string_agg(s->>'name', ' + ')\n FROM jsonb_array_elements(COALESCE(a.services::jsonb, '[]'::jsonb)) AS s), ''),\n 'professional_name', COALESCE(a.professional_name, ''),\n 'booking_date', to_char(v_starts AT TIME ZONE v_tz, 'DD/MM/YYYY'),\n 'booking_time', to_char(v_starts AT TIME ZONE v_tz, 'HH24:MI'),\n 'location_name', COALESCE(a.location_name, ''),\n 'customer_phone', COALESCE(a.client_phone, ''),\n 'source', 'channel_reply')\n INTO v_payload\n FROM public.v_appointments a\n WHERE a.id = v_row.id;\n\n v_event := CASE WHEN v_action = 'confirm'\n THEN 'agenda.booking_confirmed'\n ELSE 'agenda.booking_cancelled' END;\n\n PERFORM public.plg_emit_event(\n v_event,\n COALESCE(v_payload, '{}'::jsonb),\n 'booking',\n v_row.id::text,\n v_row.tenant_id,\n NULL);\n\n RETURN jsonb_build_object(\n 'result', v_target, 'changed', true, 'event_key', v_event,\n 'booking_id', v_row.id, 'tenant_id', v_row.tenant_id,\n 'status', v_target, 'previous_status', v_row.status);\nEND;\n$$;\n\n\n-- ── view ────────────────────────────────────────────────────────────────\n\nCREATE VIEW public.v_appointments WITH (security_invoker='true') AS\n SELECT b.id,\n b.tenant_id,\n b.kind,\n b.starts_at,\n b.ends_at,\n b.status,\n b.notes,\n b.order_id,\n b.location_id,\n b.metadata,\n b.created_at,\n b.updated_at,\n b.party_id AS client_id,\n COALESCE(pc.name, (b.metadata ->> 'title'::text)) AS client_name,\n pc.phone AS client_phone,\n pc.email AS client_email,\n pc.avatar_url AS client_avatar_url,\n b.assignee_id AS professional_id,\n ps.name AS professional_name,\n ps.avatar_url AS professional_avatar_url,\n l.name AS location_name,\n o.total AS order_total,\n o.status AS order_status,\n ((EXTRACT(epoch FROM (COALESCE(b.ends_at, b.starts_at) - b.starts_at)))::integer / 60) AS total_duration_minutes,\n o.reference_number,\n o.status AS stage,\n (o.metadata ->> 'direction'::text) AS direction,\n ( SELECT json_agg(json_build_object('id', oi.id, 'serviceId', oi.product_id, 'name', oi.name, 'durationMinutes', oi.duration_minutes, 'price', oi.unit_price, 'assigneeId', oi.assignee_id) ORDER BY oi.sort_order) AS json_agg\n FROM public.items oi\n WHERE (oi.order_id = b.order_id)) AS services,\n inv.status AS payment_status,\n inv.paid AS order_paid,\n inv.balance AS order_balance\n FROM (((((public.appointments b\n LEFT JOIN public.people pc ON ((pc.id = b.party_id)))\n LEFT JOIN public.people ps ON ((ps.id = b.assignee_id)))\n LEFT JOIN public.locations l ON ((l.id = b.location_id)))\n LEFT JOIN public.orders o ON ((o.id = b.order_id)))\n LEFT JOIN public.v_invoice_balances inv ON ((inv.invoice_id = b.order_id)));\n\nCREATE VIEW public.rep_appointments_by_period WITH (security_invoker='true') AS\n SELECT tenant_id,\n id AS booking_id,\n (starts_at)::date AS date,\n starts_at,\n client_id,\n client_name,\n professional_id,\n professional_name,\n COALESCE(((services -> 0) ->> 'name'::text), ((services -> 0) ->> 'serviceName'::text)) AS service_name,\n status,\n order_total AS revenue,\n created_at,\n updated_at\n FROM public.v_appointments b;\n\nCREATE VIEW public.plg_agenda_rep_bookings WITH (security_invoker='true') AS\n SELECT tenant_id,\n booking_id,\n date,\n starts_at,\n client_id,\n client_name,\n professional_id,\n professional_name,\n service_name,\n status,\n revenue AS booked_revenue,\n CASE\n WHEN (status = ANY (ARRAY['cancelled'::text, 'no_show'::text])) THEN (0)::numeric\n ELSE COALESCE(revenue, (0)::numeric)\n END AS effective_revenue,\n CASE\n WHEN (status = ANY (ARRAY['cancelled'::text, 'no_show'::text])) THEN COALESCE(revenue, (0)::numeric)\n ELSE (0)::numeric\n END AS lost_revenue,\n CASE\n WHEN (status = 'completed'::text) THEN 1\n ELSE 0\n END AS is_completed,\n CASE\n WHEN (status = 'cancelled'::text) THEN 1\n ELSE 0\n END AS is_cancelled,\n CASE\n WHEN (status = 'no_show'::text) THEN 1\n ELSE 0\n END AS is_no_show,\n created_at,\n updated_at\n FROM public.rep_appointments_by_period b;\n\nCREATE VIEW public.rep_confirmation_queue WITH (security_invoker='true') AS\n SELECT tenant_id,\n id AS booking_id,\n (starts_at)::date AS date,\n starts_at,\n client_id,\n client_name,\n professional_id,\n professional_name,\n COALESCE(((services -> 0) ->> 'name'::text), ((services -> 0) ->> 'serviceName'::text)) AS service_name,\n 'pending'::text AS confirmation_status,\n NULL::text AS confirmation_channel,\n NULL::timestamp with time zone AS confirmation_sent_at,\n NULL::timestamp with time zone AS confirmed_at,\n created_at,\n updated_at\n FROM public.v_appointments b\n WHERE ((status <> ALL (ARRAY['cancelled'::text, 'no_show'::text])) AND (starts_at >= (now() - '1 day'::interval)));\n\nCREATE VIEW public.rep_revenue_by_professional WITH (security_invoker='true') AS\n SELECT tenant_id,\n (starts_at)::date AS date,\n professional_id,\n COALESCE(professional_name, 'Sem profissional'::text) AS professional_name,\n (count(*))::integer AS appointment_count,\n (COALESCE(sum(NULLIF(order_total, (0)::numeric)), (0)::numeric))::numeric(14,2) AS total_revenue,\n (COALESCE(avg(NULLIF(order_total, (0)::numeric)), (0)::numeric))::numeric(14,2) AS avg_ticket,\n (0)::numeric(14,2) AS commission,\n max(updated_at) AS updated_at\n FROM public.v_appointments b\n WHERE (status <> ALL (ARRAY['cancelled'::text, 'no_show'::text]))\n GROUP BY tenant_id, ((starts_at)::date), professional_id, COALESCE(professional_name, 'Sem profissional'::text);\n\nCREATE VIEW public.rep_revenue_by_service WITH (security_invoker='true') AS\n SELECT b.tenant_id,\n (b.starts_at)::date AS date,\n NULLIF((service_item.value ->> 'serviceId'::text), ''::text) AS service_id,\n COALESCE((service_item.value ->> 'name'::text), (service_item.value ->> 'serviceName'::text), 'Sem servico'::text) AS service_name,\n (count(DISTINCT b.id))::integer AS quantity,\n (COALESCE(sum((NULLIF((service_item.value ->> 'price'::text), ''::text))::numeric), (0)::numeric))::numeric(14,2) AS total_revenue,\n (COALESCE(avg((NULLIF((service_item.value ->> 'price'::text), ''::text))::numeric), (0)::numeric))::numeric(14,2) AS avg_ticket,\n max(b.updated_at) AS updated_at\n FROM (public.v_appointments b\n CROSS JOIN LATERAL jsonb_array_elements(COALESCE((b.services)::jsonb, '[]'::jsonb)) service_item(value))\n WHERE (b.status <> ALL (ARRAY['cancelled'::text, 'no_show'::text]))\n GROUP BY b.tenant_id, ((b.starts_at)::date), NULLIF((service_item.value ->> 'serviceId'::text), ''::text), COALESCE((service_item.value ->> 'name'::text), (service_item.value ->> 'serviceName'::text), 'Sem servico'::text);\n\nCREATE VIEW public.v_appointments_sem_order WITH (security_invoker='true') AS\n SELECT id AS appointment_id,\n tenant_id,\n unit_id,\n kind,\n status,\n party_id,\n assignee_id,\n starts_at\n FROM public.appointments a\n WHERE ((order_id IS NULL) AND (status = ANY (ARRAY['completed'::text, 'invoiced'::text, 'paid'::text])));\n\nCREATE VIEW public.v_public_services AS\n SELECT id,\n tenant_id,\n name,\n description,\n price,\n currency,\n COALESCE(duration_minutes, 30) AS duration_minutes,\n image_url,\n COALESCE(((metadata ->> 'sort_order'::text))::integer, 0) AS sort_order\n FROM public.products s\n WHERE ((kind = 'service'::text) AND is_active AND (status = 'active'::text) AND COALESCE(((metadata ->> 'bookableOnline'::text))::boolean, true) AND (NOT (EXISTS ( SELECT 1\n FROM app.resource_grants g\n WHERE ((g.tenant_id = s.tenant_id) AND (g.resource_type = 'catalog.product'::text) AND (g.resource_id = s.id) AND (g.relation = 'available_in'::text))))));\n\n\n-- ── acl ─────────────────────────────────────────────────────────────────\n\nREVOKE ALL ON FUNCTION public.agenda_assert_service_is_public(p_tenant_id uuid, p_service_id uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_assert_service_is_public(p_tenant_id uuid, p_service_id uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agenda_booking_cancel(p_appointment_id uuid, p_hard boolean) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_booking_cancel(p_appointment_id uuid, p_hard boolean) TO authenticated;\nGRANT ALL ON FUNCTION public.agenda_booking_cancel(p_appointment_id uuid, p_hard boolean) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agenda_booking_create(p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_lines jsonb, p_party_id uuid, p_assignee_id uuid, p_unit_id uuid, p_location_id uuid, p_kind text, p_notes text, p_metadata jsonb, p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_booking_create(p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_lines jsonb, p_party_id uuid, p_assignee_id uuid, p_unit_id uuid, p_location_id uuid, p_kind text, p_notes text, p_metadata jsonb, p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.agenda_booking_create(p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_lines jsonb, p_party_id uuid, p_assignee_id uuid, p_unit_id uuid, p_location_id uuid, p_kind text, p_notes text, p_metadata jsonb, p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agenda_booking_invoice(p_appointment_id uuid, p_installments integer, p_due_date date) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_booking_invoice(p_appointment_id uuid, p_installments integer, p_due_date date) TO authenticated;\nGRANT ALL ON FUNCTION public.agenda_booking_invoice(p_appointment_id uuid, p_installments integer, p_due_date date) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agenda_booking_update(p_appointment_id uuid, p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_status text, p_party_id uuid, p_assignee_id uuid, p_location_id uuid, p_notes text, p_metadata jsonb, p_lines jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_booking_update(p_appointment_id uuid, p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_status text, p_party_id uuid, p_assignee_id uuid, p_location_id uuid, p_notes text, p_metadata jsonb, p_lines jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.agenda_booking_update(p_appointment_id uuid, p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_status text, p_party_id uuid, p_assignee_id uuid, p_location_id uuid, p_notes text, p_metadata jsonb, p_lines jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agenda_working_windows(p_tenant_id uuid, p_date date, p_assignee_id uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agenda_working_windows(p_tenant_id uuid, p_date date, p_assignee_id uuid) TO authenticated;\nGRANT ALL ON FUNCTION public.agenda_working_windows(p_tenant_id uuid, p_date date, p_assignee_id uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_create_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agent_agenda_create_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.agent_agenda_create_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.agent_agenda_update_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agent_agenda_update_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.agent_agenda_update_appointment(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text, p_notes text, p_assignee_id uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text, p_notes text, p_assignee_id uuid) TO authenticated;\nGRANT ALL ON FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text, p_notes text, p_assignee_id uuid) TO service_role;\nGRANT ALL ON FUNCTION public.create_public_booking(p_tenant_id uuid, p_service_id uuid, p_starts_at timestamp with time zone, p_name text, p_phone text, p_email text, p_notes text, p_assignee_id uuid) TO anon;\n\nREVOKE ALL ON FUNCTION public.get_available_slots(p_tenant_id uuid, p_date date, p_duration_minutes integer, p_assignee_id uuid, p_slot_interval integer) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.get_available_slots(p_tenant_id uuid, p_date date, p_duration_minutes integer, p_assignee_id uuid, p_slot_interval integer) TO authenticated;\nGRANT ALL ON FUNCTION public.get_available_slots(p_tenant_id uuid, p_date date, p_duration_minutes integer, p_assignee_id uuid, p_slot_interval integer) TO service_role;\nGRANT ALL ON FUNCTION public.get_available_slots(p_tenant_id uuid, p_date date, p_duration_minutes integer, p_assignee_id uuid, p_slot_interval integer) TO anon;\n\nREVOKE ALL ON FUNCTION public.plg_booking_apply_channel_reply(p_booking_id uuid, p_action text, p_expect_tenant_id uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.plg_booking_apply_channel_reply(p_booking_id uuid, p_action text, p_expect_tenant_id uuid) TO service_role;\n\nGRANT MAINTAIN ON TABLE public.v_appointments TO anon;\nGRANT ALL ON TABLE public.v_appointments TO authenticated;\nGRANT ALL ON TABLE public.v_appointments TO service_role;\n\nGRANT MAINTAIN ON TABLE public.rep_appointments_by_period TO anon;\nGRANT ALL ON TABLE public.rep_appointments_by_period TO authenticated;\nGRANT ALL ON TABLE public.rep_appointments_by_period TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_agenda_rep_bookings TO anon;\nGRANT ALL ON TABLE public.plg_agenda_rep_bookings TO authenticated;\nGRANT ALL ON TABLE public.plg_agenda_rep_bookings TO service_role;\n\nGRANT MAINTAIN ON TABLE public.rep_confirmation_queue TO anon;\nGRANT ALL ON TABLE public.rep_confirmation_queue TO authenticated;\nGRANT ALL ON TABLE public.rep_confirmation_queue TO service_role;\n\nGRANT MAINTAIN ON TABLE public.rep_revenue_by_professional TO anon;\nGRANT ALL ON TABLE public.rep_revenue_by_professional TO authenticated;\nGRANT ALL ON TABLE public.rep_revenue_by_professional TO service_role;\n\nGRANT MAINTAIN ON TABLE public.rep_revenue_by_service TO anon;\nGRANT ALL ON TABLE public.rep_revenue_by_service TO authenticated;\nGRANT ALL ON TABLE public.rep_revenue_by_service TO service_role;\n\nGRANT MAINTAIN ON TABLE public.v_appointments_sem_order TO anon;\nGRANT ALL ON TABLE public.v_appointments_sem_order TO authenticated;\nGRANT ALL ON TABLE public.v_appointments_sem_order TO service_role;\n\nGRANT SELECT,MAINTAIN ON TABLE public.v_public_services TO anon;\nGRANT ALL ON TABLE public.v_public_services TO authenticated;\nGRANT ALL ON TABLE public.v_public_services TO service_role;\n\n\n-- ── comment ─────────────────────────────────────────────────────────────\n\nCOMMENT ON FUNCTION public.agenda_booking_create(p_starts_at timestamp with time zone, p_ends_at timestamp with time zone, p_lines jsonb, p_party_id uuid, p_assignee_id uuid, p_unit_id uuid, p_location_id uuid, p_kind text, p_notes text, p_metadata jsonb, p_idempotency_key text) IS 'A booking, its Venda and its lines in one transaction (PRD 06). Replaces the three browser calls createBooking used to make — closing the tab between them is what left an order nobody could find.';\n\nCOMMENT ON FUNCTION public.agenda_booking_invoice(p_appointment_id uuid, p_installments integer, p_due_date date) IS 'Bill a booking in one call (PRD 06). The bridge used to read the order in the browser and then call the invoice RPC; here the lookup and the promotion are one transaction.';\n\nCOMMENT ON VIEW public.v_appointments_sem_order IS 'Appointments that reached a billable state with no Venda behind them (PRD 06). An unbilled appointment is legitimate; a COMPLETED one with nothing commercial attached is the 72% hole the V1 has, arriving early enough to stop.';\n\nCOMMENT ON VIEW public.v_public_services IS 'Anonymous booking catalog. Owner-rights on purpose (anon has no tenant claim), so the release rule is written into the body: only services with no available_in tuple are public — see #201.';\n\n\n-- ── default privileges: restore ─────────────────────────────────────────\n-- Put back, so the NEXT thing installed inherits what the chain had.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEND $dp$;\n`\n\nexport const MIGRATION_001_THE_CONNECTOR_DEFINERS_KEEP_A_PINNED_PATH = `-- ---------------------------------------------------------------------------\n-- 001_the_connector_definers_keep_a_pinned_path — the half of 019 the squash\n-- could not photograph (#283, #338).\n--\n-- 019 pinned \\`search_path\\` on every SECURITY DEFINER function this plugin owns,\n-- including \\`fn_gcal_push_booking\\`, which the GOOGLE CALENDAR CONNECTOR creates.\n-- Connector SQL is its own ledger source: it is not in chain.json, so it is not\n-- in the schema \\`emit-baseline\\` photographs, so 000_baseline.sql cannot carry\n-- the pin the way it carries the other 40.\n--\n-- Without this file a fresh install applies the connector's own 001-005, which\n-- create the function unpinned, and nothing ever pins it again — a definer\n-- function resolving names the caller's way, which is the exact shape #283\n-- exists to close. So 019's loop stays a migration.\n--\n-- Idempotent by construction: it pins only what is unpinned, and skips the\n-- function entirely on an install without the connector.\n-- ---------------------------------------------------------------------------\n\nDO $pin$\nDECLARE\n v_fn record;\n v_pinned integer := 0;\nBEGIN\n FOR v_fn IN\n SELECT p.oid, p.proname, pg_get_function_identity_arguments(p.oid) AS args\n FROM pg_proc p\n JOIN pg_namespace n ON n.oid = p.pronamespace\n WHERE n.nspname = 'public'\n AND p.prosecdef\n AND p.proname = ANY (ARRAY['create_public_booking', 'fn_gcal_push_booking'])\n AND NOT EXISTS (\n SELECT 1 FROM unnest(coalesce(p.proconfig, ARRAY[]::text[])) AS cfg\n WHERE cfg LIKE 'search\\\\_path=%'\n )\n LOOP\n -- \\`public, pg_catalog\\`, not '': these bodies read public objects by bare\n -- name and were written that way. What closes the hole is that the path is\n -- FIXED rather than inherited — the booking path is called by an anonymous\n -- shopper, and that caller's path should count for nothing.\n EXECUTE format('ALTER FUNCTION public.%I(%s) SET search_path = public, pg_catalog',\n v_fn.proname, v_fn.args);\n v_pinned := v_pinned + 1;\n END LOOP;\n IF v_pinned > 0 THEN\n RAISE NOTICE 'plugin-agenda: pinned search_path on % connector definer function(s)', v_pinned;\n END IF;\nEND $pin$;\n`\n\nexport const MIGRATION_002_THE_APPOINTMENT_NAMES_THE_UNIT = `-- ============================================================================\n-- 002_the_appointment_names_the_unit — v_appointments leaves the locations\n-- projection (#214 / #352).\n--\n-- The view LEFT JOINed public.locations, a compat projection of app.units. A\n-- view is a HARD dependency, so this join is what made the projection\n-- undroppable by the spine — which runs first and cannot remove a name a\n-- plugin applied later still selects.\n--\n-- The view is already security_invoker and app.units already grants SELECT to\n-- authenticated under its own RLS, so nothing about who sees which appointment\n-- changes: the same policy decides, one relation earlier.\n-- ============================================================================\n\nCREATE OR REPLACE VIEW public.v_appointments WITH (security_invoker='true') AS\n SELECT b.id,\n b.tenant_id,\n b.kind,\n b.starts_at,\n b.ends_at,\n b.status,\n b.notes,\n b.order_id,\n b.location_id,\n b.metadata,\n b.created_at,\n b.updated_at,\n b.party_id AS client_id,\n COALESCE(pc.name, (b.metadata ->> 'title'::text)) AS client_name,\n pc.phone AS client_phone,\n pc.email AS client_email,\n pc.avatar_url AS client_avatar_url,\n b.assignee_id AS professional_id,\n ps.name AS professional_name,\n ps.avatar_url AS professional_avatar_url,\n l.name AS location_name,\n o.total AS order_total,\n o.status AS order_status,\n ((EXTRACT(epoch FROM (COALESCE(b.ends_at, b.starts_at) - b.starts_at)))::integer / 60) AS total_duration_minutes,\n o.reference_number,\n o.status AS stage,\n (o.metadata ->> 'direction'::text) AS direction,\n ( SELECT json_agg(json_build_object('id', oi.id, 'serviceId', oi.product_id, 'name', oi.name, 'durationMinutes', oi.duration_minutes, 'price', oi.unit_price, 'assigneeId', oi.assignee_id) ORDER BY oi.sort_order) AS json_agg\n FROM public.items oi\n WHERE (oi.order_id = b.order_id)) AS services,\n inv.status AS payment_status,\n inv.paid AS order_paid,\n inv.balance AS order_balance\n FROM (((((public.appointments b\n LEFT JOIN public.people pc ON ((pc.id = b.party_id)))\n LEFT JOIN public.people ps ON ((ps.id = b.assignee_id)))\n LEFT JOIN app.units l ON ((l.id = b.location_id)))\n LEFT JOIN public.orders o ON ((o.id = b.order_id)))\n LEFT JOIN public.v_invoice_balances inv ON ((inv.invoice_id = b.order_id)));`\n\nexport const MIGRATION_003_THE_CLIENT_ARRIVES_BEFORE_BEING_SERVED = `-- 003_the_client_arrives_before_being_served.sql\n--\n-- Falta um estado entre \"confirmado\" e \"em atendimento\": AGUARDANDO.\n--\n-- É o estado que o check-in produz — a cliente chegou, está na recepção, ainda\n-- não sentou na cadeira. Hoje o ciclo do \\`appointment\\` vai de \\`confirmed\\`\n-- direto para \\`in_progress\\`, e quem recebe é obrigado a escolher entre mentir\n-- (dizer que já está em atendimento) ou não registrar nada. As duas respostas\n-- apagam a informação que a recepção mais usa: quem já está aqui.\n--\n-- No V1 esse estado existe e é o padrão da tela de check-in, ao lado de\n-- \\`scheduled\\`, \\`confirmed\\` e \\`in_progress\\`. Portá-lo é o que permite a tela\n-- fazer sentido — sem ele, \"fazer check-in\" não teria o que gravar.\n--\n-- Entra em \\`appointment\\` e em \\`service_order\\`: são a mesma coisa com nomes\n-- diferentes, e uma ordem de serviço também tem alguém esperando.\n\nUPDATE public.order_kinds\n SET statuses = (\n SELECT array_agg(DISTINCT s ORDER BY s)\n FROM unnest(coalesce(statuses, ARRAY[]::text[]) || ARRAY['waiting']) AS s\n ),\n updated_at = now()\n WHERE kind IN ('appointment', 'service_order')\n AND NOT ('waiting' = ANY (coalesce(statuses, ARRAY[]::text[])));\n`\n\nexport const MIGRATION_004_THE_APPOINTMENT_CARRIES_ITS_UNIT = `-- 004_the_appointment_carries_its_unit.sql\n--\n-- Um agendamento criado PELA TELA nasce com \\`unit_id\\` NULO: o formulário coleta\n-- o local e o provider nunca envia a unidade. E \\`location_id\\` já É uma unidade —\n-- aponta para o mesmo \\`app.units\\`.\n--\n-- O efeito não é cosmético. O escopo por unidade é o que faz a recepção de uma\n-- filial ver a fila DELA; uma linha sem unidade não é filtrada por unidade\n-- nenhuma, então ela aparece para TODAS. Num tenant de franquia — e a rede\n-- sintética tem seis unidades — isso é atendimento de uma filial visível na\n-- recepção da outra.\n--\n-- Apareceu numa jornada real: duas clientes no mesmo dia, uma marcada pela tela\n-- (sem unidade) e outra com unidade; a recepção de Norte — Centro via a primeira\n-- e não a segunda. O filtro estava certo. O dado é que chegava incompleto.\n--\n-- POR QUE GATILHO, E NÃO SÓ O CAMPO NO PROVIDER. O provider é um escritor entre\n-- vários: o agente cria agendamento, a importação cria, o totem cria. Corrigir\n-- só a tela deixaria os outros escrevendo linha sem unidade — e o furo é de\n-- VISIBILIDADE, que não se conserta pela metade.\nCREATE OR REPLACE FUNCTION public.trg_agenda_stamp_unit()\n RETURNS trigger\n LANGUAGE plpgsql\nAS $$\nBEGIN\n IF NEW.unit_id IS NULL AND NEW.location_id IS NOT NULL THEN\n NEW.unit_id := NEW.location_id;\n END IF;\n RETURN NEW;\nEND $$;\n\nCOMMENT ON FUNCTION public.trg_agenda_stamp_unit() IS\n 'Carimba a unidade do agendamento a partir do local, que é a mesma app.units. Sem ela a linha escapa do escopo por unidade e aparece para todas as filiais (004).';\n\nDROP TRIGGER IF EXISTS appointments_stamp_unit ON public.appointments;\nCREATE TRIGGER appointments_stamp_unit\n BEFORE INSERT OR UPDATE OF location_id, unit_id ON public.appointments\n FOR EACH ROW\n EXECUTE FUNCTION public.trg_agenda_stamp_unit();\n\n-- ── e os que já nasceram sem ───────────────────────────────────────────────\nUPDATE public.appointments\n SET unit_id = location_id\n WHERE unit_id IS NULL AND location_id IS NOT NULL;\n`\n\nexport const MIGRATION_005_THE_QUEUE_KNOWS_HOW_LONG_SHE_WAITED = `-- 005_the_queue_knows_how_long_she_waited.sql\n--\n-- A fila mostra QUEM chegou e não HÁ QUANTO TEMPO. Quem está esperando há\n-- quarenta minutos e quem acabou de entrar aparecem iguais, e é justamente essa\n-- diferença que decide quem a recepção chama primeiro.\n--\n-- O V1 mede por \\`checked_in_at\\`, e o comentário dele explica por que não serve\n-- \\`updated_at\\`: qualquer edição no agendamento o reescreve, então trocar uma\n-- observação às 14h faria a cliente que chegou às 13h parecer recém-chegada. Um\n-- relógio que qualquer coisa reinicia não é relógio.\n--\n-- O carimbo é do BANCO, e não da tela: quem faz check-in pode ser a recepção\n-- pelo navegador, o totem, ou o próprio agente. Três escritores, um só instante\n-- verdadeiro — e o relógio do servidor é o único que os três compartilham.\nALTER TABLE public.appointments\n ADD COLUMN IF NOT EXISTS checked_in_at timestamptz;\n\nCOMMENT ON COLUMN public.appointments.checked_in_at IS\n 'Quando a pessoa CHEGOU. Não use updated_at para isso: qualquer edição o reescreve e o tempo de espera mente (005).';\n\n-- ── e o carimbo acontece na transição, não no cliente ──────────────────────\nCREATE OR REPLACE FUNCTION public.trg_agenda_stamp_checkin()\n RETURNS trigger\n LANGUAGE plpgsql\nAS $$\nBEGIN\n -- Só na ENTRADA em waiting: reentrar no estado (uma correção de status, um\n -- salvamento qualquer) não pode reiniciar a espera de quem já está sentada.\n IF NEW.status = 'waiting' AND (TG_OP = 'INSERT' OR OLD.status IS DISTINCT FROM 'waiting')\n AND NEW.checked_in_at IS NULL THEN\n NEW.checked_in_at := now();\n END IF;\n RETURN NEW;\nEND $$;\n\nCOMMENT ON FUNCTION public.trg_agenda_stamp_checkin() IS\n 'Carimba a chegada ao ENTRAR em waiting, uma vez. Reentrar no estado não reinicia a espera (005).';\n\nDROP TRIGGER IF EXISTS appointments_stamp_checkin ON public.appointments;\nCREATE TRIGGER appointments_stamp_checkin\n BEFORE INSERT OR UPDATE OF status ON public.appointments\n FOR EACH ROW\n EXECUTE FUNCTION public.trg_agenda_stamp_checkin();\n\n-- Quem já está esperando desde antes deste arquivo herda o último instante\n-- conhecido — impreciso, e ainda assim melhor que um travessão.\nUPDATE public.appointments\n SET checked_in_at = updated_at\n WHERE status = 'waiting' AND checked_in_at IS NULL;\n`\n\nexport const MIGRATION_006_THE_AGENDA_STOPS_PRICING_EVERY_INVOICE = `-- ---------------------------------------------------------------------------\n-- 006_the_agenda_stops_pricing_every_invoice.sql — ler DOIS agendamentos deixa\n-- de custar a apuração de 8.134 faturas.\n--\n-- O SINTOMA: \\`GET /rest/v1/v_appointments?...\\` devolvendo 500 com\n-- \\`57014: canceling statement due to statement timeout\\`, de forma reprodutível,\n-- ao abrir a agenda depois que existe agendamento na semana. Enquanto a semana\n-- estava vazia a mesma consulta respondia em 12ms — o que escondeu o problema e\n-- fez ele parecer intermitente.\n--\n-- ── A medição ──────────────────────────────────────────────────────────────\n-- EXPLAIN ANALYZE da consulta exata, com 2 agendamentos na janela:\n--\n-- Nested Loop Left Join actual time=17137..21252 rows=2\n-- Join Filter: (o_1.id = b.order_id)\n-- Rows Removed by Join Filter: 16268 ← dezesseis mil\n-- -> Nested Loop ... actual time=5619..10590 rows=8134 loops=2\n-- Execution Time: 21272 ms\n--\n-- \\`v_invoice_balances\\` foi calculada POR INTEIRO — as 8.134 faturas do tenant —\n-- e DUAS VEZES, uma por agendamento. Só depois o \\`Join Filter\\` jogou fora\n-- 16.268 das 16.270 linhas para ficar com as 2 que interessavam.\n--\n-- ── Por que o filtro não desceu ────────────────────────────────────────────\n-- A view fazia:\n--\n-- LEFT JOIN v_invoice_balances inv ON inv.invoice_id = b.order_id\n--\n-- Isso é um JOIN entre duas relações, não um filtro constante. O planejador não\n-- tem por onde empurrar \\`b.order_id\\` para dentro de um agregado do outro lado:\n-- ele precisa produzir o lado direito inteiro para então casar as chaves. E o\n-- lado direito é um \\`GROUP BY order_id\\` sobre a árvore financeira inteira\n-- (faturas → parcelas → alocações → movimentos), cada nível pagando a RLS por\n-- linha. 8.134 linhas × ~0,45ms de política × três níveis é o orçamento todo.\n--\n-- ── A correção ─────────────────────────────────────────────────────────────\n-- \\`LEFT JOIN LATERAL\\`. A correlação deixa de ser uma condição de join e vira um\n-- PARÂMETRO da subconsulta: \\`WHERE vb.invoice_id = b.order_id\\` é avaliado com\n-- \\`b.order_id\\` já conhecido, e \\`invoice_id\\` é exatamente a chave de agrupamento\n-- de \\`v_invoice_balances\\` (\\`GROUP BY t.order_id\\`, depois \\`o.id = tb.order_id\\`).\n-- Um qual sobre a chave de agrupamento desce por baixo do agregado, e o que\n-- era uma varredura de 8.134 faturas vira uma sondagem de índice de UMA.\n--\n-- Nada muda no que a view devolve: mesmas colunas, mesma ordem, mesmos tipos —\n-- \\`LEFT JOIN LATERAL … ON true\\` tem exatamente a semântica do LEFT JOIN que\n-- substitui, inclusive o NULL quando não há fatura.\n--\n-- ── O que esta migration NÃO conserta ──────────────────────────────────────\n-- O multiplicador continua sendo a RLS por linha (~0,45ms por linha por\n-- tabela). Aqui ele deixa de doer porque o número de linhas cai de 8.134 para\n-- 1, não porque ficou barato. Qualquer outra leitura que varra as tabelas\n-- financeiras inteiras vai reencontrá-lo — ver 016 e 019 para a forma de tirar\n-- pergunta constante de dentro do laço.\n--\n-- MORA NA CORRENTE DA AGENDA, e não na do núcleo, porque redefine\n-- \\`v_appointments\\` — view da agenda — lendo \\`v_invoice_balances\\`, view do\n-- financeiro. A corrente é núcleo → financeiro → … → agenda, então este é o\n-- único degrau em que as duas já existem. Nascida como 021 no núcleo, ela\n-- falhava no \\`apply\\` com \"relation v_invoice_balances does not exist\", e o\n-- db-from-zero foi quem disse isso em voz alta.\n-- ---------------------------------------------------------------------------\n\n-- \\`WITH (security_invoker = true)\\` explícito: \\`CREATE OR REPLACE VIEW\\` NÃO\n-- herda as opções da view que substitui, e sem isto ela volta a rodar com os\n-- direitos do dono — as políticas de quem lê deixam de valer. É o que a\n-- asserção N16 da postura grada, e foi ela que pegou.\nCREATE OR REPLACE VIEW public.v_appointments WITH (security_invoker = true) AS\n SELECT b.id,\n b.tenant_id,\n b.kind,\n b.starts_at,\n b.ends_at,\n b.status,\n b.notes,\n b.order_id,\n b.location_id,\n b.metadata,\n b.created_at,\n b.updated_at,\n b.party_id AS client_id,\n COALESCE(pc.name, b.metadata ->> 'title'::text) AS client_name,\n pc.phone AS client_phone,\n pc.email AS client_email,\n pc.avatar_url AS client_avatar_url,\n b.assignee_id AS professional_id,\n ps.name AS professional_name,\n ps.avatar_url AS professional_avatar_url,\n l.name AS location_name,\n o.total AS order_total,\n o.status AS order_status,\n EXTRACT(epoch FROM COALESCE(b.ends_at, b.starts_at) - b.starts_at)::integer / 60 AS total_duration_minutes,\n o.reference_number,\n o.status AS stage,\n o.metadata ->> 'direction'::text AS direction,\n ( SELECT json_agg(json_build_object('id', oi.id, 'serviceId', oi.product_id, 'name', oi.name, 'durationMinutes', oi.duration_minutes, 'price', oi.unit_price, 'assigneeId', oi.assignee_id) ORDER BY oi.sort_order) AS json_agg\n FROM items oi\n WHERE oi.order_id = b.order_id) AS services,\n inv.status AS payment_status,\n inv.paid AS order_paid,\n inv.balance AS order_balance\n FROM appointments b\n LEFT JOIN people pc ON pc.id = b.party_id\n LEFT JOIN people ps ON ps.id = b.assignee_id\n LEFT JOIN app.units l ON l.id = b.location_id\n LEFT JOIN orders o ON o.id = b.order_id\n -- LATERAL e não JOIN: assim \\`b.order_id\\` é PARÂMETRO da subconsulta e o\n -- filtro desce por baixo do \\`GROUP BY order_id\\` de v_invoice_balances.\n -- Como JOIN, o agregado inteiro (8.134 faturas) era produzido por\n -- agendamento e descartado depois — 21s para devolver 2 linhas.\n LEFT JOIN LATERAL (\n SELECT vb.status, vb.paid, vb.balance\n FROM v_invoice_balances vb\n WHERE vb.invoice_id = b.order_id\n LIMIT 1\n ) inv ON true;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_the_connector_definers_keep_a_pinned_path\", sql: MIGRATION_001_THE_CONNECTOR_DEFINERS_KEEP_A_PINNED_PATH },\n { id: \"002_the_appointment_names_the_unit\", sql: MIGRATION_002_THE_APPOINTMENT_NAMES_THE_UNIT },\n { id: \"003_the_client_arrives_before_being_served\", sql: MIGRATION_003_THE_CLIENT_ARRIVES_BEFORE_BEING_SERVED },\n { id: \"004_the_appointment_carries_its_unit\", sql: MIGRATION_004_THE_APPOINTMENT_CARRIES_ITS_UNIT },\n { id: \"005_the_queue_knows_how_long_she_waited\", sql: MIGRATION_005_THE_QUEUE_KNOWS_HOW_LONG_SHE_WAITED },\n { id: \"006_the_agenda_stops_pricing_every_invoice\", sql: MIGRATION_006_THE_AGENDA_STOPS_PRICING_EVERY_INVOICE },\n]\n","// ---------------------------------------------------------------------------\n// Bridge factory: adapts FinancialDataProvider → AgendaFinancialBridge\n// Consumer apps call this at plugin wiring time.\n// ---------------------------------------------------------------------------\n\nimport type { FinancialDataProvider } from '@fayz-ai/plugin-financial'\nimport type { AgendaFinancialBridge, BookingPaymentSummary, BookingPaymentDetail, BookingPaymentStatus } from './financial-bridge'\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\n\n/**\n * Pure commission math: percentage of a realized order total, rounded to cents.\n * Exported for unit-testing and reuse; the bridge method below wraps the I/O.\n * Returns 0 for a non-positive base or rate so callers can skip empty accruals.\n */\nexport function computeCommissionAmount(total: number, ratePercent: number): number {\n const base = Number(total) || 0\n const rate = Number(ratePercent) || 0\n if (base <= 0 || rate <= 0) return 0\n return Math.round(base * (rate / 100) * 100) / 100\n}\n\nfunction computeStatus(movements: Array<{ status: string }>): BookingPaymentStatus {\n if (movements.length === 0) return 'none'\n const allPaid = movements.every((m) => m.status === 'paid')\n if (allPaid) return 'paid'\n const allCancelled = movements.every((m) => m.status === 'cancelled')\n if (allCancelled) return 'cancelled'\n const anyOverdue = movements.some((m) => m.status === 'overdue')\n if (anyOverdue) return 'overdue'\n const anyPaid = movements.some((m) => m.status === 'paid' || m.status === 'partial')\n if (anyPaid) return 'partial'\n return 'pending'\n}\n\n/**\n * Create an AgendaFinancialBridge backed by the financial plugin's data provider.\n *\n * @example\n * const financialProvider = createSupabaseFinancialProvider()\n * const agenda = createAgendaPlugin({\n * financialBridge: createFinancialBridge(financialProvider),\n * })\n */\nexport function createFinancialBridge(provider: FinancialDataProvider): AgendaFinancialBridge {\n return {\n async resolvePaymentStatuses(orderIds: string[]): Promise<Map<string, BookingPaymentSummary>> {\n const result = new Map<string, BookingPaymentSummary>()\n if (orderIds.length === 0) return result\n\n // Single batch query instead of N individual getInvoiceById calls\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return result\n\n // One read of a derived view (financial 039) instead of two: the order plus\n // the legacy `movement_kind='bill'` mirror. The badge only ever wanted \"how\n // much of this has been paid\", and the installment balances answer that\n // from the allocations themselves — which is what lets the mirror die.\n try {\n const { data: rows } = await supabase\n .from('v_order_payment_status')\n .select('order_id, order_status, reference_number, total_amount, paid_amount, status')\n .in('order_id', orderIds)\n\n for (const row of rows ?? []) {\n result.set(row.order_id as string, {\n invoiceId: row.order_id as string,\n referenceNumber: row.reference_number as string | undefined,\n status: (row.status as string) === 'none'\n ? mapInvoiceStatus(row.order_status as string)\n : (row.status as BookingPaymentStatus),\n totalAmount: Number(row.total_amount) || 0,\n paidAmount: Number(row.paid_amount) || 0,\n })\n }\n } catch { /* non-blocking */ }\n\n return result\n },\n\n async getPaymentDetail(orderId: string): Promise<BookingPaymentDetail | null> {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return null\n\n // The header comes from the derived view and the instalments from the\n // canonical balances — neither reads the legacy bill mirror any more.\n const [headRes, movRes] = await Promise.all([\n supabase\n .from('v_order_payment_status')\n .select('order_id, order_status, reference_number, total_amount, paid_amount, status')\n .eq('order_id', orderId)\n .single(),\n supabase.from('plg_financial_movements').select('*').eq('invoice_id', orderId).order('due_date'),\n ])\n\n const order = headRes.data\n if (!order) return null\n\n // Collect unique payment_method_type_ids to resolve names in one query\n const typeIds = [...new Set((movRes.data ?? []).map((m: any) => m.payment_method_type_id).filter(Boolean))]\n let typeNames: Record<string, string> = {}\n if (typeIds.length > 0) {\n const { data: types } = await supabase.from('plg_financial_payment_method_types').select('id, name').in('id', typeIds)\n typeNames = Object.fromEntries((types ?? []).map((t: any) => [t.id, t.name]))\n }\n\n const movements = (movRes.data ?? []).map((m: Record<string, unknown>) => ({\n id: String(m.id),\n amount: Number(m.amount) || 0,\n paidAmount: Number(m.paid_amount) || 0,\n status: String(m.status ?? 'pending'),\n dueDate: String(m.due_date ?? ''),\n installmentNumber: m.installment_number != null ? Number(m.installment_number) : undefined,\n paymentDate: m.payment_date ? String(m.payment_date) : undefined,\n paymentMethodTypeName: m.payment_method_type_id ? typeNames[String(m.payment_method_type_id)] : undefined,\n cardBrand: m.card_brand ? String(m.card_brand) : undefined,\n cardInstallments: m.card_installments ? Number(m.card_installments) : undefined,\n }))\n\n return {\n invoiceId: order.order_id as string,\n referenceNumber: order.reference_number as string | undefined,\n status: (order.status as string) === 'none'\n ? mapInvoiceStatus(order.order_status as string)\n : (order.status as BookingPaymentStatus),\n totalAmount: Number(order.total_amount) || 0,\n paidAmount: Number(order.paid_amount) || 0,\n movements,\n }\n },\n\n async createInvoiceFromOrder(orderId: string, options?: {\n installments?: number\n dueDate?: string\n paymentMethodTypeId?: string\n }): Promise<string> {\n // One call, one transaction (PRD 06). Promoting the Venda to a Título is\n // the database's job: the two-call version could leave a sale with no\n // receivable and nothing to reconcile it afterwards.\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not available')\n const { error } = await supabase.rpc('fn_invoice_from_order', {\n p_order_id: orderId,\n p_due_date: options?.dueDate ?? null,\n p_status: 'invoiced',\n p_installments: options?.installments ?? 1,\n p_direction: 'credit',\n })\n if (error) throw new Error(error.message)\n return orderId\n },\n\n async payMovement(input) {\n await provider.payMovement({\n movementId: input.movementId,\n amount: input.amount,\n paymentDate: input.paymentDate,\n paymentMethodTypeId: input.paymentMethodTypeId,\n paymentMethodId: input.paymentMethodId,\n bankAccountId: input.bankAccountId,\n cardBrand: input.cardBrand,\n cardInstallments: input.cardInstallments,\n })\n },\n\n async createCommissionMovement(orderId, options) {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return null\n\n // The professional and the realized total come from the agenda's own read\n // model, not from public.orders: the core owns that table, and this plugin\n // reads what the core publishes (PRD 06, the ownership rule).\n const { data: order } = await supabase\n .from('v_appointments')\n .select('order_id, tenant_id, professional_id, order_total')\n .eq('order_id', orderId)\n .limit(1)\n .maybeSingle()\n if (!order || !order.professional_id) return null // no professional → no commission\n\n // The rate belongs to the professional's ROLE, not to the person: same\n // human, different unit, different rate (143). v_staff, which this used to\n // ask, is declared by no migration and has no such column anywhere.\n const { data: staff } = await supabase\n .from('v_professional_rates')\n .select('commission_rate')\n .eq('id', order.professional_id)\n .single()\n\n const rate = Number(staff?.commission_rate) || 0\n const base = Number(order.order_total) || 0\n const amount = computeCommissionAmount(base, rate)\n if (amount <= 0) return null // nothing configured/realized to accrue\n\n // Idempotent: one commission accrual per order. Reuse if already present.\n const { data: existing } = await supabase\n .from('plg_financial_movements')\n .select('id')\n .eq('invoice_id', orderId)\n .eq('movement_kind', 'commission')\n .limit(1)\n if (existing && existing.length > 0) return existing[0].id as string\n\n const dueDate = options?.dueDate ?? new Date().toISOString().slice(0, 10)\n\n const { data: inserted } = await supabase\n .from('plg_financial_movements')\n .insert({\n tenant_id: order.tenant_id,\n invoice_id: orderId,\n direction: 'debit', // payable to the professional\n movement_kind: 'commission',\n amount,\n paid_amount: 0,\n status: 'pending',\n due_date: dueDate,\n metadata: {\n source: 'agenda',\n kind: 'commission',\n professionalId: order.professional_id,\n commissionRate: rate,\n baseAmount: base,\n },\n })\n .select('id')\n .single()\n\n return (inserted?.id as string | undefined) ?? null\n },\n\n async checkout(orderId, input) {\n // 1. Create invoice (single installment, due today)\n const today = new Date().toISOString().slice(0, 10)\n const invoiceId = await this.createInvoiceFromOrder(orderId, { installments: 1, dueDate: today })\n\n // 2. Get the created movement\n const detail = await this.getPaymentDetail(invoiceId)\n if (!detail || detail.movements.length === 0) throw new Error('No movement created')\n\n const movement = detail.movements[0]\n\n // 3. Pay it in full\n await this.payMovement({\n movementId: movement.id,\n amount: movement.amount,\n paymentDate: today,\n paymentMethodTypeId: input.paymentMethodTypeId,\n paymentMethodId: input.paymentMethodId,\n bankAccountId: input.bankAccountId,\n cardBrand: input.cardBrand,\n cardInstallments: input.cardInstallments,\n })\n\n // 4. Return updated detail\n return (await this.getPaymentDetail(invoiceId))!\n },\n\n async getPaymentMethodTypes() {\n const types = await provider.getPaymentMethodTypes()\n return types.map((t: any) => ({ id: t.id, name: t.name, transactionType: t.transactionType }))\n },\n\n async getBankAccounts() {\n const accounts = await provider.getBankAccounts()\n return accounts\n .filter((a: any) => a.isActive)\n .map((a: any) => ({ id: a.id, name: a.name, accountType: a.accountType }))\n },\n\n async getPaymentMethods(paymentMethodTypeId: string) {\n const methods = await provider.getPaymentMethods()\n return methods\n .filter((m: any) => m.paymentMethodTypeId === paymentMethodTypeId && m.isActive)\n .map((m: any) => ({ id: m.id, name: m.name }))\n },\n }\n}\n\nfunction mapInvoiceStatus(status: string): BookingPaymentStatus {\n switch (status) {\n case 'paid': return 'paid'\n case 'partial': return 'partial'\n case 'overdue': return 'overdue'\n case 'cancelled': return 'cancelled'\n case 'invoiced': return 'pending'\n case 'pending': return 'pending'\n case 'scheduled': return 'none'\n case 'confirmed': return 'none'\n case 'in_progress': return 'none'\n case 'completed': return 'none'\n case 'no_show': return 'none'\n case 'booked': return 'none'\n default: return 'pending'\n }\n}\n","// Booking ↔ Google Calendar event mapping — the SINGLE SOURCE OF TRUTH.\n//\n// These helpers are pure and Deno-friendly (only `import type`, no runtime\n// node/react/https imports), so the Supabase edge function imports this exact\n// file via a relative path (`../../src/integrations/google-calendar/mapping.ts`)\n// instead of keeping a divergent mirror. `import type` is elided by the Deno /\n// esbuild bundler, so the plugin `types.ts`/`CalendarBooking` type imports never\n// become runtime dependencies of the function bundle.\n//\n// Two callers, two input shapes:\n// • the SDK/UI works with the rich `CalendarBooking` (camelCase, joined) — see\n// bookingToEvent / eventToBookingPatch;\n// • the edge function + RPCs work with the raw `AppointmentRow` (snake_case DB\n// columns) — see appointmentRowToEvent / eventToAppointmentPatch.\n// Field decisions (title, all-day, cancel) are made once, here.\nimport type { CalendarBooking } from '../../types'\nimport type { GCalEvent, AppointmentRow, CalendarChannel, CalendarChannelRow } from './types'\n\nexport interface GCalEventInput {\n summary: string\n description?: string\n // Timed events use dateTime; all-day events use date (YYYY-MM-DD).\n start: { dateTime?: string; date?: string; timeZone?: string }\n end: { dateTime?: string; date?: string; timeZone?: string }\n}\n\n/** Normalized time window read off a Google event, all-day aware. */\nexport interface EventTimes {\n startsAt: string\n endsAt: string\n allDay: boolean\n}\n\n// --- Booking (rich SDK shape) → event -------------------------------------\n\n/** Build the event title from the booking's services + client. */\nexport function bookingSummary(b: Pick<CalendarBooking, 'services' | 'clientName'>): string {\n const services = (b.services ?? []).map((s) => s.name).filter(Boolean).join(', ')\n const who = b.clientName ?? ''\n if (services && who) return `${services} — ${who}`\n return services || who || 'Appointment'\n}\n\n/** Map a Fayz booking to a Google Calendar event input. Returns null when the booking has no end. */\nexport function bookingToEvent(b: CalendarBooking, timeZone?: string): GCalEventInput | null {\n if (!b.startsAt || !b.endsAt) return null\n const notes = [b.notes, b.professionalName ? `Pro: ${b.professionalName}` : '', b.locationName ?? '']\n .filter(Boolean).join('\\n')\n return {\n summary: bookingSummary(b),\n description: notes || undefined,\n start: { dateTime: b.startsAt, timeZone },\n end: { dateTime: b.endsAt, timeZone },\n }\n}\n\n/** Map an inbound Google event change to a partial booking update (reschedule/cancel), all-day aware. */\nexport function eventToBookingPatch(ev: GCalEvent): { startsAt?: string; endsAt?: string; status?: 'cancelled' } {\n if (ev.status === 'cancelled') return { status: 'cancelled' }\n const t = eventTimes(ev)\n return { startsAt: t.startsAt, endsAt: t.endsAt }\n}\n\n// --- Appointment row (raw DB shape) → event -------------------------------\n\n/**\n * Build the event title from an appointments row's denormalized metadata.\n * The raw row has no joined services/client, so we read the names the app\n * stamps onto metadata (serviceNames, contactName/clientName).\n */\nexport function appointmentRowSummary(row: AppointmentRow): string {\n const m = row.metadata ?? {}\n const services = (m.serviceNames as string) ?? ''\n const who = (m.contactName as string) ?? (m.clientName as string) ?? ''\n if (services && who) return `${services} — ${who}`\n return services || who || 'Appointment'\n}\n\n/** Map a raw appointments row to a Google event input (outbound push from the edge function). */\nexport function appointmentRowToEvent(row: AppointmentRow): GCalEventInput {\n return {\n summary: appointmentRowSummary(row),\n description: row.notes ?? undefined,\n start: { dateTime: row.starts_at },\n end: { dateTime: row.ends_at ?? row.starts_at },\n }\n}\n\n/**\n * Map an inbound Google event to a DB-friendly appointment patch (snake_case\n * times), all-day aware, cancellation included. Consumed by the edge function\n * when calling gcal_apply_event_patch.\n */\nexport function eventToAppointmentPatch(ev: GCalEvent): {\n starts_at?: string\n ends_at?: string\n summary?: string\n allDay?: boolean\n cancelled: boolean\n} {\n if (ev.status === 'cancelled') return { cancelled: true }\n const t = eventTimes(ev)\n return { starts_at: t.startsAt, ends_at: t.endsAt, summary: ev.summary, allDay: t.allDay, cancelled: false }\n}\n\n// --- Shared time normalization (all-day aware) ----------------------------\n\n/**\n * Read a normalized {startsAt, endsAt, allDay} window off a Google event.\n * All-day events carry `start.date`/`end.date` (YYYY-MM-DD, end exclusive) and\n * no dateTime; timed events carry dateTime. Falls back start→end when one side\n * is missing so callers always get a usable pair.\n */\nexport function eventTimes(ev: GCalEvent): EventTimes {\n const allDay = !ev.start?.dateTime && !!ev.start?.date\n const startsAt = ev.start?.dateTime ?? ev.start?.date ?? ''\n const endsAt = ev.end?.dateTime ?? ev.end?.date ?? startsAt\n return { startsAt, endsAt, allDay }\n}\n\n// --- Channel resolution (outbound destination priority) -------------------\n\n/** Convert a raw plg_calendar_channels row (snake_case) to the camelCase CalendarChannel. */\nexport function channelRowToChannel(r: CalendarChannelRow): CalendarChannel {\n return {\n id: r.id,\n integrationId: r.integration_id,\n tenantId: r.tenant_id,\n googleCalendarId: r.google_calendar_id,\n summary: r.summary ?? null,\n color: r.color ?? null,\n direction: r.direction,\n targetKind: r.target_kind ?? null,\n targetId: r.target_id ?? null,\n importMode: r.import_mode ?? 'appointment',\n syncToken: r.sync_token ?? null,\n channelId: r.channel_id ?? null,\n resourceId: r.resource_id ?? null,\n channelExpiresAt: r.channel_expires_at ?? null,\n isActive: r.is_active ?? true,\n createdAt: r.created_at ?? '',\n updatedAt: r.updated_at ?? '',\n }\n}\n\nexport interface ChannelMatchInput {\n assigneeId?: string | null\n serviceIds?: string[]\n locationId?: string | null\n}\n\n/**\n * Pick the outbound destination channel for a booking, by priority:\n * 1. a channel targeting the booking's assignee,\n * 2. else a channel targeting one of the booking's services,\n * 3. else a channel targeting the booking's location,\n * 4. else the whole-agenda channel (targetKind === null).\n * Only active outbound/bidirectional channels are eligible. Returns null when\n * nothing matches (caller falls back to the integration's default calendar).\n */\nexport function resolveTargetChannel(\n channels: CalendarChannel[],\n booking: ChannelMatchInput,\n): CalendarChannel | null {\n const eligible = channels.filter(\n (c) => c.isActive && (c.direction === 'outbound' || c.direction === 'bidirectional'),\n )\n const serviceIds = booking.serviceIds ?? []\n\n if (booking.assigneeId) {\n const byAssignee = eligible.find((c) => c.targetKind === 'assignee' && c.targetId === booking.assigneeId)\n if (byAssignee) return byAssignee\n }\n if (serviceIds.length) {\n const byService = eligible.find((c) => c.targetKind === 'service' && !!c.targetId && serviceIds.includes(c.targetId))\n if (byService) return byService\n }\n if (booking.locationId) {\n const byLocation = eligible.find((c) => c.targetKind === 'location' && c.targetId === booking.locationId)\n if (byLocation) return byLocation\n }\n return eligible.find((c) => c.targetKind === null) ?? null\n}\n","// Where the Google grant lives — and the one place that changes when it moves.\n//\n// It moved (FAY-1359/1360, 2026-08-12). It used to live on\n// plg_calendar_integrations as `oauth_refresh_token` / `oauth_access_token`: a\n// tenant-RLS table the browser reads, so every authenticated member of the\n// tenant — reception included — could pull a refresh token down the wire, which\n// is durable access to someone's whole calendar. It now lives in the platform\n// vault, and the edge function redeems a short-lived access token per call.\n//\n// So this file no longer answers \"is there a grant?\" at all: `connections`\n// does, through the shared connection store, the same as every other connector.\n// What is left here is the ONE rule that outlived the credential — the browser\n// reads named columns off the integration row and never `*`.\nimport type { CalendarIntegrationRow } from './types'\n\n/**\n * The columns the browser may read off the integration row. An explicit list,\n * not `*` — `select('*')` is how the refresh token reached the browser in the\n * first place, and a column added later should have to be let in on purpose.\n *\n * There is no credential column left to exclude. The list stays anyway: it is\n * cheap, and the day someone adds one, this is what makes them notice.\n */\nexport const CONNECTION_COLUMNS = 'id, provider, calendar_id, active, last_sync_at'\n\n/**\n * Whether the calendar side of the integration is switched on.\n *\n * NOT \"is the connector connected\" — that question belongs to\n * `connections` and is asked through the connection store. This one only\n * says whether the tenant's own sync state row is live, which is what the\n * health rule needs before it complains about a stale cursor.\n */\nexport function isIntegrationActive(\n row: Pick<CalendarIntegrationRow, 'active'> | null | undefined,\n): boolean {\n return !!row && row.active !== false\n}\n\n/**\n * The patch that stops the calendar side.\n *\n * It does not revoke anything: the grant is the platform's, and revoking it at\n * Google is the platform's disconnect. This turns off the sync state row.\n */\nexport function disconnectPatch(): Record<string, unknown> {\n return { active: false, updated_at: new Date().toISOString() }\n}\n","// Canonical DB object names for the Google Calendar connector.\n//\n// Plugin-owned tables carry the platform `plg_<plugin>_` prefix (DATA-MODEL.md\n// Ring 1). Single source of truth so the connector data layer (supabase.ts) and\n// the google-calendar-sync edge function never drift on a table name. The SQL\n// side is owned by ./migrations/001_google_calendar.sql + 002_smart_sync.sql\n// (fresh installs) and 003_plg_rename.sql (legacy-pool rename).\n// webhookDeliveries/automationOutbox were recovered from the deployed bundles on\n// 2026-08-12 (FAY-1379): both live functions read them off this map, but the two\n// tables existed only in the pool — 006 is the migration that creates them.\nexport const GCAL_TABLES = {\n integrations: 'plg_calendar_integrations',\n channels: 'plg_calendar_channels',\n syncLog: 'plg_calendar_sync_log',\n webhookDeliveries: 'plg_calendar_webhook_deliveries',\n automationOutbox: 'plg_calendar_automation_outbox',\n} as const\n","// Google Calendar integration (control plane) — Supabase client.\n//\n// Thin client. Split of responsibilities:\n// • anything that touches Google goes through the google-calendar-sync edge\n// function, which redeems the tenant's grant from the platform vault;\n// • plain tenant-scoped reads/writes (integration row, channels, log) hit the\n// tables directly under RLS.\n//\n// No call from here carries a credential, and none can: the browser has never\n// been able to see the grant since FAY-1359, and what it sends instead is a\n// runtime token that only says WHICH TENANT is asking.\nimport {\n CONNECTOR_RUNTIME_TOKEN_HEADER,\n connectorRuntimeToken,\n getSupabaseClientOptional,\n getActiveTenantId,\n} from '@fayz-ai/core'\nimport { channelRowToChannel } from '../mapping'\nimport { CONNECTION_COLUMNS, disconnectPatch, isIntegrationActive } from '../credentials'\nimport { GCAL_TABLES } from './tables'\nimport type {\n CalendarIntegration,\n CalendarSyncLogEntry,\n CalendarChannel,\n ExternalEventPreview,\n GoogleCalendarListEntry,\n ImportEventsResult,\n} from '../types'\n\nconst FUNCTION = 'google-calendar-sync'\n\nfunction sb() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\n/**\n * One call to the data plane, carrying the two things it cannot derive.\n *\n * The Supabase session goes in `Authorization`, and the Fayz runtime token in\n * its own header — that is the one the function forwards to redeem this\n * tenant's Google grant. An edge function cannot mint one, so a call without it\n * is a call the function must refuse; asking for it here means the refusal\n * happens before the round trip instead of as a 401 the clinic sees.\n */\nasync function invoke<T>(body: Record<string, unknown>): Promise<T> {\n const tenantId = getActiveTenantId()\n const runtimeToken = await connectorRuntimeToken({ tenantId })\n\n const { data, error } = await sb().functions.invoke(FUNCTION, {\n body: { ...body, tenantId },\n headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken },\n })\n if (error) throw new Error(error.message)\n return data as T\n}\n\n/** Snake_case patch for plg_calendar_channels writes (RLS-scoped). */\nexport interface CalendarChannelInput {\n id?: string\n integrationId?: string\n googleCalendarId: string\n summary?: string | null\n color?: string | null\n direction?: CalendarChannel['direction']\n targetKind?: CalendarChannel['targetKind']\n targetId?: string | null\n importMode?: CalendarChannel['importMode']\n isActive?: boolean\n}\n\nexport interface GoogleCalendarProvider {\n getIntegration(): Promise<CalendarIntegration | null>\n /**\n * Make sure this tenant HAS a sync state row, and switch it on.\n *\n * The OAuth callback used to create it, as a side effect of writing the\n * refresh token into it. That callback is the platform's now and knows\n * nothing about this pool's tables, so the row has to be created on the way\n * back from consent — a channel FKs to it, and a de-para with no integration\n * to hang from is the shape of \"conectei e não dá para escolher a agenda\".\n */\n ensureIntegration(): Promise<void>\n setCalendar(calendarId: string): Promise<void>\n disconnect(): Promise<void>\n /** Manually pull external changes now (inbound). */\n syncNow(): Promise<{ fetched: number; written: number; discovered?: number }>\n getSyncLog(): Promise<CalendarSyncLogEntry[]>\n // --- smart sync: multi-calendar channels + import wizard ---\n /** List the user's Google calendars for the de-para picker (needs the API → function). */\n listGoogleCalendars(): Promise<GoogleCalendarListEntry[]>\n /** Read this tenant's channels (RLS). */\n listChannels(): Promise<CalendarChannel[]>\n /** Create/update a channel (RLS upsert on integration_id + google_calendar_id). */\n saveChannel(input: CalendarChannelInput): Promise<void>\n /** Delete a channel by id (RLS). */\n deleteChannel(id: string): Promise<void>\n /** Preview future events not yet linked to an appointment (import wizard). */\n listExternalEvents(params?: { channelId?: string; timeMin?: string }): Promise<ExternalEventPreview[]>\n /** Import selected external events as appointments. */\n importEvents(items: { channelId: string; eventId: string }[]): Promise<ImportEventsResult>\n}\n\nexport function createGoogleCalendarProvider(): GoogleCalendarProvider {\n return {\n async getIntegration() {\n // Named columns, never `*`: the credential must not be able to ride along.\n const { data } = await sb().from(GCAL_TABLES.integrations).select(CONNECTION_COLUMNS).eq('provider', 'google').limit(1).maybeSingle()\n if (!data) return null\n return {\n id: data.id,\n provider: data.provider,\n calendarId: data.calendar_id ?? 'primary',\n active: isIntegrationActive(data),\n // The sync state row existing is not the same as the clinic having\n // authorized Google — `connections` owns that answer now, and the\n // connector asks it through the connection store.\n connected: isIntegrationActive(data),\n lastSyncAt: data.last_sync_at ?? undefined,\n }\n },\n\n async ensureIntegration() {\n const { error } = await sb()\n .from(GCAL_TABLES.integrations)\n .upsert(\n {\n tenant_id: getActiveTenantId(),\n provider: 'google',\n active: true,\n updated_at: new Date().toISOString(),\n },\n { onConflict: 'tenant_id,provider' },\n )\n if (error) throw new Error(error.message)\n },\n\n async setCalendar(calendarId) {\n await sb().from(GCAL_TABLES.integrations).update({ calendar_id: calendarId, updated_at: new Date().toISOString() }).eq('provider', 'google')\n },\n\n async disconnect() {\n // Two writes, and the order matters: the function stops the watches at\n // Google while the grant still works, then the row goes inactive. No\n // token is cleared here because none is stored here — revoking the grant\n // is the platform's call, since it is the platform that holds it.\n await invoke({ action: 'disconnect' })\n await sb().from(GCAL_TABLES.integrations).update(disconnectPatch()).eq('provider', 'google')\n },\n\n async syncNow() {\n return invoke<{ fetched: number; written: number; discovered?: number }>({\n action: 'pull_events',\n trigger: 'manual',\n })\n },\n\n async getSyncLog() {\n const { data } = await sb().from(GCAL_TABLES.syncLog).select('*').order('created_at', { ascending: false }).limit(20)\n return (data ?? []).map((r: any) => ({\n id: r.id, direction: r.direction, trigger: r.trigger ?? undefined,\n status: r.status, fetched: r.fetched ?? 0, written: r.written ?? 0,\n error: r.error ?? undefined, createdAt: r.created_at,\n }))\n },\n\n async listGoogleCalendars() {\n const result = await invoke<{ calendars: GoogleCalendarListEntry[] }>({ action: 'list_calendars' })\n return result.calendars ?? []\n },\n\n async listChannels() {\n const { data } = await sb().from(GCAL_TABLES.channels).select('*').order('created_at', { ascending: true })\n return (data ?? []).map(channelRowToChannel)\n },\n\n async saveChannel(input) {\n const tenantId = getActiveTenantId()\n // Resolve the integration id when the caller didn't pass one.\n let integrationId = input.integrationId\n if (!integrationId) {\n const { data } = await sb().from(GCAL_TABLES.integrations).select('id').eq('provider', 'google').limit(1).maybeSingle()\n integrationId = data?.id\n }\n const row: Record<string, unknown> = {\n integration_id: integrationId,\n tenant_id: tenantId,\n google_calendar_id: input.googleCalendarId,\n updated_at: new Date().toISOString(),\n }\n if (input.id !== undefined) row.id = input.id\n if (input.summary !== undefined) row.summary = input.summary\n if (input.color !== undefined) row.color = input.color\n if (input.direction !== undefined) row.direction = input.direction\n if (input.targetKind !== undefined) row.target_kind = input.targetKind\n if (input.targetId !== undefined) row.target_id = input.targetId\n if (input.importMode !== undefined) row.import_mode = input.importMode\n if (input.isActive !== undefined) row.is_active = input.isActive\n const { error } = await sb().from(GCAL_TABLES.channels).upsert(row, { onConflict: 'integration_id,google_calendar_id' })\n if (error) throw new Error(error.message)\n },\n\n async deleteChannel(id) {\n const { error } = await sb().from(GCAL_TABLES.channels).delete().eq('id', id)\n if (error) throw new Error(error.message)\n },\n\n async listExternalEvents(params) {\n const result = await invoke<{ events: ExternalEventPreview[] }>({\n action: 'list_external_events',\n channelId: params?.channelId,\n timeMin: params?.timeMin,\n })\n return result.events ?? []\n },\n\n async importEvents(items) {\n return invoke<ImportEventsResult>({ action: 'import_events', items })\n },\n }\n}\n","// What \"connected\" is not enough to tell you.\n//\n// A green badge only says a grant exists. The ways this connector actually\n// stops working are quieter: the last run errored, nothing has run in an hour,\n// no calendar is mapped to import from, or the Google watch that delivers\n// inbound changes has lapsed. Deriving them in one pure function means the\n// status badge (getStatus) and the panel say the same thing, and means the rule\n// is testable without a Google account.\nimport type { CalendarChannel, CalendarSyncLogEntry } from './types'\n\nexport type GoogleCalendarHealthStatus = 'disconnected' | 'healthy' | 'attention' | 'error'\n\nexport type GoogleCalendarHealthIssueCode =\n | 'sync_error'\n | 'sync_missing'\n | 'sync_stale'\n | 'inbound_channel_missing'\n | 'watch_missing'\n | 'watch_expiring'\n | 'timezone_mismatch'\n\nexport interface GoogleCalendarHealthIssue {\n code: GoogleCalendarHealthIssueCode\n detail?: string\n}\n\nexport interface GoogleCalendarHealth {\n status: GoogleCalendarHealthStatus\n issues: GoogleCalendarHealthIssue[]\n}\n\nexport function deriveGoogleCalendarHealth(input: {\n connected: boolean\n lastSyncAt?: string\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n calendarTimeZones?: string[]\n localTimeZone?: string\n now?: number\n staleAfterMs?: number\n renewBeforeMs?: number\n}): GoogleCalendarHealth {\n if (!input.connected) return { status: 'disconnected', issues: [] }\n\n const now = input.now ?? Date.now()\n const staleAfterMs = input.staleAfterMs ?? 45 * 60_000\n // Google watches expire in ~7 days; the platform's renewal clock is expected\n // to act a day out, so a shorter window than that is already a warning.\n const renewBeforeMs = input.renewBeforeMs ?? 24 * 60 * 60_000\n const issues: GoogleCalendarHealthIssue[] = []\n const latest = input.logs[0]\n\n if (latest && latest.status !== 'success' && latest.status !== 'skipped') {\n issues.push({ code: 'sync_error', detail: latest.error })\n }\n if (!input.lastSyncAt) {\n issues.push({ code: 'sync_missing' })\n } else {\n const lastSyncMs = new Date(input.lastSyncAt).getTime()\n if (!Number.isFinite(lastSyncMs) || lastSyncMs < now - staleAfterMs) {\n issues.push({ code: 'sync_stale', detail: input.lastSyncAt })\n }\n }\n\n const inbound = input.channels.filter(\n (channel) => channel.isActive && (channel.direction === 'inbound' || channel.direction === 'bidirectional'),\n )\n if (inbound.length === 0) issues.push({ code: 'inbound_channel_missing' })\n for (const channel of inbound) {\n if (!channel.channelId || !channel.resourceId || !channel.channelExpiresAt) {\n issues.push({ code: 'watch_missing', detail: channel.summary ?? channel.googleCalendarId })\n continue\n }\n const expiresAt = new Date(channel.channelExpiresAt).getTime()\n if (!Number.isFinite(expiresAt) || expiresAt <= now + renewBeforeMs) {\n issues.push({ code: 'watch_expiring', detail: channel.summary ?? channel.googleCalendarId })\n }\n }\n\n // A calendar in another timezone is not an error, but it is the single most\n // common reason an imported event lands \"three hours off\".\n const localTimeZone = input.localTimeZone\n const mismatchedTimeZones = [...new Set(input.calendarTimeZones ?? [])]\n .filter(Boolean)\n .filter((timeZone) => localTimeZone && timeZone !== localTimeZone)\n if (mismatchedTimeZones.length > 0) {\n issues.push({ code: 'timezone_mismatch', detail: mismatchedTimeZones.join(', ') })\n }\n\n return {\n status: issues.some((issue) => issue.code === 'sync_error')\n ? 'error'\n : issues.length > 0\n ? 'attention'\n : 'healthy',\n issues,\n }\n}\n","// What the connector's panel and its status badge both need, read once.\n//\n// It used to be read twice. The panel awaited `getIntegration()`, and then —\n// with that answer already in hand — called `readHealth()`, which awaited\n// `getIntegration()` again, plus a second `getSyncLog()` and a second\n// `listChannels()`. Sequential, so the transport's in-flight de-duplication\n// could not collapse them: the first request had already settled when the\n// second was issued. Three tables, six requests, for one screen.\n//\n// Extracted out of the component so the count is assertable without a DOM.\nimport { deriveGoogleCalendarHealth } from './health'\nimport type { GoogleCalendarHealth } from './health'\nimport type { CalendarChannel, CalendarIntegration, CalendarSyncLogEntry } from './types'\n\n/** The narrow slice of the provider this needs — a fake is three functions. */\nexport interface GoogleCalendarPanelSource {\n getIntegration(): Promise<CalendarIntegration | null>\n getSyncLog(): Promise<CalendarSyncLogEntry[]>\n listChannels(): Promise<CalendarChannel[]>\n}\n\nexport interface GoogleCalendarPanelData {\n integration: CalendarIntegration | null\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n health: GoogleCalendarHealth\n}\n\nfunction localTimeZone(): string | undefined {\n // The Google calendar's own timezone is not in the calendarList response the\n // function returns today, so timezone_mismatch stays dormant until it is.\n return typeof Intl !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : undefined\n}\n\n/** Derive health from rows the caller already holds. Pure — it never fetches. */\nexport function googleCalendarHealthOf(input: {\n integration: CalendarIntegration | null\n logs: CalendarSyncLogEntry[]\n channels: CalendarChannel[]\n}): GoogleCalendarHealth {\n if (!input.integration?.connected) return { status: 'disconnected', issues: [] }\n return deriveGoogleCalendarHealth({\n connected: true,\n lastSyncAt: input.integration.lastSyncAt,\n logs: input.logs,\n channels: input.channels,\n localTimeZone: localTimeZone(),\n })\n}\n\n/**\n * One read per table. Tolerant: a partial read still reports, and a\n * disconnected integration costs exactly one request.\n */\nexport async function readGoogleCalendarPanel(\n provider: GoogleCalendarPanelSource,\n): Promise<GoogleCalendarPanelData> {\n const integration = await provider.getIntegration().catch(() => null)\n if (!integration?.connected) {\n return { integration, logs: [], channels: [], health: { status: 'disconnected', issues: [] } }\n }\n const [logs, channels] = await Promise.all([\n provider.getSyncLog().catch(() => [] as CalendarSyncLogEntry[]),\n provider.listChannels().catch(() => [] as CalendarChannel[]),\n ])\n return { integration, logs, channels, health: googleCalendarHealthOf({ integration, logs, channels }) }\n}\n","// A small round swatch tinted with a Google calendar's backgroundColor.\n//\n// Google's calendarList entries carry a `backgroundColor` hex; we render it as a\n// dot next to the calendar summary in the de-para list and as the leading dot of\n// the origin badge in the import wizard. Falls back to the muted border when a\n// calendar has no color (rare, e.g. some shared calendars).\nimport React from 'react'\n\nexport function CalendarColorDot({\n color,\n className = '',\n}: {\n color?: string | null\n className?: string\n}) {\n return (\n <span\n className={`inline-block h-2.5 w-2.5 shrink-0 rounded-full border border-black/10 ${className}`}\n style={{ backgroundColor: color || 'hsl(var(--muted-foreground))' }}\n aria-hidden\n />\n )\n}\n","// Host-plugin lookups for the smart-sync de-para target picker.\n//\n// A channel can target one professional (assignee), one service, or one location\n// instead of the whole agenda. To offer real pickers (not raw uuid inputs) the\n// connector reuses plugin-agenda's own data providers — it lives inside the same\n// package, so these are in-process reads under the same RLS:\n// • professionals + locations → createSupabaseAgendaProvider()\n// • services → createSupabasePublicBookingProvider() (v_public_services)\n// Everything is loaded once, lazily, and degrades to an empty list (the row then\n// falls back to a plain uuid input) if a lookup is unavailable for the tenant.\nimport { useEffect, useState } from 'react'\nimport { getActiveTenantId } from '@fayz-ai/core'\nimport { createSupabaseAgendaProvider } from '../../../data'\nimport { createSupabasePublicBookingProvider } from '../../../public/data/supabase'\nimport type { ChannelTargetKind } from '../types'\n\n/** A pickable target option (assignee/service/location) — id + display name. */\nexport interface LookupOption {\n id: string\n name: string\n}\n\nexport interface AgendaLookups {\n assignee: LookupOption[]\n service: LookupOption[]\n location: LookupOption[]\n}\n\nconst EMPTY: AgendaLookups = { assignee: [], service: [], location: [] }\n\nexport interface UseAgendaLookupsResult {\n lookups: AgendaLookups\n loading: boolean\n /** True when at least one of the three lookups returned rows. */\n hasAny: boolean\n}\n\n/**\n * Load professionals / services / locations for the target picker. Failures are\n * swallowed per-lookup (each falls back to an empty list) so a missing table or\n * a vertical without services never breaks the whole de-para screen.\n */\nexport function useAgendaLookups(enabled: boolean): UseAgendaLookupsResult {\n const [lookups, setLookups] = useState<AgendaLookups>(EMPTY)\n const [loading, setLoading] = useState(false)\n\n useEffect(() => {\n if (!enabled) return\n let cancelled = false\n setLoading(true)\n void (async () => {\n const agenda = createSupabaseAgendaProvider()\n const tenantId = getActiveTenantId()\n const publicProvider = tenantId\n ? createSupabasePublicBookingProvider({ tenantId })\n : null\n\n const [assignee, location, service] = await Promise.all([\n agenda.getProfessionals().then(\n (rows) => rows.map((p) => ({ id: p.id, name: p.name })),\n () => [] as LookupOption[],\n ),\n (agenda.getLocations?.() ?? Promise.resolve([])).then(\n (rows) => rows.map((l) => ({ id: l.id, name: l.name })),\n () => [] as LookupOption[],\n ),\n (publicProvider?.getServices() ?? Promise.resolve([])).then(\n (rows) => rows.map((s) => ({ id: s.id, name: s.name })),\n () => [] as LookupOption[],\n ),\n ])\n\n if (cancelled) return\n setLookups({ assignee, service, location })\n setLoading(false)\n })()\n\n return () => {\n cancelled = true\n }\n }, [enabled])\n\n const hasAny =\n lookups.assignee.length > 0 ||\n lookups.service.length > 0 ||\n lookups.location.length > 0\n\n return { lookups, loading, hasAny }\n}\n\n/** Options available for a given target kind (empty for whole-agenda / null). */\nexport function optionsForKind(\n lookups: AgendaLookups,\n kind: ChannelTargetKind,\n): LookupOption[] {\n if (kind === 'assignee') return lookups.assignee\n if (kind === 'service') return lookups.service\n if (kind === 'location') return lookups.location\n return []\n}\n","// De-para (mapping) list — one row per Google calendar.\n//\n// Reads the user's Google calendars (listGoogleCalendars) and this tenant's\n// existing channels (listChannels), joins them by google_calendar_id, and lets\n// the user, per calendar:\n// • toggle sync on/off → creates/updates the channel (is_active)\n// • pick a direction → Two-way / Import only / Export only / Off\n// • pick a target → Whole agenda / Professional / Service / Location\n// • pick an import mode → Block / Appointment\n// Every change is persisted immediately via saveChannel (RLS upsert on\n// integration_id + google_calendar_id), snapshotting the calendar summary+color\n// onto the channel. Target ids come from real host lookups (useAgendaLookups);\n// if a lookup is empty for the tenant the row degrades to a raw uuid input.\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { Loader2, AlertCircle, RefreshCw } from 'lucide-react'\nimport {\n Button,\n Checkbox,\n Badge,\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n toast,\n} from '@fayz-ai/ui'\nimport type { GoogleCalendarProvider } from '../data/supabase'\nimport type {\n CalendarChannel,\n ChannelDirection,\n ChannelTargetKind,\n ChannelImportMode,\n GoogleCalendarListEntry,\n} from '../types'\nimport { CalendarColorDot } from './CalendarColorDot'\nimport { useAgendaLookups, optionsForKind } from './useAgendaLookups'\n\nconst DIRECTION_LABELS: Record<ChannelDirection, string> = {\n bidirectional: 'Two-way',\n inbound: 'Import only',\n outbound: 'Export only',\n off: 'Off',\n}\nconst IMPORT_MODE_LABELS: Record<ChannelImportMode, string> = {\n block: 'Block',\n appointment: 'Appointment',\n}\n// 'agenda' is the UI sentinel for the whole-agenda target (target_kind = null).\nconst TARGET_KIND_LABELS: Record<'agenda' | 'assignee' | 'service' | 'location', string> = {\n agenda: 'Whole agenda',\n assignee: 'Professional',\n service: 'Service',\n location: 'Location',\n}\nconst NO_TARGET = '__none__'\n\n/** Defaults for a freshly-enabled calendar (mirror the migration defaults). */\nfunction defaultChannel(): {\n direction: ChannelDirection\n targetKind: ChannelTargetKind\n targetId: string | null\n importMode: ChannelImportMode\n} {\n return { direction: 'bidirectional', targetKind: null, targetId: null, importMode: 'block' }\n}\n\nexport function ChannelMappingList({\n provider,\n onChannelsChange,\n}: {\n provider: GoogleCalendarProvider\n /** Bubble the current channels up so the parent can gate the import wizard. */\n onChannelsChange?: (channels: CalendarChannel[]) => void\n}) {\n const [calendars, setCalendars] = useState<GoogleCalendarListEntry[]>([])\n const [byGcalId, setByGcalId] = useState<Record<string, CalendarChannel>>({})\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [savingId, setSavingId] = useState<string | null>(null)\n\n const { lookups, hasAny: hasLookups } = useAgendaLookups(true)\n\n const load = useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const [cals, channels] = await Promise.all([\n provider.listGoogleCalendars(),\n provider.listChannels(),\n ])\n setCalendars(cals)\n const map: Record<string, CalendarChannel> = {}\n for (const ch of channels) map[ch.googleCalendarId] = ch\n setByGcalId(map)\n onChannelsChange?.(channels)\n } catch (e: any) {\n setError(e?.message ?? 'Could not load Google calendars')\n } finally {\n setLoading(false)\n }\n }, [provider, onChannelsChange])\n\n useEffect(() => {\n void load()\n }, [load])\n\n /** Persist a patch for one calendar, then refresh channels (keeps ids correct). */\n const persist = useCallback(\n async (\n cal: GoogleCalendarListEntry,\n patch: {\n direction?: ChannelDirection\n targetKind?: ChannelTargetKind\n targetId?: string | null\n importMode?: ChannelImportMode\n isActive?: boolean\n },\n ) => {\n const existing = byGcalId[cal.id]\n const base = existing ?? { ...defaultChannel(), isActive: true }\n setSavingId(cal.id)\n try {\n await provider.saveChannel({\n id: existing?.id,\n googleCalendarId: cal.id,\n summary: cal.summary,\n color: cal.backgroundColor ?? null,\n direction: patch.direction ?? base.direction,\n targetKind: patch.targetKind !== undefined ? patch.targetKind : base.targetKind,\n targetId: patch.targetId !== undefined ? patch.targetId : base.targetId ?? null,\n importMode: patch.importMode ?? base.importMode,\n isActive: patch.isActive !== undefined ? patch.isActive : base.isActive,\n })\n const channels = await provider.listChannels()\n const map: Record<string, CalendarChannel> = {}\n for (const ch of channels) map[ch.googleCalendarId] = ch\n setByGcalId(map)\n onChannelsChange?.(channels)\n } catch (e: any) {\n toast.error(e?.message ?? 'Could not save calendar mapping')\n } finally {\n setSavingId(null)\n }\n },\n [byGcalId, provider, onChannelsChange],\n )\n\n if (loading) {\n return (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin inline\" />\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"rounded-md border border-warning/40 bg-warning-soft/40 px-3 py-3 text-sm\">\n <div className=\"flex items-center gap-2 text-warning-soft-foreground\">\n <AlertCircle className=\"h-4 w-4\" /> {error}\n </div>\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => void load()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Retry\n </Button>\n </div>\n )\n }\n\n if (calendars.length === 0) {\n return (\n <p className=\"py-6 text-center text-sm text-muted-foreground\">\n No Google calendars found on this account.\n </p>\n )\n }\n\n return (\n <div className=\"rounded-md border divide-y\">\n {calendars.map((cal) => {\n const ch = byGcalId[cal.id]\n const active = !!ch?.isActive\n const saving = savingId === cal.id\n const direction: ChannelDirection = ch?.direction ?? 'bidirectional'\n const targetKind: ChannelTargetKind = ch?.targetKind ?? null\n const importMode: ChannelImportMode = ch?.importMode ?? 'block'\n // Import mode only matters when Google can write into the agenda.\n const canImport = direction === 'inbound' || direction === 'bidirectional'\n const kindOptions = optionsForKind(lookups, targetKind)\n\n return (\n <div key={cal.id} className=\"px-3 py-3 space-y-3\">\n <div className=\"flex items-center gap-2.5\">\n <Checkbox\n checked={active}\n disabled={saving}\n onChange={(next) => void persist(cal, { isActive: next })}\n />\n <CalendarColorDot color={cal.backgroundColor} />\n <span className=\"text-sm font-medium truncate\">{cal.summary}</span>\n {cal.primary && (\n <Badge variant=\"outline\" className=\"shrink-0\">\n Primary\n </Badge>\n )}\n {saving && <Loader2 className=\"ml-auto h-3.5 w-3.5 animate-spin text-muted-foreground\" />}\n </div>\n\n {active && (\n <div className=\"grid gap-2 pl-[26px] sm:grid-cols-2 lg:grid-cols-4\">\n {/* Direction */}\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Direction</span>\n <Select\n value={direction}\n onValueChange={(v) => void persist(cal, { direction: v as ChannelDirection })}\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(DIRECTION_LABELS) as ChannelDirection[]).map((d) => (\n <SelectItem key={d} value={d}>\n {DIRECTION_LABELS[d]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n\n {/* Target kind */}\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Target</span>\n <Select\n value={targetKind ?? 'agenda'}\n onValueChange={(v) =>\n void persist(cal, {\n targetKind: v === 'agenda' ? null : (v as ChannelTargetKind),\n // Reset the id whenever the kind changes.\n targetId: null,\n })\n }\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(TARGET_KIND_LABELS) as Array<keyof typeof TARGET_KIND_LABELS>).map(\n (k) => (\n <SelectItem key={k} value={k}>\n {TARGET_KIND_LABELS[k]}\n </SelectItem>\n ),\n )}\n </SelectContent>\n </Select>\n </label>\n\n {/* Target id — real picker when we have lookups, uuid input otherwise */}\n {targetKind && (\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">\n {TARGET_KIND_LABELS[targetKind]}\n </span>\n {kindOptions.length > 0 ? (\n <Select\n value={ch?.targetId ?? NO_TARGET}\n onValueChange={(v) =>\n void persist(cal, { targetId: v === NO_TARGET ? null : v })\n }\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue placeholder=\"Select…\" />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map((o) => (\n <SelectItem key={o.id} value={o.id}>\n {o.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <input\n defaultValue={ch?.targetId ?? ''}\n placeholder=\"uuid\"\n onBlur={(e) =>\n void persist(cal, { targetId: e.target.value.trim() || null })\n }\n className=\"w-full mt-1 h-8 rounded-input border border-input bg-card px-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n )}\n </label>\n )}\n\n {/* Import mode — only when inbound */}\n {canImport && (\n <label className=\"block\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">Import as</span>\n <Select\n value={importMode}\n onValueChange={(v) => void persist(cal, { importMode: v as ChannelImportMode })}\n >\n <SelectTrigger className=\"mt-1 h-8 text-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(IMPORT_MODE_LABELS) as ChannelImportMode[]).map((m) => (\n <SelectItem key={m} value={m}>\n {IMPORT_MODE_LABELS[m]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n )}\n </div>\n )}\n </div>\n )\n })}\n {!hasLookups && (\n <p className=\"px-3 py-2 text-[11px] text-muted-foreground\">\n No professional/service/location lookups available — target ids fall back to manual uuid\n entry.\n </p>\n )}\n </div>\n )\n}\n","// Import wizard — pull FUTURE Google events into the agenda as blocks/appointments.\n//\n// listExternalEvents() returns events on the active inbound channels that are not\n// yet linked to an appointment. The user ticks the ones to bring in and confirms;\n// importEvents() runs them through gcal_import_event (honouring each channel's\n// import_mode + target) and returns a per-item tally {imported, skipped, errors}.\n// Events show their source calendar as a colored badge and an \"All-day\" badge\n// when applicable; times are formatted pt-BR.\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Loader2, CalendarPlus, CheckCircle2, AlertCircle, RefreshCw, X } from 'lucide-react'\nimport { Button, Checkbox, Badge, toast } from '@fayz-ai/ui'\nimport type { GoogleCalendarProvider } from '../data/supabase'\nimport type { CalendarChannel, ExternalEventPreview, ImportEventsResult } from '../types'\nimport { CalendarColorDot } from './CalendarColorDot'\n\n/** pt-BR datetime label, all-day aware (date only for all-day events). */\nfunction formatWhen(ev: ExternalEventPreview): string {\n const start = new Date(ev.startsAt)\n if (ev.allDay) {\n return start.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })\n }\n return start.toLocaleString('pt-BR', {\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n })\n}\n\nexport function ImportEventsWizard({\n provider,\n channels,\n onClose,\n onImported,\n}: {\n provider: GoogleCalendarProvider\n /** Active channels — used to label each event with its source calendar + color. */\n channels: CalendarChannel[]\n onClose: () => void\n /** Fired after a successful import so the parent can refresh status/history. */\n onImported?: (result: ImportEventsResult) => void\n}) {\n const [events, setEvents] = useState<ExternalEventPreview[]>([])\n const [selected, setSelected] = useState<Set<string>>(new Set())\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const [importing, setImporting] = useState(false)\n const [result, setResult] = useState<ImportEventsResult | null>(null)\n\n const channelById = useMemo(() => {\n const m: Record<string, CalendarChannel> = {}\n for (const c of channels) m[c.id] = c\n return m\n }, [channels])\n\n const load = useCallback(async () => {\n setLoading(true)\n setError(null)\n setResult(null)\n try {\n const rows = await provider.listExternalEvents()\n setEvents(rows)\n setSelected(new Set(rows.map((r) => r.eventId)))\n } catch (e: any) {\n setError(e?.message ?? 'Could not load upcoming events')\n } finally {\n setLoading(false)\n }\n }, [provider])\n\n useEffect(() => {\n void load()\n }, [load])\n\n const toggle = (eventId: string) =>\n setSelected((prev) => {\n const next = new Set(prev)\n if (next.has(eventId)) next.delete(eventId)\n else next.add(eventId)\n return next\n })\n\n const allSelected = events.length > 0 && selected.size === events.length\n const toggleAll = () =>\n setSelected(allSelected ? new Set() : new Set(events.map((e) => e.eventId)))\n\n async function handleImport() {\n const items = events\n .filter((e) => selected.has(e.eventId))\n .map((e) => ({ channelId: e.channelId, eventId: e.eventId }))\n if (items.length === 0) return\n setImporting(true)\n try {\n const res = await provider.importEvents(items)\n setResult(res)\n onImported?.(res)\n toast.success(`Imported ${res.imported} · skipped ${res.skipped}`)\n // Drop imported events from the list so the wizard reflects the new state.\n await load()\n } catch (e: any) {\n toast.error(e?.message ?? 'Import failed')\n } finally {\n setImporting(false)\n }\n }\n\n return (\n <div className=\"rounded-card border bg-card\">\n <div className=\"flex items-center gap-2 border-b px-3 py-2\">\n <CalendarPlus className=\"h-4 w-4 text-muted-foreground\" />\n <h4 className=\"text-sm font-semibold\">Import future events</h4>\n <button\n onClick={onClose}\n className=\"ml-auto rounded p-1 text-muted-foreground hover:bg-muted/50\"\n aria-label=\"Close\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n {loading ? (\n <div className=\"py-8 text-center text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin inline\" />\n </div>\n ) : error ? (\n <div className=\"p-3\">\n <div className=\"flex items-center gap-2 text-sm text-warning-soft-foreground\">\n <AlertCircle className=\"h-4 w-4\" /> {error}\n </div>\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => void load()}>\n <RefreshCw className=\"h-3.5 w-3.5\" /> Retry\n </Button>\n </div>\n ) : events.length === 0 ? (\n <div className=\"py-8 px-4 text-center space-y-1\">\n <p className=\"text-sm font-medium\">You're all caught up</p>\n <p className=\"text-xs text-muted-foreground\">\n No upcoming Google events left to import on your active calendars.\n </p>\n {result && (\n <p className=\"text-xs text-success\">\n Imported {result.imported} · skipped {result.skipped}\n {result.errors.length > 0 ? ` · ${result.errors.length} errors` : ''}\n </p>\n )}\n </div>\n ) : (\n <>\n <div className=\"flex items-center gap-2.5 border-b px-3 py-2\">\n <Checkbox checked={allSelected} onChange={toggleAll} />\n <span className=\"text-xs text-muted-foreground\">\n {selected.size} of {events.length} selected\n </span>\n </div>\n <div className=\"max-h-[320px] overflow-y-auto divide-y\">\n {events.map((ev) => {\n const ch = channelById[ev.channelId]\n return (\n <label\n key={ev.eventId}\n className=\"flex items-start gap-2.5 px-3 py-2.5 cursor-pointer hover:bg-muted/30\"\n >\n <Checkbox\n checked={selected.has(ev.eventId)}\n onChange={() => toggle(ev.eventId)}\n />\n <div className=\"min-w-0 flex-1 space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">\n {ev.summary || '(no title)'}\n </span>\n {ev.allDay && (\n <Badge variant=\"secondary\" className=\"shrink-0\">\n All-day\n </Badge>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{formatWhen(ev)}</span>\n <span className=\"inline-flex items-center gap-1\">\n <CalendarColorDot color={ch?.color} />\n {ch?.summary ?? ev.calendarId}\n </span>\n </div>\n </div>\n </label>\n )\n })}\n </div>\n <div className=\"flex items-center gap-2 border-t px-3 py-2\">\n {result && (\n <span className=\"text-xs text-muted-foreground\">\n Last run: {result.imported} imported\n {result.errors.length > 0 ? `, ${result.errors.length} errors` : ''}\n </span>\n )}\n <Button\n size=\"sm\"\n className=\"ml-auto\"\n disabled={importing || selected.size === 0}\n onClick={handleImport}\n >\n {importing ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n )}\n Import {selected.size > 0 ? selected.size : ''}\n </Button>\n </div>\n </>\n )}\n </div>\n )\n}\n","// Google Calendar as a unified ConnectorDefinition.\n//\n// Surfaces inside plugin-agenda's settings → Integrations tab (the host),\n// rendered by the shared ConnectorsHub. The hub handles the OAuth connect/\n// disconnect; what is left here is declared through the four seams the hub\n// renders in four different places, because they are four different questions:\n//\n// getStatus().issues → Visão geral what is wrong right now\n// listRuns → Sincronizações what has already happened\n// syncActions → Sincronizações sync now, import future events\n// ExtraPanel → Configurações the de-para, and nothing else\n//\n// All four used to be one `ExtraPanel` on the settings tab — health warnings, a\n// calendar mapping, an import wizard and a run log stacked under a heading that\n// said \"Configurações\". That is what the founder called *bem ruim e estranho\n// junto na tela de settings direto*, and none of it was a rendering problem: the\n// panel was the only seam there was, so everything arrived through it.\nimport React, { useEffect, useState } from 'react'\nimport type { ConnectorDefinition, SyncRun, SyncTrigger } from '@fayz-ai/core'\nimport { connectionStatus, createConnectionStore } from '@fayz-ai/core'\nimport { fayzConnectorOAuth } from '@fayz-ai/admin'\nimport { createGoogleCalendarProvider } from './data/supabase'\nimport { readGoogleCalendarPanel } from './panel-data'\nimport type { GoogleCalendarHealth, GoogleCalendarHealthIssueCode } from './health'\nimport type { CalendarChannel, CalendarSyncLogEntry } from './types'\nimport { ChannelMappingList } from './components/ChannelMappingList'\nimport { ImportEventsWizard } from './components/ImportEventsWizard'\n\nconst provider = createGoogleCalendarProvider()\n\nexport const GOOGLE_CALENDAR_CONNECTOR_ID = 'google-calendar'\n\n/**\n * \"Is Google Calendar on for this tenant?\" — asked of `connections`, the\n * one table every connector answers it from.\n *\n * It used to be asked of `plg_calendar_integrations.token_expires_at`: a\n * timestamp stamped whenever a token was stored, which meant the answer was a\n * by-product of the credential living in this pool. The credential is in the\n * platform vault now, so that column is gone (migration 007) and so is the\n * question it answered.\n */\nexport const googleCalendarConnectionStore = () =>\n createConnectionStore(GOOGLE_CALENDAR_CONNECTOR_ID, {\n settingsKeys: ['calendarId'],\n })\n\n// Product copy: what each derived issue means to the person reading the badge.\nconst HEALTH_LABELS: Record<GoogleCalendarHealthIssueCode, string> = {\n sync_error: 'a última sincronização falhou',\n sync_missing: 'nenhuma sincronização foi feita ainda',\n sync_stale: 'sem sincronizar há mais de uma hora',\n inbound_channel_missing: 'nenhuma agenda do Google está marcada para importar',\n watch_missing: 'o aviso automático do Google não está ativo',\n watch_expiring: 'o aviso automático do Google está prestes a expirar',\n timezone_mismatch: 'o fuso horário do Google é diferente do seu',\n}\n\n/** One issue as a sentence. */\nfunction issueLine(issue: GoogleCalendarHealth['issues'][number]): string {\n const label = HEALTH_LABELS[issue.code]\n return issue.detail ? `${label} (${issue.detail})` : label\n}\n\n/** One line for the status badge — the first thing wrong, or that all is well. */\nfunction healthDetail(health: GoogleCalendarHealth): string | undefined {\n if (health.status === 'disconnected') return undefined\n if (health.status === 'healthy') return 'Sincronizando normalmente'\n return issueLine(health.issues[0])\n}\n\n/** Read everything the health rule needs. Tolerant: a partial read still reports. */\nasync function readHealth(): Promise<GoogleCalendarHealth> {\n return (await readGoogleCalendarPanel(provider)).health\n}\n\n/** Channels Google is allowed to write INTO the agenda from (gate the import wizard). */\nfunction inboundChannels(channels: CalendarChannel[]): CalendarChannel[] {\n return channels.filter(\n (c) => c.isActive && (c.direction === 'inbound' || c.direction === 'bidirectional'),\n )\n}\n\n/** The four words the column holds (migrations/001); anything else is a manual run. */\nconst TRIGGERS: readonly SyncTrigger[] = ['on-write', 'scheduled', 'manual', 'webhook']\n\n/**\n * This connector's own log, in the one shape the shared history renders.\n *\n * `plg_calendar_sync_log` predates `sync_runs` and still holds the rows, so\n * the mapping is here rather than a migration nobody needs yet — what the\n * surface asked for is a {@link SyncRun}, not a table.\n */\nfunction toSyncRun(entry: CalendarSyncLogEntry): SyncRun {\n return {\n connectionId: '',\n connectorId: 'google-calendar',\n direction: entry.direction === 'inbound' ? 'inbound' : 'outbound',\n triggerKind: TRIGGERS.includes(entry.trigger as SyncTrigger) ? (entry.trigger as SyncTrigger) : 'manual',\n status: entry.status === 'success' || entry.status === 'partial' || entry.status === 'running'\n ? entry.status\n : 'error',\n id: entry.id,\n fetched: entry.fetched,\n written: entry.written,\n error: entry.error ?? null,\n startedAt: entry.createdAt,\n }\n}\n\n/**\n * The de-para, and nothing else — the Configurações tab.\n *\n * Which Google calendar feeds which professional IS configuration: it is chosen\n * once, changed on a Tuesday in March, and never \"finished\". Everything that\n * used to sit above and below it in this component was not — a health warning is\n * status, an import is an act, a run log is history, and each of them now\n * arrives through the seam that renders it where it belongs.\n */\nfunction GoogleCalendarMapping() {\n const [connected, setConnected] = useState(false)\n const [loaded, setLoaded] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n void provider\n .getIntegration()\n .then((i) => { if (!cancelled) setConnected(!!i?.connected) })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoaded(true) })\n return () => { cancelled = true }\n }, [])\n\n if (!loaded || !connected) return null\n\n return (\n <div className=\"space-y-2\">\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n Diga o que cada agenda do Google sincroniza — um profissional, um serviço, um local, ou a\n sua agenda inteira. Cada mudança é salva na hora.\n </p>\n <ChannelMappingList provider={provider} />\n </div>\n )\n}\n\n/**\n * The import, as the shared surface opens it. The wizard is untouched — what\n * went away is the button, the spinner and the toast around it.\n */\nfunction GoogleCalendarImport({ onClose, onRan }: { onClose(): void; onRan?(): void }) {\n const [channels, setChannels] = useState<CalendarChannel[]>([])\n\n useEffect(() => {\n let cancelled = false\n void provider\n .listChannels()\n .then((ch) => { if (!cancelled) setChannels(ch) })\n .catch(() => {})\n return () => { cancelled = true }\n }, [])\n\n return (\n <ImportEventsWizard\n provider={provider}\n channels={inboundChannels(channels)}\n onClose={onClose}\n onImported={() => onRan?.()}\n />\n )\n}\n\nexport const googleCalendarConnectorDef: ConnectorDefinition = {\n id: 'google-calendar',\n hostPluginId: 'agenda',\n name: 'Google Calendar',\n description: 'Two-way sync between your bookings and Google Calendar.',\n icon: 'Calendar',\n authKind: 'oauth',\n category: 'scheduling',\n // `direction` is who reaches for whom: this app reaches Google (consent, push,\n // pull). The data being BIDIRECTIONAL is a property of the entity, and is\n // declared where the type allows it — see ./connector.ts, capability\n // `booking: 'bidirectional'`.\n direction: 'outbound',\n // Sync only, and deliberately: the agenda has to exist inside the app — to be\n // listed, filtered, reported on, and read when Google is unreachable. An\n // agentic plane would answer questions but leave the calendar screen empty.\n planes: ['sync'],\n docsUrl: 'https://support.google.com/calendar',\n // What it needs, grounded in what the data plane actually does. `booking` is\n // read AND written: the pull path lands external events through the\n // `gcal_import_event` / `gcal_apply_event_patch` RPCs (migrations/002 §\n // \"import\"), which INSERT and UPDATE public.appointments, and the push path\n // reads the appointment plus its items to compose the Google event.\n //\n // Marked sensitive because of what leaves the tenant, not because of the row\n // count: the event title is \"<serviços> — <nome do cliente>\" and the\n // description carries the appointment notes (./mapping.ts). Someone\n // authorizing this is sending client names and visit notes to Google, and that\n // is the fact the consent view exists to put in front of them.\n permissions: [\n {\n kind: 'data',\n resource: 'booking',\n actions: ['read', 'write'],\n reason:\n 'Ler os agendamentos para criar os eventos no Google, e gravar aqui os eventos que você criar por lá. Nome do cliente, serviços e observações vão no evento.',\n sensitive: true,\n },\n // The three facts that change what Google should show, and only those.\n // `booking_completed`/`booking_no_show` are left out because Google has no\n // notion of either and the event does not move; `booking_reminder` likewise.\n {\n kind: 'event',\n resource: 'agenda.booking_created',\n actions: ['listen'],\n reason: 'Saber que um horário foi marcado, para criar o evento no Google Calendar.',\n },\n {\n kind: 'event',\n resource: 'agenda.booking_rescheduled',\n actions: ['listen'],\n reason: 'Saber que um horário mudou, para mover o evento no Google Calendar.',\n },\n {\n kind: 'event',\n resource: 'agenda.booking_cancelled',\n actions: ['listen'],\n reason: 'Saber que um agendamento foi cancelado, para apagar o evento do Google Calendar.',\n },\n ],\n // Keys copied from ../../lib/message-events.ts, which is where the agenda\n // declares them.\n //\n // `agenda.booking_completed` and `agenda.booking_no_show` are left out on\n // purpose: Google has no notion of either, and the event does not move, so\n // waking the connector for them is a round-trip that changes nothing.\n // `agenda.booking_reminder` is left out for the same reason — a reminder is\n // not a change to the calendar.\n //\n // Deletion is missing because the agenda declares no `booking_deleted` fact;\n // a hard delete is delivered by the trigger in migrations/004, not by an\n // event. That asymmetry is real and is written down in ./GOOGLE-CALENDAR.md.\n subscribesTo: [\n 'agenda.booking_created',\n 'agenda.booking_rescheduled',\n 'agenda.booking_cancelled',\n ],\n // These are not preferences someone chose — they are what the integration IS,\n // so they appear only while the connection is live and disconnecting is the\n // way out. Today the trigger in migrations/004 delivers them; when the Fayz\n // ingress lands it takes over the same three, which is what makes that swap a\n // configuration change instead of a rewrite.\n managedAutomations: [\n { eventKey: 'agenda.booking_created', label: 'Criar o evento no Google Calendar quando um horário é agendado aqui' },\n { eventKey: 'agenda.booking_rescheduled', label: 'Mover o evento no Google Calendar quando o horário é remarcado' },\n { eventKey: 'agenda.booking_cancelled', label: 'Apagar o evento do Google Calendar quando o agendamento é cancelado' },\n ],\n // The two moments that DO exist in code, as opposed to the three above, which\n // are delivered by the trigger in migrations/004 rather than by an ingress.\n // Both are sync moments and both reach `booking`, which is what `touches`\n // says — the connector cannot name a resource it did not ask for.\n invokedAt: [\n {\n key: 'agenda.booking.push',\n label: 'Um horário é criado, remarcado ou cancelado aqui, e o evento é atualizado no Google',\n plane: 'sync',\n trigger: 'on-write',\n touches: ['booking'],\n },\n {\n key: 'agenda.calendar.pull',\n label: 'O Google avisa que algo mudou por lá, e os eventos são trazidos para cá',\n plane: 'sync',\n trigger: 'webhook',\n touches: ['booking'],\n },\n ],\n /**\n * The LIST row, from the connection the hub already batched — one request for\n * N connectors, and no calendar read at all.\n */\n ...connectionStatus(\n GOOGLE_CALENDAR_CONNECTOR_ID,\n (connection) => (connection?.active ? { connected: true, plane: 'sync' } : { connected: false }),\n { store: googleCalendarConnectionStore },\n ),\n /**\n * The DETAIL screen, where health is worth a round-trip.\n *\n * Two questions, in order, and they are not the same one: `connections`\n * says whether the clinic authorized Google, and ./health.ts says whether the\n * sync is actually working. Asking only the second is what let a connection\n * read as \"conectado\" off a token timestamp; asking only the first would\n * report a healthy connector that has not synced since Tuesday.\n */\n async getStatus() {\n try {\n const connection = await googleCalendarConnectionStore().get()\n if (!connection?.active) return { connected: false }\n\n const health = await readHealth()\n // `detail` is the one line a row has room for; `issues` is all of them,\n // for the detail screen. A connection can be unwell in three ways at once.\n return {\n connected: true,\n plane: 'sync',\n detail: healthDetail(health),\n issues: health.issues.map(issueLine),\n }\n } catch {\n return { connected: false }\n }\n },\n // Consent runs on the platform: it holds the Google client pair, takes the\n // callback and puts the grant in the vault. This pool used to do all three.\n startOAuth: fayzConnectorOAuth(GOOGLE_CALENDAR_CONNECTOR_ID),\n /**\n * The other half of the consent. The platform stores the grant; the pool\n * stores \"is it on?\", and with nobody writing the second the connector would\n * answer \"não conectado\" to a clinic that had just authorized Google.\n *\n * Called with no values — the credential is not ours to see.\n */\n saveConnection: async () => {\n // The sync state row first: a channel FKs to it, so a connection saved\n // without one is a connector that says \"conectado\" and cannot map a single\n // calendar. It used to be created as a side effect of storing the token.\n await provider.ensureIntegration()\n await googleCalendarConnectionStore().save({ active: true })\n },\n /**\n * Three things end a connection, and only the first is this pool's:\n * the row flips inactive (here)\n * the watches are stopped at Google and the cursors cleared (the function)\n * the grant is revoked (the platform — it holds the token)\n *\n * The function call is best-effort on purpose: a clinic that already revoked\n * us at Google gets a 409 from it, and refusing to disconnect over that would\n * leave the connector on with no way to turn it off.\n */\n disconnect: async () => {\n try {\n await provider.disconnect()\n } catch {\n /* Google already gone, or the pool's watches were never opened */\n }\n await googleCalendarConnectionStore().disconnect()\n },\n // Disconnecting stops the traffic; it does not undo it. Said here because the\n // question is only ever asked next to the button.\n disconnectNote:\n 'Desconectar para a sincronização nos dois sentidos. Os agendamentos já importados continuam aqui, e os eventos já criados continuam no Google.',\n async listRuns(options) {\n try {\n const log = await provider.getSyncLog()\n const runs = log.map(toSyncRun)\n return options?.limit ? runs.slice(0, options.limit) : runs\n } catch {\n return []\n }\n },\n // Declared, not drawn — the same seam Bling uses. Behaviour unchanged.\n syncActions: [\n {\n key: 'sync_now',\n label: 'Sincronizar agora',\n direction: 'inbound',\n run: async () => {\n const result = await provider.syncNow()\n return `Sincronizado — ${result.written} atualizados`\n },\n },\n {\n key: 'import_events',\n label: 'Importar eventos futuros',\n direction: 'inbound',\n // Hidden rather than disabled: nothing to bring in, and a greyed control\n // reads as something the reader failed to do.\n available: async () => {\n try {\n return inboundChannels(await provider.listChannels()).length > 0\n } catch {\n return false\n }\n },\n Component: GoogleCalendarImport,\n run: async () => {},\n },\n ],\n ExtraPanel: GoogleCalendarMapping,\n}\n","// AUTO-GENERATED from 001_google_calendar.sql, 002_smart_sync.sql, 003_plg_rename.sql, 004_drop_oauth_tokens.sql, 005_outbound_vault_delivery.sql, 006_webhook_deliveries_outbox.sql, 007_credential_free_install.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_001_GOOGLE_CALENDAR = `-- ---------------------------------------------------------------------------\n-- Google Calendar integration (bidirectional) — connection + audit + triggers\n-- ---------------------------------------------------------------------------\n-- Outbound (Fayz booking → Google event) fires from a trigger on public.appointments\n-- via pg_net to the google-calendar-sync edge function (push_event). Inbound\n-- (Google → booking) runs on a pg_cron schedule (pull_events) and/or a Google\n-- watch-channel webhook. The booking↔event link is stored on\n-- public.appointments.metadata.googleCalendarEventId (no schema change there).\n\n-- Plugin-owned tables carry the platform \\`plg_<plugin>_\\` prefix (DATA-MODEL.md\n-- Ring 1). Legacy pools provisioned under the old \\`calendar_*\\` names are migrated\n-- by 003_plg_rename.sql; fresh installs are born with the prefixed names here.\nCREATE TABLE IF NOT EXISTS public.plg_calendar_integrations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n provider text NOT NULL DEFAULT 'google',\n oauth_refresh_token text,\n oauth_access_token text,\n token_expires_at timestamptz,\n calendar_id text NOT NULL DEFAULT 'primary',\n -- Incremental pull cursor + Google watch channel bookkeeping.\n sync_token text,\n channel_id text,\n channel_resource_id text,\n channel_expires_at timestamptz,\n active boolean NOT NULL DEFAULT true,\n last_sync_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, provider)\n);\nALTER TABLE public.plg_calendar_integrations ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_integrations_tenant ON public.plg_calendar_integrations(tenant_id);\n\nCREATE TABLE IF NOT EXISTS public.plg_calendar_sync_log (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n direction text NOT NULL, -- inbound | outbound\n trigger text, -- on-write | scheduled | webhook | manual\n status text NOT NULL DEFAULT 'success', -- success | partial | error\n fetched integer NOT NULL DEFAULT 0,\n written integer NOT NULL DEFAULT 0,\n error text,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_calendar_sync_log ENABLE ROW LEVEL SECURITY;\n\n-- RLS: tenant isolation.\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY['plg_calendar_integrations','plg_calendar_sync_log'])\n LOOP\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_rls') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids())) WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_rls', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- ---------------------------------------------------------------------------\n-- Outbound trigger: booking change → edge function (push_event).\n-- Requires pg_net + a configured function URL. Set once per project:\n-- ALTER DATABASE postgres SET app.gcal_sync_url = 'https://<ref>.functions.supabase.co/google-calendar-sync';\n-- ALTER DATABASE postgres SET app.gcal_service_key = '<service-role-key>';\n-- Safe to skip in environments without pg_net — outbound also works via the\n-- client-side withGoogleCalendarSync() decorator.\n-- ---------------------------------------------------------------------------\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql SECURITY DEFINER AS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\nBEGIN\n IF url IS NULL OR url = '' THEN RETURN COALESCE(NEW, OLD); END IF;\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object('Content-Type', 'application/json', 'Authorization', 'Bearer ' || COALESCE(key, '')),\n body := jsonb_build_object('action', 'push_event', 'op', op, 'bookingId', rec.id, 'tenantId', rec.tenant_id)\n );\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\nDROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;\nCREATE TRIGGER trg_gcal_push\n AFTER INSERT OR UPDATE OR DELETE ON public.appointments\n FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();\n\n-- Inbound schedule (optional): pull external changes every 10 minutes.\n-- SELECT cron.schedule('gcal-pull', '*/10 * * * *', $$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object('Content-Type','application/json','Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events'));\n-- $$);\n`\n\nexport const MIGRATION_002_SMART_SYNC = `-- ---------------------------------------------------------------------------\n-- Google Calendar SMART SYNC — multi-calendar de-para + loop-safe two-way sync\n-- ---------------------------------------------------------------------------\n-- Builds on 001_google_calendar.sql. Where 001 modelled a single calendar per\n-- tenant (plg_calendar_integrations, one outbound trigger, a pull template), 002\n-- makes the sync vertical-agnostic and bidirectional-safe:\n--\n-- §1 public.plg_calendar_channels — de-para: one Google calendar → one sync\n-- target (whole tenant / assignee / service\n-- / location), per direction + import mode\n-- §2 fn_gcal_push_booking (REPLACE)— loop-prevention guard + correlation id\n-- §3 plg_calendar_sync_log — correlation_id + channel_id_ref columns\n-- §4 inbound write functions — the ONLY path Google→booking writes take\n-- (gcal_import_event / gcal_apply_event_patch\n-- / gcal_unlink_channel), SECURITY DEFINER,\n-- service_role-only\n-- §5 get_available_slots (REPLACE) — tenant-wide imported blocks now also\n-- remove slots for every professional\n-- §6 pg_cron template — per-channel pull\n--\n-- Idempotent / re-runnable: IF NOT EXISTS, CREATE OR REPLACE, DROP … IF EXISTS.\n-- Written against the canonical public names (appointments uses starts_at/ends_at,\n-- metadata jsonb, party_id/assignee_id — see packages/db 004_archetypes.sql).\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — plg_calendar_channels: multi-calendar de-para (vertical-agnostic)\n-- target_kind NULL → whole tenant agenda (agency-os): every professional\n-- target_kind 'assignee' → calendar maps to one professional (school: teacher)\n-- target_kind 'service' | 'location' → clinic-style mapping\n-- import_mode 'block' → inbound events become opaque busy blocks\n-- import_mode 'appointment' → inbound events become real appointments\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_channels (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n integration_id uuid NOT NULL REFERENCES public.plg_calendar_integrations(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL,\n google_calendar_id text NOT NULL,\n summary text,\n color text,\n direction text NOT NULL DEFAULT 'bidirectional'\n CHECK (direction IN ('inbound','outbound','bidirectional','off')),\n target_kind text CHECK (target_kind IN ('assignee','service','location')),\n target_id uuid,\n import_mode text NOT NULL DEFAULT 'block'\n CHECK (import_mode IN ('block','appointment')),\n sync_token text,\n channel_id text,\n resource_id text,\n channel_expires_at timestamptz,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (integration_id, google_calendar_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_tenant ON public.plg_calendar_channels(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_integration ON public.plg_calendar_channels(integration_id);\n\nALTER TABLE public.plg_calendar_channels ENABLE ROW LEVEL SECURITY;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_channels TO authenticated;\n-- service_role bypasses RLS, but this table is born after 004's blanket grant,\n-- so grant it explicitly (the inbound functions run as definer/service_role).\nGRANT ALL ON public.plg_calendar_channels TO service_role;\n\nDROP TRIGGER IF EXISTS plg_calendar_channels_updated_at ON public.plg_calendar_channels;\nCREATE TRIGGER plg_calendar_channels_updated_at BEFORE UPDATE ON public.plg_calendar_channels\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\n-- RLS: tenant isolation (padrão 001) + explicit service_role FOR ALL policy\n-- (matches the vigente service_role policy pattern from 001_core payment_events).\nDROP POLICY IF EXISTS plg_calendar_channels_rls ON public.plg_calendar_channels;\nCREATE POLICY plg_calendar_channels_rls ON public.plg_calendar_channels\n FOR ALL TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()))\n WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()));\n\nDROP POLICY IF EXISTS plg_calendar_channels_service ON public.plg_calendar_channels;\nCREATE POLICY plg_calendar_channels_service ON public.plg_calendar_channels\n FOR ALL TO service_role USING (true) WITH CHECK (true);\n\n-- ===========================================================================\n-- §2 — Outbound trigger with loop-prevention + correlation id.\n-- CREATE OR REPLACE of 001's fn_gcal_push_booking. Same pg_net → edge function\n-- payload (app.gcal_sync_url / app.gcal_service_key), but now:\n-- * SKIP the push when the write itself came from the Google sync, detected by\n-- the TRANSACTION-LOCAL GUC app.booking_origin = 'google' — set by every §4\n-- writer via set_config(..., true) and gone when the transaction ends.\n-- This is what stops the Google→booking→Google→… echo loop.\n-- Deliberately NOT a persistent metadata check: a sticky marker\n-- (metadata.syncOrigin) would permanently mute pushes for imported events,\n-- so a later admin edit would never reach Google. metadata.syncOrigin is\n-- kept by §4 as provenance only — this trigger does not read it.\n-- * carry a correlation_id so both directions can be stitched in the sync log\n-- (from GUC app.booking_correlation_id, else a fresh uuid — design ported\n-- from PR #7).\n-- ===========================================================================\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql SECURITY DEFINER AS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- Loop guard: never bounce a Google-originated write back to Google.\n -- Transaction-local GUC only (see §2 header for why not persistent metadata).\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n IF url IS NULL OR url = '' THEN RETURN COALESCE(NEW, OLD); END IF;\n\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object('Content-Type', 'application/json',\n 'Authorization', 'Bearer ' || COALESCE(key, '')),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- Re-assert the trigger (idempotent; unchanged from 001).\nDROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;\nCREATE TRIGGER trg_gcal_push\n AFTER INSERT OR UPDATE OR DELETE ON public.appointments\n FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();\n\n-- ===========================================================================\n-- §3 — sync log: correlate the two directions + reference the source channel.\n-- ===========================================================================\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS correlation_id uuid;\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS channel_id_ref uuid\n REFERENCES public.plg_calendar_channels(id) ON DELETE SET NULL;\n-- Unlinked future events seen during a pull (import-wizard candidates), so the\n-- log can show \"N eventos aguardando import\" without re-hitting Google.\nALTER TABLE public.plg_calendar_sync_log\n ADD COLUMN IF NOT EXISTS discovered integer;\n\n-- ===========================================================================\n-- §4 — Inbound write path (Google → booking). THE single entry point used by\n-- the edge function (scheduled pull, webhook, and the import wizard). All three\n-- functions are SECURITY DEFINER with SET search_path = public and are granted\n-- to service_role ONLY (anon/authenticated explicitly revoked) — they bypass the\n-- tenant RLS on purpose and must never be reachable from the anon/authenticated\n-- PostgREST surface. Every writer sets the TRANSACTION-LOCAL GUC\n-- app.booking_origin='google' (set_config ..., true) so §2's trigger suppresses\n-- the echo for THIS write only; metadata.syncOrigin is provenance, not a guard.\n-- ===========================================================================\n\n-- gcal_import_event: create (or idempotently update) a booking from a Google\n-- event, honouring the channel's import_mode + target mapping.\n-- kind = 'block' | 'appointment' (from channel.import_mode)\n-- assignee_id = channel.target_id when target_kind='assignee', else NULL\n-- (NULL = tenant-wide → blocks every professional, see §5)\n-- location_id = channel.target_id when target_kind='location', else NULL\n-- status = 'scheduled'\n-- No order is created — an external import is not a sale. Idempotent on\n-- (tenant_id, metadata.googleCalendarEventId): update in place if seen before.\nCREATE OR REPLACE FUNCTION public.gcal_import_event(\n p_tenant_id uuid,\n p_channel_id uuid,\n p_event_id text,\n p_etag text,\n p_summary text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_all_day boolean,\n p_description text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_ch record;\n v_kind text;\n v_assignee uuid;\n v_location uuid;\n v_ends timestamptz;\n v_meta jsonb;\n v_existing uuid;\n v_appt uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL OR p_starts_at IS NULL THEN\n RAISE EXCEPTION 'gcal_import_event: tenant, event id and start are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n -- Resolve the channel mapping (must belong to the same tenant).\n SELECT c.import_mode, c.target_kind, c.target_id\n INTO v_ch\n FROM plg_calendar_channels c\n WHERE c.id = p_channel_id AND c.tenant_id = p_tenant_id;\n IF NOT FOUND THEN RAISE EXCEPTION 'gcal_import_event: unknown channel for tenant'; END IF;\n\n v_kind := CASE WHEN v_ch.import_mode = 'appointment' THEN 'appointment' ELSE 'block' END;\n v_assignee := CASE WHEN v_ch.target_kind = 'assignee' THEN v_ch.target_id ELSE NULL END;\n v_location := CASE WHEN v_ch.target_kind = 'location' THEN v_ch.target_id ELSE NULL END;\n\n -- All-day events without an explicit end block the whole day so §5 excludes it.\n v_ends := COALESCE(\n p_ends_at,\n CASE WHEN COALESCE(p_all_day, false) THEN p_starts_at + interval '1 day' ELSE p_starts_at END\n );\n\n v_meta := jsonb_build_object(\n 'syncOrigin', 'google',\n 'googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalChannelId', p_channel_id::text,\n 'allDay', COALESCE(p_all_day, false),\n 'title', p_summary,\n 'source', 'google_import'\n );\n\n -- Idempotency: has this event already been imported for the tenant?\n SELECT b.id INTO v_existing\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_existing IS NOT NULL THEN\n UPDATE appointments b\n SET kind = v_kind,\n assignee_id = v_assignee,\n location_id = v_location,\n starts_at = p_starts_at,\n ends_at = v_ends,\n status = 'scheduled',\n notes = COALESCE(p_description, p_summary),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || v_meta,\n updated_at = now()\n WHERE b.id = v_existing\n RETURNING b.id INTO v_appt;\n ELSE\n INSERT INTO appointments (tenant_id, kind, assignee_id, location_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, v_kind, v_assignee, v_location,\n p_starts_at, v_ends, 'scheduled', COALESCE(p_description, p_summary), v_meta)\n RETURNING id INTO v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\n-- gcal_apply_event_patch: apply an inbound reschedule/cancel to an already-linked\n-- booking. Located by metadata.googleCalendarEventId. Echo suppression: if the\n-- stored gcalEtag already equals the incoming etag, this is our own write coming\n-- back — skip and return NULL. Every real write re-stamps syncOrigin='google'.\nCREATE OR REPLACE FUNCTION public.gcal_apply_event_patch(\n p_tenant_id uuid,\n p_event_id text,\n p_etag text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_summary text,\n p_cancelled boolean\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_appt uuid;\n v_curr_etag text;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_apply_event_patch: tenant and event id are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT b.id, b.metadata->>'gcalEtag'\n INTO v_appt, v_curr_etag\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_appt IS NULL THEN RETURN NULL; END IF; -- not linked here\n IF p_etag IS NOT NULL AND p_etag = v_curr_etag THEN\n RETURN NULL; -- echo: nothing changed\n END IF;\n\n IF COALESCE(p_cancelled, false) THEN\n UPDATE appointments b\n SET status = 'cancelled',\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google', 'gcalEtag', p_etag),\n updated_at = now()\n WHERE b.id = v_appt;\n ELSE\n UPDATE appointments b\n SET starts_at = COALESCE(p_starts_at, b.starts_at),\n ends_at = COALESCE(p_ends_at, b.ends_at),\n notes = COALESCE(p_summary, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google',\n 'gcalEtag', p_etag,\n 'title', COALESCE(p_summary, b.metadata->>'title')),\n updated_at = now()\n WHERE b.id = v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\n-- gcal_stamp_outbound: after the edge function creates the Google event for an\n-- outbound push, it stamps the fresh event id/etag back onto the appointment.\n-- Bookkeeping only — must not re-fire §2's trigger, hence the GUC. Does NOT set\n-- metadata.syncOrigin (the booking's provenance is still the app/site).\nCREATE OR REPLACE FUNCTION public.gcal_stamp_outbound(\n p_tenant_id uuid,\n p_booking_id uuid,\n p_event_id text,\n p_etag text DEFAULT NULL,\n p_calendar_id text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_booking_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_stamp_outbound: tenant, booking and event id are required';\n END IF;\n\n -- Transaction-local: §2's trigger skips the echo for this write only.\n PERFORM set_config('app.booking_origin', 'google', true);\n\n UPDATE appointments b\n SET metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalSyncedAt', now())\n || CASE WHEN p_calendar_id IS NULL THEN '{}'::jsonb\n ELSE jsonb_build_object('gcalCalendarId', p_calendar_id) END,\n updated_at = now()\n WHERE b.id = p_booking_id AND b.tenant_id = p_tenant_id\n RETURNING b.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- gcal_unlink_channel: forget the incremental cursor + Google watch bookkeeping\n-- for a channel (used on disconnect / re-watch). Leaves the mapping row in place.\nCREATE OR REPLACE FUNCTION public.gcal_unlink_channel(\n p_channel_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n UPDATE plg_calendar_channels c\n SET sync_token = NULL,\n channel_id = NULL,\n resource_id = NULL,\n channel_expires_at = NULL,\n updated_at = now()\n WHERE c.id = p_channel_id\n RETURNING c.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- Lock the inbound writers to service_role only.\nDO $$\nDECLARE fn text;\nBEGIN\n FOR fn IN SELECT unnest(ARRAY[\n 'public.gcal_import_event(uuid, uuid, text, text, text, timestamptz, timestamptz, boolean, text)',\n 'public.gcal_apply_event_patch(uuid, text, text, timestamptz, timestamptz, text, boolean)',\n 'public.gcal_stamp_outbound(uuid, uuid, text, text, text)',\n 'public.gcal_unlink_channel(uuid)'\n ])\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION %s FROM public, anon, authenticated', fn);\n EXECUTE format('GRANT EXECUTE ON FUNCTION %s TO service_role', fn);\n END LOOP;\nEND $$;\n\n-- ===========================================================================\n-- §5 — get_available_slots: imported Google blocks must remove availability.\n-- CREATE OR REPLACE keeping the EXACT signature (anon + admin both call it, and\n-- it is graded on the same shape as plugin-agenda/src/migrations/001_public_booking.sql).\n--\n-- Conceptual diff vs 001 — ONE condition in the overlap NOT EXISTS:\n-- before: AND b.assignee_id = c.assignee_id\n-- after: AND (b.assignee_id = c.assignee_id\n-- OR (b.assignee_id IS NULL AND b.kind = 'block'))\n-- Rationale: a tenant-wide BLOCK imported from Google (target_kind NULL →\n-- assignee_id IS NULL, kind 'block', see §4) must busy-out the slot for EVERY\n-- professional. Restricted to kind='block' so an unassigned admin appointment\n-- keeps the 001 behaviour (blocks nobody). Per-assignee rows keep matching on\n-- assignee_id.\n-- Everything else is byte-identical to 001: the status filter already covers\n-- \"any non-cancelled kind\" (no_show also excluded), and the p_assignee_id-NULL\n-- fan-out across staff via day_schedules is preserved untouched.\n-- ===========================================================================\nCREATE OR REPLACE FUNCTION public.get_available_slots(\n p_tenant_id uuid,\n p_date date,\n p_duration_minutes integer,\n p_assignee_id uuid DEFAULT NULL,\n p_slot_interval integer DEFAULT 30\n) RETURNS TABLE (slot_start timestamptz, slot_end timestamptz)\nLANGUAGE plpgsql STABLE SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_tz text;\nBEGIN\n -- tight validation: this function is anon-callable\n IF p_duration_minutes IS NULL OR p_duration_minutes NOT BETWEEN 5 AND 480 THEN\n RAISE EXCEPTION 'invalid duration';\n END IF;\n IF p_slot_interval IS NULL OR p_slot_interval NOT BETWEEN 5 AND 240 THEN\n RAISE EXCEPTION 'invalid interval';\n END IF;\n IF p_date IS NULL OR p_date < current_date OR p_date > current_date + 90 THEN\n RETURN;\n END IF;\n\n SELECT COALESCE(t.settings->>'timezone', 'America/Sao_Paulo') INTO v_tz\n FROM tenants t WHERE t.id = p_tenant_id;\n IF v_tz IS NULL THEN RETURN; END IF; -- unknown tenant → empty, not an error\n\n RETURN QUERY\n WITH day_schedules AS (\n SELECT sc.assignee_id, sc.starts_at AS win_start, sc.ends_at AS win_end\n FROM schedules sc\n WHERE sc.tenant_id = p_tenant_id\n AND sc.kind = 'working_hours'\n AND sc.is_active\n AND (p_assignee_id IS NULL OR sc.assignee_id = p_assignee_id)\n AND (\n sc.specific_date = p_date\n OR (sc.specific_date IS NULL AND sc.day_of_week = EXTRACT(dow FROM p_date)::smallint)\n )\n ),\n candidate AS (\n SELECT\n ds.assignee_id,\n gs AS s_start,\n gs + make_interval(mins => p_duration_minutes) AS s_end\n FROM day_schedules ds\n CROSS JOIN LATERAL generate_series(\n (p_date + ds.win_start) AT TIME ZONE v_tz,\n ((p_date + ds.win_end) AT TIME ZONE v_tz) - make_interval(mins => p_duration_minutes),\n make_interval(mins => p_slot_interval)\n ) AS gs\n )\n SELECT DISTINCT c.s_start, c.s_end\n FROM candidate c\n WHERE NOT EXISTS (\n SELECT 1 FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n -- SMART SYNC: match this professional's own bookings OR any tenant-wide\n -- BLOCK (assignee_id IS NULL AND kind='block', e.g. imported from Google\n -- with a whole-tenant channel) — the latter busies the slot for every\n -- professional. Assignee-less rows of other kinds (an unassigned admin\n -- appointment) keep the 001 behaviour and do not block anyone.\n AND (b.assignee_id = c.assignee_id\n OR (b.assignee_id IS NULL AND b.kind = 'block'))\n AND b.status NOT IN ('cancelled', 'no_show')\n AND b.starts_at < c.s_end\n AND COALESCE(b.ends_at, b.starts_at) > c.s_start\n )\n ORDER BY 1;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer) FROM public;\nGRANT EXECUTE ON FUNCTION public.get_available_slots(uuid, date, integer, uuid, integer)\n TO anon, authenticated, service_role;\n\n-- ===========================================================================\n-- §6 — Inbound schedule (optional) — per-channel incremental pull.\n-- Supersedes the single-calendar template in 001. Enable once per project after\n-- setting app.gcal_sync_url / app.gcal_service_key (see 001 header). The edge\n-- function fans out over active channels, using each channel's sync_token cursor:\n--\n-- SELECT cron.schedule('gcal-pull', '*/10 * * * *', $CRON$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object(\n-- 'Content-Type','application/json',\n-- 'Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events'))\n-- $CRON$);\n--\n-- Or drive one row per channel from SQL (tighter scoping / per-channel cadence):\n--\n-- SELECT cron.schedule('gcal-pull-'||ch.id::text, '*/10 * * * *', format($CRON$\n-- SELECT net.http_post(\n-- url := current_setting('app.gcal_sync_url'),\n-- headers := jsonb_build_object(\n-- 'Content-Type','application/json',\n-- 'Authorization','Bearer '||current_setting('app.gcal_service_key')),\n-- body := jsonb_build_object('action','pull_events','channelId',%L))\n-- $CRON$, ch.id))\n-- FROM public.plg_calendar_channels ch\n-- WHERE ch.is_active AND ch.direction IN ('inbound','bidirectional');\n-- ===========================================================================\n`\n\nexport const MIGRATION_003_PLG_RENAME = `-- ---------------------------------------------------------------------------\n-- 003_plg_rename.sql — standardize the Google Calendar connector objects onto\n-- the platform \\`plg_<plugin>_\\` prefix (DATA-MODEL.md Ring 1).\n--\n-- calendar_integrations → plg_calendar_integrations\n-- calendar_channels → plg_calendar_channels\n-- calendar_sync_log → plg_calendar_sync_log\n--\n-- Legacy-pool remediation ONLY: 001/002 now create the prefixed names directly,\n-- so fresh installs never reach a rename branch. Fully idempotent and guarded —\n-- every RENAME fires only when the old object exists and the new one does not,\n-- so re-running (or running on an already-prefixed pool) is a no-op.\n--\n-- A table RENAME preserves its data, RLS state, policies, grants, indexes,\n-- constraints and triggers (they follow the table), so §1 only renames the\n-- table + the explicitly-named indexes. §2 then re-points the SECURITY DEFINER\n-- gcal_* functions whose bodies hard-code the old table names.\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — Guarded table + index renames.\n-- ===========================================================================\nDO $$\nBEGIN\n IF to_regclass('public.calendar_integrations') IS NOT NULL\n AND to_regclass('public.plg_calendar_integrations') IS NULL THEN\n ALTER TABLE public.calendar_integrations RENAME TO plg_calendar_integrations;\n END IF;\n\n IF to_regclass('public.calendar_channels') IS NOT NULL\n AND to_regclass('public.plg_calendar_channels') IS NULL THEN\n ALTER TABLE public.calendar_channels RENAME TO plg_calendar_channels;\n END IF;\n\n IF to_regclass('public.calendar_sync_log') IS NOT NULL\n AND to_regclass('public.plg_calendar_sync_log') IS NULL THEN\n ALTER TABLE public.calendar_sync_log RENAME TO plg_calendar_sync_log;\n END IF;\n\n -- Named indexes do not follow a table rename automatically.\n IF to_regclass('public.idx_calendar_integrations_tenant') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_integrations_tenant') IS NULL THEN\n ALTER INDEX public.idx_calendar_integrations_tenant RENAME TO idx_plg_calendar_integrations_tenant;\n END IF;\n\n IF to_regclass('public.idx_calendar_channels_tenant') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_channels_tenant') IS NULL THEN\n ALTER INDEX public.idx_calendar_channels_tenant RENAME TO idx_plg_calendar_channels_tenant;\n END IF;\n\n IF to_regclass('public.idx_calendar_channels_integration') IS NOT NULL\n AND to_regclass('public.idx_plg_calendar_channels_integration') IS NULL THEN\n ALTER INDEX public.idx_calendar_channels_integration RENAME TO idx_plg_calendar_channels_integration;\n END IF;\nEND $$;\n\n-- ===========================================================================\n-- §2 — Re-point the inbound SECURITY DEFINER writers at the prefixed names.\n-- These bodies are byte-identical to 002_smart_sync.sql except the calendar_*\n-- table references, which now read plg_calendar_*. gcal_apply_event_patch and\n-- gcal_stamp_outbound only touch public.appointments (unaffected by the rename)\n-- and are re-asserted here for completeness so all four writers stay in step.\n-- ===========================================================================\n\nCREATE OR REPLACE FUNCTION public.gcal_import_event(\n p_tenant_id uuid,\n p_channel_id uuid,\n p_event_id text,\n p_etag text,\n p_summary text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_all_day boolean,\n p_description text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_ch record;\n v_kind text;\n v_assignee uuid;\n v_location uuid;\n v_ends timestamptz;\n v_meta jsonb;\n v_existing uuid;\n v_appt uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL OR p_starts_at IS NULL THEN\n RAISE EXCEPTION 'gcal_import_event: tenant, event id and start are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT c.import_mode, c.target_kind, c.target_id\n INTO v_ch\n FROM plg_calendar_channels c\n WHERE c.id = p_channel_id AND c.tenant_id = p_tenant_id;\n IF NOT FOUND THEN RAISE EXCEPTION 'gcal_import_event: unknown channel for tenant'; END IF;\n\n v_kind := CASE WHEN v_ch.import_mode = 'appointment' THEN 'appointment' ELSE 'block' END;\n v_assignee := CASE WHEN v_ch.target_kind = 'assignee' THEN v_ch.target_id ELSE NULL END;\n v_location := CASE WHEN v_ch.target_kind = 'location' THEN v_ch.target_id ELSE NULL END;\n\n v_ends := COALESCE(\n p_ends_at,\n CASE WHEN COALESCE(p_all_day, false) THEN p_starts_at + interval '1 day' ELSE p_starts_at END\n );\n\n v_meta := jsonb_build_object(\n 'syncOrigin', 'google',\n 'googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalChannelId', p_channel_id::text,\n 'allDay', COALESCE(p_all_day, false),\n 'title', p_summary,\n 'source', 'google_import'\n );\n\n SELECT b.id INTO v_existing\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_existing IS NOT NULL THEN\n UPDATE appointments b\n SET kind = v_kind,\n assignee_id = v_assignee,\n location_id = v_location,\n starts_at = p_starts_at,\n ends_at = v_ends,\n status = 'scheduled',\n notes = COALESCE(p_description, p_summary),\n metadata = COALESCE(b.metadata, '{}'::jsonb) || v_meta,\n updated_at = now()\n WHERE b.id = v_existing\n RETURNING b.id INTO v_appt;\n ELSE\n INSERT INTO appointments (tenant_id, kind, assignee_id, location_id,\n starts_at, ends_at, status, notes, metadata)\n VALUES (p_tenant_id, v_kind, v_assignee, v_location,\n p_starts_at, v_ends, 'scheduled', COALESCE(p_description, p_summary), v_meta)\n RETURNING id INTO v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_apply_event_patch(\n p_tenant_id uuid,\n p_event_id text,\n p_etag text,\n p_starts_at timestamptz,\n p_ends_at timestamptz,\n p_summary text,\n p_cancelled boolean\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_appt uuid;\n v_curr_etag text;\nBEGIN\n IF p_tenant_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_apply_event_patch: tenant and event id are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n SELECT b.id, b.metadata->>'gcalEtag'\n INTO v_appt, v_curr_etag\n FROM appointments b\n WHERE b.tenant_id = p_tenant_id\n AND b.metadata->>'googleCalendarEventId' = p_event_id\n LIMIT 1;\n\n IF v_appt IS NULL THEN RETURN NULL; END IF;\n IF p_etag IS NOT NULL AND p_etag = v_curr_etag THEN\n RETURN NULL;\n END IF;\n\n IF COALESCE(p_cancelled, false) THEN\n UPDATE appointments b\n SET status = 'cancelled',\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google', 'gcalEtag', p_etag),\n updated_at = now()\n WHERE b.id = v_appt;\n ELSE\n UPDATE appointments b\n SET starts_at = COALESCE(p_starts_at, b.starts_at),\n ends_at = COALESCE(p_ends_at, b.ends_at),\n notes = COALESCE(p_summary, b.notes),\n metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('syncOrigin', 'google',\n 'gcalEtag', p_etag,\n 'title', COALESCE(p_summary, b.metadata->>'title')),\n updated_at = now()\n WHERE b.id = v_appt;\n END IF;\n\n RETURN v_appt;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_stamp_outbound(\n p_tenant_id uuid,\n p_booking_id uuid,\n p_event_id text,\n p_etag text DEFAULT NULL,\n p_calendar_id text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n IF p_tenant_id IS NULL OR p_booking_id IS NULL OR p_event_id IS NULL THEN\n RAISE EXCEPTION 'gcal_stamp_outbound: tenant, booking and event id are required';\n END IF;\n\n PERFORM set_config('app.booking_origin', 'google', true);\n\n UPDATE appointments b\n SET metadata = COALESCE(b.metadata, '{}'::jsonb)\n || jsonb_build_object('googleCalendarEventId', p_event_id,\n 'gcalEtag', p_etag,\n 'gcalSyncedAt', now())\n || CASE WHEN p_calendar_id IS NULL THEN '{}'::jsonb\n ELSE jsonb_build_object('gcalCalendarId', p_calendar_id) END,\n updated_at = now()\n WHERE b.id = p_booking_id AND b.tenant_id = p_tenant_id\n RETURNING b.id INTO v_id;\n RETURN v_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.gcal_unlink_channel(\n p_channel_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_id uuid;\nBEGIN\n UPDATE plg_calendar_channels c\n SET sync_token = NULL,\n channel_id = NULL,\n resource_id = NULL,\n channel_expires_at = NULL,\n updated_at = now()\n WHERE c.id = p_channel_id\n RETURNING c.id INTO v_id;\n RETURN v_id;\nEND $$;\n\n-- Re-assert the service_role-only lock (idempotent; matches 002 §4).\nDO $$\nDECLARE fn text;\nBEGIN\n FOR fn IN SELECT unnest(ARRAY[\n 'public.gcal_import_event(uuid, uuid, text, text, text, timestamptz, timestamptz, boolean, text)',\n 'public.gcal_apply_event_patch(uuid, text, text, timestamptz, timestamptz, text, boolean)',\n 'public.gcal_stamp_outbound(uuid, uuid, text, text, text)',\n 'public.gcal_unlink_channel(uuid)'\n ])\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION %s FROM public, anon, authenticated', fn);\n EXECUTE format('GRANT EXECUTE ON FUNCTION %s TO service_role', fn);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_004_DROP_OAUTH_TOKENS = `-- ============================================================================\n-- Google Calendar 004: the credential leaves the tenant database, and the\n-- outbound trigger stops being able to break a booking write.\n--\n-- §1 credential drop oauth_refresh_token + oauth_access_token\n-- §2 outbound anti-loop, safe no-op, delete context, correlation id\n-- §3 realtime publish public.appointments so the calendar repaints\n--\n-- Additive and idempotent: no table is created, no policy is rewritten, and the\n-- tenant RLS from 001 already covers everything touched here.\n-- ============================================================================\n\n-- §1 ── credential ───────────────────────────────────────────────────────────\n-- THE EXPOSURE THIS CLOSES: 001 stored \\`oauth_refresh_token text\\` and\n-- \\`oauth_access_token text\\` on public.plg_calendar_integrations. That table is\n-- read from the browser with the publishable key under tenant RLS — and the\n-- connector read it with \\`select('*')\\` — so a Google refresh token was readable\n-- by ANY authenticated member of the tenant, reception included. A refresh token\n-- is not a session: it is durable access to the owner's entire calendar, mail-\n-- adjacent metadata and every calendar shared with them. And a pool is one\n-- Supabase project serving N tenants, so anything running there with\n-- service_role read every clinic's Google grant at once.\n--\n-- This is the third connector to make the same move, and the worst of the three.\n-- RankLayer had nothing to replace its key with (it pushes IN and authenticates\n-- against the platform); PlugBank's credential is meant to move to the platform\n-- (FAY-1360 — as of 2026-08-12 its api_token is still a plaintext pool column).\n-- Google Calendar is PlugBank's case: the grant still has to exist, it just must\n-- not exist HERE. The destination is the platform's ConnectorConnection store\n-- (encrypted; exists, unused), with the sync function redeeming per call — that\n-- is FAY-1359, and it has NOT happened.\n--\n-- ⚠ REPO AHEAD OF POOL (verified 2026-08-12, FAY-1379): this file has NOT been\n-- applied to the live salon pool. plg_calendar_integrations there still carries\n-- both token columns with a real clinic's grant, and the DEPLOYED\n-- google-calendar-sync (v16) still reads and writes them. Applying this drop\n-- before FAY-1359's ordered rollout (function reads both homes → data migrated\n-- → function reads only the new home → drop) severs the clinic's sync. Do not\n-- \\`db apply\\` this to a pool outside that sequence.\n--\n-- \\`token_expires_at\\` deliberately stays. It is a timestamp, not a credential,\n-- and it is the only non-secret signal that a grant exists — which is what the\n-- browser needs in order to draw a connected/disconnected badge without ever\n-- being handed the thing it is reporting on. See ../credentials.ts.\n--\n-- ROTATE any token a pool already stored. Nothing is live on this connector yet,\n-- but DROP COLUMN is a catalog change: the old values stay in the heap until the\n-- next table rewrite, so a grant that ever reached a pool must be revoked at\n-- Google rather than assumed gone.\n\nDO $$\nBEGIN\n IF to_regclass('public.plg_calendar_integrations') IS NOT NULL THEN\n ALTER TABLE public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n END IF;\n -- Pools converted before 003 renamed the tables carry the legacy name.\n IF to_regclass('public.calendar_integrations') IS NOT NULL THEN\n ALTER TABLE public.calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE public.calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n END IF;\nEND $$;\n\n-- §2 ── outbound trigger ─────────────────────────────────────────────────────\n-- Three defects in 001's fn_gcal_push_booking, in order of how badly they hurt:\n--\n-- 1. NO ANTI-LOOP. An inbound Google event is written to public.appointments by\n-- the sync function, which fires this trigger, which pushes the same change\n-- back to Google, which changes the event, which the next pull reads as new.\n-- The symptom a customer reports is an appointment that will not stop moving.\n-- The sync function sets \\`app.booking_origin = 'google'\\` for the duration of\n-- its transaction; a write carrying that marker is never echoed back.\n--\n-- 2. A MISSING PREREQUISITE COULD BREAK THE BOOKING. 001 returned early on an\n-- empty URL but not on an empty key, so a half-configured pool sent an\n-- unauthenticated pg_net request; and any error raised in here aborts the\n-- INSERT that fired it. An integration that is not set up must degrade to\n-- \"Google is not updated\", never to \"the appointment could not be saved\".\n-- Every exit path below returns the row.\n--\n-- 3. A DELETE ARRIVED WITH NOTHING TO DELETE. AFTER DELETE can still read OLD,\n-- but pg_net delivers asynchronously — by the time the function runs, the row\n-- is gone and it cannot look up which Google event to remove. The linked ids\n-- now travel in the payload.\n--\n-- The early returns are not enough on their own: on a pool where the settings\n-- are present but pg_net is not installed, the PERFORM itself raises \\`schema\n-- \"net\" does not exist\\` and takes the INSERT down with it. So the delivery is\n-- wrapped too. Swallowing a delivery error is safe here because pg_net only\n-- ENQUEUES — anything it could tell us is already visible as \"nothing has\n-- synced\" in plg_calendar_sync_log and in the connector's derived health.\n--\n-- The Supabase service-role key still reaches this trigger through the\n-- \\`app.gcal_service_key\\` database setting that 001 introduced. That is a lesser\n-- exposure than the one closed in §1 (a GUC is not reachable through PostgREST,\n-- so no browser can read it) but it is still a pool-wide credential in the\n-- database, and it is NOT fixed here. FAY-1372 shipped the RLS half (a\n-- tenant-scoped claim narrows user_tenant_ids); nothing mints such a token for\n-- this trigger yet, and the function still runs on service_role (FAY-1378).\n-- Left as a named debt rather than moved to a third hiding place.\n\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public, extensions, net\nAS $$\nDECLARE\n url text := current_setting('app.gcal_sync_url', true);\n key text := current_setting('app.gcal_service_key', true);\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- (1) Inbound Google writes mark themselves. Never echo them back.\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n -- (2) Not configured is not an error. Diagnostics report the connector as\n -- incomplete; the appointment is saved either way.\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n BEGIN\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object(\n 'Content-Type', 'application/json',\n 'Authorization', 'Bearer ' || key\n ),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n -- (3) Carried so a delete can still be honoured after the row is gone.\n 'googleEventId', rec.metadata->>'googleCalendarEventId',\n 'calendarId', rec.metadata->>'gcalCalendarId',\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n EXCEPTION WHEN OTHERS THEN\n -- Missing pg_net, a bad URL, a full queue: the appointment is still saved.\n RAISE WARNING 'gcal push skipped for booking %: %', rec.id, SQLERRM;\n END;\n\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- §3 ── realtime ─────────────────────────────────────────────────────────────\n-- The calendar screen subscribes to public.appointments so a booking written by\n-- the sync function repaints the grid the manager is looking at, instead of\n-- waiting for them to reload the tab. Additive and guarded: a pool without the\n-- supabase_realtime publication is left alone, and re-running adds nothing.\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM pg_publication WHERE pubname = 'supabase_realtime')\n AND NOT EXISTS (\n SELECT 1 FROM pg_publication_tables\n WHERE pubname = 'supabase_realtime' AND schemaname = 'public' AND tablename = 'appointments'\n )\n THEN\n ALTER PUBLICATION supabase_realtime ADD TABLE public.appointments;\n END IF;\nEND $$;\n`\n\nexport const MIGRATION_005_OUTBOUND_VAULT_DELIVERY = `-- ============================================================================\n-- Google Calendar 005: the outbound credential moves to Vault, and stops being\n-- the service-role key. The Authorization header stays.\n--\n-- §1 trigger fn_gcal_push_booking reads Vault, falls back to the old GUCs\n-- §2 cleanup clear app.gcal_service_key ONLY where Vault already covers it\n--\n-- Additive and idempotent: a CREATE OR REPLACE plus a guarded, conditional\n-- catalog cleanup.\n--\n-- WRITTEN AGAINST THE DEPLOYED POOL, NOT AGAINST THIS FOLDER. The repo and\n-- cluster-salon-br-01 (gphxclpkbtbucoqclbco) had drifted: \\`004\\` here still reads\n-- \\`app.gcal_service_key\\`, while the pool has been on Vault since 2026-07-28 and\n-- the deployed function is four features ahead of \\`functions/\\`. Everything below\n-- was checked against the live database and the live function source, because\n-- the previous attempt at this file was derived from the repo alone and would\n-- have broken a real clinic. See FAY-1379 for the drift itself.\n-- ============================================================================\n\n-- §1 ── the credential ───────────────────────────────────────────────────────\n-- THE EXPOSURE THIS CLOSES, precisely: \\`001\\` told operators to run\n-- ALTER DATABASE postgres SET app.gcal_service_key = '<service-role-key>';\n-- and every version of this trigger in the repo since (\\`001\\`, \\`002 §2\\`,\n-- \\`004 §2\\`) reads it back with current_setting(). A pool is ONE Supabase project\n-- serving N tenants and service_role bypasses RLS by definition, so that setting\n-- is unrestricted read/write over every tenant in the cluster, in plain text in\n-- pg_db_role_setting and in every pg_dump taken since.\n--\n-- It is closed by making the credential BOTH narrow and encrypted, not by\n-- removing it: the header is the only thing authorising the push. The deployed\n-- function checks it (\\`isServiceRequest\\` compares the bearer against\n-- GCAL_OUTBOUND_SECRET, then against the service-role key) and \\`push_event\\` is a\n-- service action with no user path, so a request with no Authorization header is\n-- rejected with \\`400 Unknown action: push_event\\`. Because pg_net is\n-- fire-and-forget that rejection is INVISIBLE — the clinic would simply stop\n-- appearing in Google Calendar. Removing the header is therefore not a security\n-- improvement, it is a silent outage. It was tried and reverted.\n--\n-- So: \\`gcal_outbound_secret\\` in Vault. Encrypted at rest, outside pg_dump's\n-- plaintext, readable only by a definer function like this one, and — the part\n-- that matters — it authorises exactly one thing, calling this connector's edge\n-- function. Losing it does not hand anyone another tenant's data. This is the\n-- shape the pool has been running since 2026-07-28; \\`005\\` is the repo catching\n-- up, so a pool provisioned fresh from this folder is born with it instead of\n-- being told to paste a service-role key into a database setting.\n--\n-- THE FALLBACK IS DELIBERATE. A pool that followed \\`001\\` and has no Vault secret\n-- keeps working off the old GUCs, loudly. The alternative — read Vault only —\n-- silently disarms the push on exactly the pools that did what the docs told\n-- them to, which is the failure this file exists to avoid.\n--\n-- WHAT THIS DOES NOT FIX: the edge function still builds its Supabase client\n-- with SUPABASE_SERVICE_ROLE_KEY, so the FUNCTION still reads every tenant in\n-- the pool. That is not reachable from SQL and does not close here: it closes\n-- when the platform mints a short-lived tenant-scoped token (FAY-1353) that\n-- packages/db/migrations/028_tenant_scoped_token.sql already teaches every\n-- policy to honour through user_tenant_ids(). See docs/platform/DECISIONS.md,\n-- 2026-08-11 — \"a connector's privilege comes from its token\".\n--\n-- ROTATE the service-role key of any pool that ever ran \\`001\\`'s setup line: it\n-- was plain text at rest and in every backup taken since, so §2 clearing it is\n-- not the same as it never having been there.\n\nCREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = public, extensions, net, vault\nAS $$\nDECLARE\n url text;\n key text;\n legacy boolean := false;\n rec record := COALESCE(NEW, OLD);\n op text := lower(TG_OP);\n corr text := NULLIF(current_setting('app.booking_correlation_id', true), '');\nBEGIN\n -- Unchanged from 004: inbound Google writes mark themselves, and a write\n -- carrying that marker is never echoed back.\n IF current_setting('app.booking_origin', true) = 'google' THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n -- Vault first. Wrapped because a pool without the vault extension must\n -- degrade to the fallback, not abort the booking write.\n BEGIN\n SELECT decrypted_secret INTO url\n FROM vault.decrypted_secrets WHERE name = 'gcal_sync_url'\n ORDER BY created_at DESC LIMIT 1;\n SELECT decrypted_secret INTO key\n FROM vault.decrypted_secrets WHERE name = 'gcal_outbound_secret'\n ORDER BY created_at DESC LIMIT 1;\n EXCEPTION WHEN OTHERS THEN\n url := NULL;\n key := NULL;\n END;\n\n -- Legacy pools provisioned per 001's header keep working, and say so.\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n url := COALESCE(NULLIF(url, ''), current_setting('app.gcal_sync_url', true));\n key := COALESCE(NULLIF(key, ''), current_setting('app.gcal_service_key', true));\n legacy := NULLIF(key, '') IS NOT NULL;\n END IF;\n\n -- Not configured is not an error: an unconfigured pool degrades to \"Google is\n -- not updated\", never to \"the appointment could not be saved\".\n IF NULLIF(url, '') IS NULL OR NULLIF(key, '') IS NULL THEN\n RETURN COALESCE(NEW, OLD);\n END IF;\n\n IF legacy THEN\n RAISE WARNING 'gcal outbound is still using app.gcal_service_key; move it to the vault secret gcal_outbound_secret and rotate the service-role key';\n END IF;\n\n BEGIN\n PERFORM net.http_post(\n url := url,\n headers := jsonb_build_object(\n 'Content-Type', 'application/json',\n -- REQUIRED. The deployed function authorises push_event on this header\n -- alone; without it every push 400s, silently, forever.\n 'Authorization', 'Bearer ' || key\n ),\n body := jsonb_build_object(\n 'action', 'push_event',\n 'op', op,\n 'bookingId', rec.id,\n 'tenantId', rec.tenant_id,\n -- Carried so a delete can still be honoured after the row is gone.\n 'googleEventId', rec.metadata->>'googleCalendarEventId',\n 'calendarId', rec.metadata->>'gcalCalendarId',\n 'correlationId', COALESCE(corr, gen_random_uuid()::text)\n )\n );\n EXCEPTION WHEN OTHERS THEN\n -- Missing pg_net, a bad URL, a full queue: the appointment is still saved.\n -- The deployed trigger lacks this wrapper; 004 added it here after a pool\n -- with the settings present but the extension missing took an INSERT down.\n RAISE WARNING 'gcal push skipped for booking %: %', rec.id, SQLERRM;\n END;\n\n RETURN COALESCE(NEW, OLD);\nEND $$;\n\n-- §2 ── cleanup ──────────────────────────────────────────────────────────────\n-- Redefining the function stops the key being PREFERRED; it does not stop it\n-- being STORED. Settings live in pg_db_role_setting per (database, role), so the\n-- sweep is driven off the catalog rather than off the one ALTER DATABASE form\n-- \\`001\\` happened to show.\n--\n-- CONDITIONAL ON PURPOSE: the setting is cleared only where Vault already\n-- supplies \\`gcal_outbound_secret\\`, i.e. only where §1 provably never needs the\n-- fallback. Anywhere else it is left in place and reported, because clearing it\n-- there would disarm the push with no error anyone can see. On the live pool\n-- this loop finds nothing — the setting is not present on any role or database —\n-- and that is the expected result, not a failure.\nDO $$\nDECLARE\n r record;\n has_vault boolean := false;\nBEGIN\n BEGIN\n SELECT EXISTS (\n SELECT 1 FROM vault.decrypted_secrets\n WHERE name = 'gcal_outbound_secret' AND NULLIF(decrypted_secret, '') IS NOT NULL\n ) INTO has_vault;\n EXCEPTION WHEN OTHERS THEN\n has_vault := false;\n END;\n\n FOR r IN\n SELECT d.datname, a.rolname\n FROM pg_db_role_setting s\n LEFT JOIN pg_database d ON d.oid = s.setdatabase\n LEFT JOIN pg_roles a ON a.oid = s.setrole\n WHERE EXISTS (\n SELECT 1 FROM unnest(s.setconfig) AS c WHERE c LIKE 'app.gcal_service_key=%'\n )\n LOOP\n IF NOT has_vault THEN\n RAISE WARNING 'app.gcal_service_key is still set (database %, role %) and is the ONLY outbound credential — create the vault secret gcal_outbound_secret first, then re-run this migration',\n r.datname, r.rolname;\n CONTINUE;\n END IF;\n BEGIN\n IF r.rolname IS NULL THEN\n EXECUTE format('ALTER DATABASE %I RESET app.gcal_service_key', r.datname);\n ELSIF r.datname IS NULL THEN\n EXECUTE format('ALTER ROLE %I RESET app.gcal_service_key', r.rolname);\n ELSE\n EXECUTE format('ALTER ROLE %I IN DATABASE %I RESET app.gcal_service_key', r.rolname, r.datname);\n END IF;\n EXCEPTION WHEN OTHERS THEN\n RAISE WARNING 'could not clear app.gcal_service_key (database %, role %): % — clear it by hand, and rotate the key either way',\n r.datname, r.rolname, SQLERRM;\n END;\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX = `-- ---------------------------------------------------------------------------\n-- Google Calendar WEBHOOK INTAKE — delivery ledger + automation outbox\n-- ---------------------------------------------------------------------------\n-- RECONSTRUCTED FROM THE LIVE SCHEMA on 2026-08-12 (FAY-1379). These objects\n-- existed in pool gphxclpkbtbucoqclbco and in NO migration in any repo: they\n-- were applied by hand alongside the google-calendar-webhook deployment. A pool\n-- provisioned from this repo could not run that function — the SELECT of\n-- plg_calendar_channels.webhook_token_hash failed before any gate ran, and both\n-- INSERT targets were missing. This file closes that hole.\n--\n-- Written to be applied to a pool that ALREADY has them: every statement is\n-- IF NOT EXISTS / DROP-then-CREATE, and re-running it must be a no-op.\n--\n-- §1 plg_calendar_channels — the three webhook columns\n-- §2 plg_calendar_webhook_deliveries — one row per Google notification\n-- §3 plg_calendar_automation_outbox — domain events for the automations lane\n--\n-- Read by: functions/google-calendar-webhook/index.ts (§1 gate, §2 idempotency,\n-- §3 emit) and functions/google-calendar-sync/index.ts (§1 watch bookkeeping,\n-- §3 emit on inbound import/patch).\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — Watch-channel authentication state on plg_calendar_channels.\n-- Added by ALTER in the pool (they sit after created_at/updated_at), so they\n-- are added the same way here rather than folded into 002's CREATE TABLE —\n-- 002 has already run everywhere and its checksum must not move.\n--\n-- webhook_token_hash: SHA-256 of the token handed to Google at watch_start. The\n-- token itself is never stored, so a dump of this table does not let anyone\n-- forge a notification. The webhook re-hashes what arrives and compares in\n-- constant time.\n-- last_webhook_message_number: high-water mark of Google's monotonic per-channel\n-- counter — the replay guard. bigint because it outgrows int4.\n-- ===========================================================================\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS webhook_token_hash text;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_message_number bigint;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_at timestamptz;\n\n-- ===========================================================================\n-- §2 — plg_calendar_webhook_deliveries: one row per accepted notification.\n--\n-- The row IS the idempotency mechanism, not a log of one: the webhook inserts\n-- before doing any work and reads 23505 as \"already handled\", returning 204.\n-- Hence two unique keys, both present in the pool and both reproduced —\n-- (channel_ref, message_number) is the constraint the FK cascade protects, and\n-- (google_channel_id, message_number) catches a replay arriving after the\n-- channel row was recreated with the same Google channel id.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_webhook_deliveries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n channel_ref uuid NOT NULL REFERENCES public.plg_calendar_channels(id) ON DELETE CASCADE,\n google_channel_id text NOT NULL,\n resource_id text,\n message_number bigint NOT NULL,\n resource_state text,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n error text,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n created_at timestamptz DEFAULT now(),\n UNIQUE (channel_ref, message_number)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_webhook_delivery_message\n ON public.plg_calendar_webhook_deliveries (google_channel_id, message_number);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_tenant_created\n ON public.plg_calendar_webhook_deliveries (tenant_id, created_at DESC);\n\n-- Two partial indexes over the same predicate on different sort columns. Both\n-- are in the pool (evidence of two overlapping hand-applied scripts) and both\n-- are reproduced so this file matches the live schema exactly; consolidating\n-- them is a separate change with its own reasoning.\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_pending\n ON public.plg_calendar_webhook_deliveries (status, received_at)\n WHERE status IN ('pending','failed');\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_pending\n ON public.plg_calendar_webhook_deliveries (status, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_webhook_deliveries ENABLE ROW LEVEL SECURITY;\n\n-- Read-only for the app. Every write comes from the webhook function running as\n-- service_role, which bypasses RLS — there is no authenticated INSERT/UPDATE\n-- grant, so a browser cannot forge or retire a delivery.\nGRANT SELECT ON public.plg_calendar_webhook_deliveries TO authenticated;\nGRANT ALL ON public.plg_calendar_webhook_deliveries TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries;\nCREATE POLICY plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\n-- ===========================================================================\n-- §3 — plg_calendar_automation_outbox: calendar facts, for the automations lane.\n--\n-- Transactional outbox: the sync/webhook functions record WHAT happened and\n-- return; a consumer drains it. idempotency_key is unique per tenant so a\n-- replayed Google delivery or a re-run pull upserts onto the same row instead\n-- of firing an automation twice — that key is what the functions pass as\n-- onConflict, so it is load-bearing and not merely a hygiene constraint.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_automation_outbox (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n source text NOT NULL DEFAULT 'google_calendar',\n event_type text NOT NULL,\n aggregate_type text NOT NULL,\n aggregate_id text,\n idempotency_key text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n attempts integer NOT NULL DEFAULT 0,\n last_error text,\n occurred_at timestamptz NOT NULL DEFAULT now(),\n -- available_at is the retry clock: a failed row is re-eligible once it passes.\n available_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n error text,\n created_at timestamptz DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\n-- Redundant with the UNIQUE constraint's own index, and present in the pool for\n-- the same overlapping-scripts reason as §2. Reproduced, not tidied.\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_automation_outbox_idempotency\n ON public.plg_calendar_automation_outbox (tenant_id, idempotency_key);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_pending\n ON public.plg_calendar_automation_outbox (status, available_at)\n WHERE status IN ('pending','failed');\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_outbox_pending\n ON public.plg_calendar_automation_outbox (status, available_at, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_automation_outbox ENABLE ROW LEVEL SECURITY;\n\nGRANT SELECT ON public.plg_calendar_automation_outbox TO authenticated;\nGRANT ALL ON public.plg_calendar_automation_outbox TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox;\nCREATE POLICY plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n`\n\nexport const MIGRATION_007_CREDENTIAL_FREE_INSTALL = `-- ---------------------------------------------------------------------------\n-- Google Calendar — a credential-free install, from zero\n-- ---------------------------------------------------------------------------\n-- FAY-1359/1360. On 2026-08-12 the five plg_calendar_* tables were DROPPED from\n-- the beauty pool (gphxclpkbtbucoqclbco) together with both edge functions,\n-- because plg_calendar_integrations held the tenant's Google refresh token in an\n-- open column. A pool is one database for N clinics, so that column was one\n-- backup, one dump or one service_role key away from being every clinic's\n-- calendar.\n--\n-- This file is what a pool runs to have the connector back. It is deliberately\n-- SELF-CONTAINED rather than \"001 through 006 again\":\n--\n-- * 001 CREATEs the credential columns and 004 drops them. A pool restored by\n-- replaying the chain therefore holds a refresh-token column for the length\n-- of that replay, and holds it forever if the replay stops early — which is\n-- exactly what a half-applied ledger does. There is no ordering of those\n-- files in which the column never exists; there is this file, in which it\n-- never exists.\n-- * The beauty pool's ledger and its schema had already parted company (it\n-- recorded shop/0006b while tables up to 0043 were applied by hand). A\n-- recovery that depends on the ledger being right is not a recovery.\n--\n-- Re-runnable, and a near no-op on a pool that ran 001–006: every statement is\n-- IF NOT EXISTS / DROP-then-CREATE, and §5 drops the credential columns if it\n-- finds them rather than assuming 004 ran.\n--\n-- §1 plg_calendar_integrations — per-tenant sync state. NO credential.\n-- §2 plg_calendar_channels — the de-para, incl. the webhook columns\n-- §3 plg_calendar_sync_log — run history\n-- §4 plg_calendar_webhook_deliveries + plg_calendar_automation_outbox\n-- §5 the gate: this schema must not be able to hold a Google grant\n--\n-- WHAT OWNS WHAT, after this file (FAY-1388):\n-- the PLATFORM owns the credential — which Google account, authorized by\n-- whom, and the refresh token, in the vault, reachable only by redemption;\n-- plg_connections owns \"is this connector on for this tenant\", written by the\n-- app when consent comes back;\n-- these tables own the SYNC STATE — which calendars map to what, how far the\n-- cursor got, what Google last told us. Nothing here is a secret, and\n-- nothing here can be traded for access to anyone's calendar.\n-- ---------------------------------------------------------------------------\n\n-- ===========================================================================\n-- §1 — plg_calendar_integrations: one row per tenant, sync state only.\n--\n-- Same shape as 001 MINUS oauth_refresh_token, oauth_access_token and\n-- token_expires_at. There is no column here to put a token in, which is the\n-- property this migration exists to establish — see §5, which enforces it.\n--\n-- No FK to plg_connections on purpose. That table is the connector framework's\n-- and this one is the calendar's; a FK would make the connector's row a\n-- prerequisite for reading a cursor, and the two planes are meant to be able to\n-- fail independently.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_integrations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n provider text NOT NULL DEFAULT 'google',\n calendar_id text NOT NULL DEFAULT 'primary',\n -- Incremental pull cursor + legacy single-calendar watch bookkeeping.\n sync_token text,\n channel_id text,\n channel_resource_id text,\n channel_expires_at timestamptz,\n active boolean NOT NULL DEFAULT true,\n last_sync_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, provider)\n);\nALTER TABLE public.plg_calendar_integrations ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_integrations_tenant\n ON public.plg_calendar_integrations(tenant_id);\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_integrations TO authenticated;\nGRANT ALL ON public.plg_calendar_integrations TO service_role;\n\n-- ===========================================================================\n-- §2 — plg_calendar_channels: the de-para, with 006's webhook columns folded in.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_channels (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n integration_id uuid NOT NULL REFERENCES public.plg_calendar_integrations(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL,\n google_calendar_id text NOT NULL,\n summary text,\n color text,\n direction text NOT NULL DEFAULT 'bidirectional'\n CHECK (direction IN ('inbound','outbound','bidirectional','off')),\n target_kind text CHECK (target_kind IN ('assignee','service','location')),\n target_id uuid,\n import_mode text NOT NULL DEFAULT 'block'\n CHECK (import_mode IN ('block','appointment')),\n sync_token text,\n channel_id text,\n resource_id text,\n channel_expires_at timestamptz,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (integration_id, google_calendar_id)\n);\n\n-- The webhook's authentication state. \\`webhook_token_hash\\` is a SHA-256 of the\n-- token handed to Google — the token itself is never stored, so reading this\n-- table does not let anyone forge a notification. Added by ALTER as well as in\n-- the CREATE above, for the pool that already has the table from 002.\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS webhook_token_hash text;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_message_number bigint;\nALTER TABLE public.plg_calendar_channels\n ADD COLUMN IF NOT EXISTS last_webhook_at timestamptz;\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_tenant\n ON public.plg_calendar_channels(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_channels_integration\n ON public.plg_calendar_channels(integration_id);\n\nALTER TABLE public.plg_calendar_channels ENABLE ROW LEVEL SECURITY;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_channels TO authenticated;\nGRANT ALL ON public.plg_calendar_channels TO service_role;\n\nDROP TRIGGER IF EXISTS plg_calendar_channels_updated_at ON public.plg_calendar_channels;\nCREATE TRIGGER plg_calendar_channels_updated_at BEFORE UPDATE ON public.plg_calendar_channels\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\n-- ===========================================================================\n-- §3 — plg_calendar_sync_log: what already happened, per run.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_sync_log (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n direction text NOT NULL, -- inbound | outbound\n trigger text, -- on-write | scheduled | webhook | manual\n status text NOT NULL DEFAULT 'success', -- success | partial | error\n fetched integer NOT NULL DEFAULT 0,\n written integer NOT NULL DEFAULT 0,\n error text,\n correlation_id uuid,\n channel_id_ref uuid,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_calendar_sync_log ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_calendar_sync_log ADD COLUMN IF NOT EXISTS correlation_id uuid;\nALTER TABLE public.plg_calendar_sync_log ADD COLUMN IF NOT EXISTS channel_id_ref uuid;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_calendar_sync_log TO authenticated;\nGRANT ALL ON public.plg_calendar_sync_log TO service_role;\n\n-- RLS: tenant isolation for the three tables the app reads and writes.\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY[\n 'plg_calendar_integrations',\n 'plg_calendar_channels',\n 'plg_calendar_sync_log'\n ])\n LOOP\n IF NOT EXISTS (\n SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_rls'\n ) THEN\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR ALL TO authenticated '\n 'USING (tenant_id IN (SELECT public.user_tenant_ids())) '\n 'WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))',\n t||'_rls', t);\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_service'\n ) THEN\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR ALL TO service_role USING (true) WITH CHECK (true)',\n t||'_service', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- ===========================================================================\n-- §4 — Webhook intake: the delivery ledger and the automation outbox.\n--\n-- The delivery row IS the idempotency mechanism: the webhook inserts before\n-- doing any work and reads a 23505 as \"already handled\". Google retries hard,\n-- so this is what stops one notification becoming two appointments.\n-- ===========================================================================\nCREATE TABLE IF NOT EXISTS public.plg_calendar_webhook_deliveries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n channel_ref uuid NOT NULL REFERENCES public.plg_calendar_channels(id) ON DELETE CASCADE,\n google_channel_id text NOT NULL,\n resource_id text,\n message_number bigint NOT NULL,\n resource_state text,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n error text,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n created_at timestamptz DEFAULT now(),\n UNIQUE (channel_ref, message_number)\n);\n\n-- Catches a replay that arrives after the channel row was recreated with the\n-- same Google channel id — the FK-scoped constraint above cannot see that.\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_calendar_webhook_delivery_message\n ON public.plg_calendar_webhook_deliveries (google_channel_id, message_number);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_tenant_created\n ON public.plg_calendar_webhook_deliveries (tenant_id, created_at DESC);\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_webhook_deliveries_pending\n ON public.plg_calendar_webhook_deliveries (status, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_webhook_deliveries ENABLE ROW LEVEL SECURITY;\n-- Read-only for the app: every write comes from the webhook function as\n-- service_role, so a browser cannot forge or retire a delivery.\nGRANT SELECT ON public.plg_calendar_webhook_deliveries TO authenticated;\nGRANT ALL ON public.plg_calendar_webhook_deliveries TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries;\nCREATE POLICY plg_calendar_webhook_deliveries_read ON public.plg_calendar_webhook_deliveries\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\nCREATE TABLE IF NOT EXISTS public.plg_calendar_automation_outbox (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL,\n source text NOT NULL DEFAULT 'google_calendar',\n event_type text NOT NULL,\n aggregate_type text NOT NULL,\n aggregate_id text,\n idempotency_key text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending','processing','processed','failed','ignored')),\n attempts integer NOT NULL DEFAULT 0,\n last_error text,\n occurred_at timestamptz NOT NULL DEFAULT now(),\n -- available_at is the retry clock: a failed row is re-eligible once it passes.\n available_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n error text,\n created_at timestamptz DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS idx_plg_calendar_automation_outbox_pending\n ON public.plg_calendar_automation_outbox (status, available_at, created_at)\n WHERE status IN ('pending','failed');\n\nALTER TABLE public.plg_calendar_automation_outbox ENABLE ROW LEVEL SECURITY;\nGRANT SELECT ON public.plg_calendar_automation_outbox TO authenticated;\nGRANT ALL ON public.plg_calendar_automation_outbox TO service_role;\n\nDROP POLICY IF EXISTS plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox;\nCREATE POLICY plg_calendar_automation_outbox_read ON public.plg_calendar_automation_outbox\n FOR SELECT TO authenticated\n USING (tenant_id IN (SELECT public.user_tenant_ids()));\n\n-- ===========================================================================\n-- §5 — The gate.\n--\n-- Everything above is a CREATE, and a CREATE says nothing about a pool that\n-- already has the old shape. This block is the part that actually removes the\n-- hole: it drops the three credential columns wherever it finds them — the\n-- pool 004 never reached, the pool restored from an old backup, the pool\n-- someone re-provisioned from 001 — and then refuses to finish if any survived.\n--\n-- The RAISE matters more than the DROP. A migration that silently tolerated a\n-- token column is how this schema kept one for months.\n-- ===========================================================================\nDO $$\nDECLARE\n leftover text;\nBEGIN\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_refresh_token;\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS oauth_access_token;\n ALTER TABLE IF EXISTS public.plg_calendar_integrations DROP COLUMN IF EXISTS token_expires_at;\n\n SELECT string_agg(table_name || '.' || column_name, ', ')\n INTO leftover\n FROM information_schema.columns\n WHERE table_schema = 'public'\n AND table_name LIKE 'plg_calendar%'\n AND (\n column_name LIKE '%refresh_token%'\n OR column_name LIKE '%access_token%'\n OR column_name IN ('oauth_token', 'client_secret', 'api_key')\n );\n\n IF leftover IS NOT NULL THEN\n RAISE EXCEPTION\n 'Google Calendar schema still holds credential columns: %. The grant belongs in the platform vault (FAY-1359); redeem it at run time instead.',\n leftover;\n END IF;\nEND $$;\n\n-- Dropping the columns does not erase what was in them: Postgres leaves the old\n-- values in the heap until the next table rewrite. Any grant that ever reached a\n-- pool must be REVOKED AT GOOGLE, not assumed gone — which is also why every\n-- tenant re-consents after this file runs.\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"001_google_calendar\", sql: MIGRATION_001_GOOGLE_CALENDAR },\n { id: \"002_smart_sync\", sql: MIGRATION_002_SMART_SYNC },\n { id: \"003_plg_rename\", sql: MIGRATION_003_PLG_RENAME },\n { id: \"004_drop_oauth_tokens\", sql: MIGRATION_004_DROP_OAUTH_TOKENS },\n { id: \"005_outbound_vault_delivery\", sql: MIGRATION_005_OUTBOUND_VAULT_DELIVERY },\n { id: \"006_webhook_deliveries_outbox\", sql: MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX },\n { id: \"007_credential_free_install\", sql: MIGRATION_007_CREDENTIAL_FREE_INSTALL },\n]\n","// Google Calendar connector descriptor (control-plane metadata).\n//\n// Declares the connector against the SDK integration spine so the platform can\n// reason about what it syncs. The actual data-plane verbs run in the\n// google-calendar-sync edge function; this is the typed contract + capabilities.\nimport type { Connector } from '@fayz-ai/core'\n\nexport const googleCalendarConnector: Connector = {\n id: 'google-calendar',\n provider: 'google',\n pluginId: 'agenda',\n authKind: 'oauth',\n capabilities: [\n {\n entity: 'booking',\n direction: 'bidirectional',\n triggers: ['on-write', 'scheduled', 'webhook'],\n },\n ],\n}\n","// Google Calendar integration — official (in-SDK) addon for plugin-agenda.\n//\n// Settings-only PluginManifest: contributes a \"Google Calendar\" tab to /settings\n// for connecting an account and running a manual sync. Outbound (booking →\n// Google) is automatic via a DB trigger; inbound (Google → booking) via pg_cron\n// or a Google watch webhook. The data plane is the google-calendar-sync edge\n// function (see ./functions/google-calendar-sync). The booking↔event link lives\n// on public.appointments.metadata.googleCalendarEventId.\n//\n// Graduation path: extract to its own `@fayz-ai/plugin-google-calendar` package.\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { googleCalendarConnectorDef } from './connectorDef'\nimport {\n MIGRATION_001_GOOGLE_CALENDAR,\n MIGRATION_002_SMART_SYNC,\n MIGRATION_003_PLG_RENAME,\n MIGRATION_004_DROP_OAUTH_TOKENS,\n MIGRATION_005_OUTBOUND_VAULT_DELIVERY,\n MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX,\n MIGRATION_007_CREDENTIAL_FREE_INSTALL,\n} from './migrations'\n\nexport { createGoogleCalendarProvider } from './data/supabase'\nexport { googleCalendarConnector } from './connector'\nexport { googleCalendarConnectorDef } from './connectorDef'\nexport { deriveGoogleCalendarHealth } from './health'\nexport type { GoogleCalendarHealth, GoogleCalendarHealthIssue, GoogleCalendarHealthIssueCode, GoogleCalendarHealthStatus } from './health'\nexport { resolveBookingConflict, CONFLICT_SKEW_TOLERANCE_MS } from './conflict'\nexport type { BookingConflictInput, BookingConflictDecision, ConflictWinner } from './conflict'\nexport { CONNECTION_COLUMNS, isIntegrationActive, disconnectPatch } from './credentials'\nexport { googleCalendarConnectionStore, GOOGLE_CALENDAR_CONNECTOR_ID } from './connectorDef'\nexport {\n bookingToEvent,\n eventToBookingPatch,\n bookingSummary,\n appointmentRowToEvent,\n eventToAppointmentPatch,\n eventTimes,\n resolveTargetChannel,\n channelRowToChannel,\n} from './mapping'\nexport * from './types'\n\n// Addon plugin: contributes the Google Calendar connector into its host\n// (plugin-agenda). It appears in Agenda settings → Integrations — no top-level\n// settings tab of its own. See packages/saas ConnectorsHub.\nexport function createGoogleCalendarPlugin(): PluginManifest {\n return {\n id: 'google-calendar',\n name: 'Google Calendar',\n icon: 'Calendar',\n version: '0.1.0',\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['agenda'],\n navigation: [],\n routes: [],\n connectors: [googleCalendarConnectorDef],\n functions: [\n {\n slug: 'google-calendar-sync',\n // Not reached through the Fayz ingress: it is called from the browser\n // (calendar list, sync now, import), from the appointments trigger and\n // from the webhook function. Consent is NOT in that list any more — it\n // moved to the platform (FAY-1359/1360), which is also why this function\n // no longer answers GET.\n ingress: 'none',\n // FALSE, and here it is a decision rather than a gap: two of its callers\n // cannot present a JWT — the DB trigger sends a Vault secret as bearer\n // and pg_cron/the webhook send the service-role key. The gateway would\n // reject both before a line of the function runs. Authorization lives one\n // level in: `isServiceRequest` for the service actions, a Supabase user\n // plus tenant membership for the rest, and `tenantId` is required on both.\n verifyJwt: false,\n // NAMES only — and no Google client pair among them any more. The client\n // secret and the tenant's grant are both the platform's; this function\n // redeems a short-lived access token per call with the three names below.\n // SUPABASE_SERVICE_ROLE_KEY is listed because the function reads it\n // TODAY — it is the pool-wide privilege the 2026-08-11 ADR is written\n // to remove, and hiding it from the manifest would hide the debt.\n secrets: [\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n 'GCAL_OUTBOUND_SECRET',\n 'SUPABASE_URL',\n 'SUPABASE_SERVICE_ROLE_KEY',\n ],\n // The RPCs the function's credential should be allowed to call once it\n // stops holding service_role. Both already exist (002/003) and are\n // already how the inbound writes are applied; what is missing is the\n // credential that can call these and nothing else.\n grants: ['gcal_import_event', 'gcal_apply_event_patch'],\n },\n {\n // Declared for the first time (FAY-1379). It had been ACTIVE in the live\n // pool since 2026-05 with no source in any repo — the manifest could not\n // name what nobody could read.\n slug: 'google-calendar-webhook',\n // Google POSTs here directly; there is no ingress to put in front of it.\n ingress: 'none',\n // FALSE, and here it is a correct decision rather than a gap: Google\n // sends no Authorization header at all. The credential is the per-channel\n // token, checked against a stored SHA-256 in constant time, with the\n // resource id and a monotonic message number as the replay guard.\n verifyJwt: false,\n // NAMES only. GCAL_OUTBOUND_SECRET is the shared secret this function\n // presents when it asks google-calendar-sync to pull — the same secret\n // the DB trigger uses. SUPABASE_SERVICE_ROLE_KEY is listed because the\n // function reads it TODAY, same declared debt as the sync function.\n secrets: [\n 'SUPABASE_URL',\n 'SUPABASE_SERVICE_ROLE_KEY',\n 'GCAL_OUTBOUND_SECRET',\n 'GCAL_SYNC_FUNCTION_URL',\n 'GCAL_WEBHOOK_AUTO_PULL',\n ],\n // It calls no RPC: it writes the delivery row and the outbox, and\n // delegates every appointment write to google-calendar-sync.\n grants: [],\n },\n ],\n // Declared for the first time. Without this the connector's SQL was\n // reachable only by whoever remembered the folder — which is how a table\n // holding plaintext OAuth tokens shipped with nothing to gate it.\n migrations: [\n {\n id: 'google-calendar-001_google_calendar',\n version: '0.1.0',\n sql: MIGRATION_001_GOOGLE_CALENDAR,\n description: 'plg_calendar_integrations + plg_calendar_sync_log with tenant RLS, and the outbound appointments trigger',\n },\n {\n id: 'google-calendar-002_smart_sync',\n version: '0.1.0',\n sql: MIGRATION_002_SMART_SYNC,\n description: 'plg_calendar_channels (per-calendar de-para) + gcal_import_event / gcal_apply_event_patch',\n },\n {\n id: 'google-calendar-003_plg_rename',\n version: '0.1.0',\n sql: MIGRATION_003_PLG_RENAME,\n description: 'Rename legacy calendar_* tables to the plg_calendar_* prefix and repoint the RPCs',\n },\n {\n id: 'google-calendar-004_drop_oauth_tokens',\n version: '0.9.1',\n sql: MIGRATION_004_DROP_OAUTH_TOKENS,\n description:\n 'Drop plg_calendar_integrations.oauth_refresh_token/oauth_access_token (destination: the Fayz platform credential store — only inside FAY-1359 ordered rollout), give the outbound trigger an anti-loop guard and a safe no-op, and publish appointments for realtime',\n },\n {\n id: 'google-calendar-005_outbound_vault_delivery',\n version: '0.9.2',\n sql: MIGRATION_005_OUTBOUND_VAULT_DELIVERY,\n description:\n \"Take the outbound credential from the vault secret gcal_outbound_secret instead of the service-role key in app.gcal_service_key, keeping the Authorization header the sync function authorises on, and falling back to the old setting so a legacy pool is never silently disarmed\",\n },\n {\n id: 'google-calendar-006_webhook_deliveries_outbox',\n version: '0.9.2',\n sql: MIGRATION_006_WEBHOOK_DELIVERIES_OUTBOX,\n description:\n 'Reconstructed from the live pool (FAY-1379): the webhook columns on plg_calendar_channels plus plg_calendar_webhook_deliveries and plg_calendar_automation_outbox with RLS. Both deployed functions write these and no migration created them, so a fresh pool could not run the webhook at all',\n },\n {\n id: 'google-calendar-007_credential_free_install',\n version: '0.9.3',\n sql: MIGRATION_007_CREDENTIAL_FREE_INSTALL,\n description:\n 'Install the whole connector schema in its post-FAY-1359 shape, from zero, with no credential column at any point — the five tables the beauty pool had dropped, plus a gate that drops a token column wherever it is still found and refuses to finish if one survives',\n },\n ],\n }\n}\n","import React from 'react'\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { createSafeDataProvider, registerTranslations, registerMessageDefaults } from '@fayz-ai/core'\nimport { buildAgendaDomainEvents, buildAgendaMessageDefaults } from './lib/message-events'\nimport type { AgendaPluginOptions } from './config'\nimport { resolveConfig } from './config'\nimport { AgendaPage } from './views/AgendaPage'\nimport { CheckinPage } from './views/CheckinPage'\nimport { createSupabaseAgendaProvider } from './data/supabase'\nimport { createMockAgendaProvider } from './data/mock'\nimport { setAgendaTenantId } from './lib/tenant'\nimport { createAgendaStore } from './store'\nimport { agendaRegistries } from './data/registries'\nimport { AgendaGeneralSettings } from './components/AgendaGeneralSettings'\nimport { agendaLocales } from './locales'\nimport { MIGRATIONS } from './migrations'\nimport { setScheduleBlockConfig, getScheduleBlockConfig, PluginSettingsPanel } from '@fayz-ai/admin'\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAgendaPlugin(options?: AgendaPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n registerTranslations(agendaLocales)\n // O texto sugerido para cada fato da agenda. Os FATOS vão no manifesto\n // (`events`), de onde automações, integrações e auditoria leem o mesmo\n // contrato.\n registerMessageDefaults(buildAgendaMessageDefaults())\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseAgendaProvider({ professionalKind: config.professionalKind }),\n () => createMockAgendaProvider(),\n )\n const store = createAgendaStore(provider, options?.financialBridge)\n const registries = [...agendaRegistries, ...(options?.settingsRegistries ?? [])]\n\n // Register schedule block config globally so ScheduleEditor can read it\n setScheduleBlockConfig({\n defaults: config.scheduleBlockDefaults,\n showServices: !!config.serviceLookup,\n showConcurrent: true,\n showBookingWindow: true,\n showLocations: config.modules.locationSelection,\n locations: config.locations.map((l) => ({ id: l.id, name: l.name })),\n // Lazy fetcher — called by ScheduleEditor when locations are needed but empty\n fetchLocations: config.modules.locationSelection && provider.getLocations\n ? async () => {\n const locations = await provider.getLocations!()\n const current = getScheduleBlockConfig()\n if (current) setScheduleBlockConfig({ ...current, locations })\n return locations\n }\n : undefined,\n })\n\n const PageComponent: React.FC<any> = () =>\n React.createElement(AgendaPage, { config, provider, store })\n\n return {\n id: 'agenda',\n defaultAgentRole: 'frontdesk',\n name: config.labels.pageTitle,\n icon: 'Calendar',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n // Booking/scheduling is business-ops (clinic, salon, services) — targets\n // the saas/admin Panel world, not the ecommerce storefront.\n scaffolds: ['saas'],\n defaultEnabled: true,\n // The parts a plan can permit separately (#281, ADR 0025). This is the\n // plugin ADR 0018 named: it ships open with the \"suggest a slot\" button,\n // and the intelligence behind that button is a service we host — so the\n // facet is what says whether this tenant contracted it.\n facets: [\n { id: 'scheduling', label: 'Agenda', description: 'Horários, profissionais e reservas.', includedWithPlugin: true },\n { id: 'public_booking', label: 'Agendamento online', description: 'A página pública onde o cliente marca sozinho.' },\n { id: 'smart_fit', label: 'Encaixe inteligente', description: 'Sugere o melhor horário lendo a agenda inteira.' },\n ],\n dependencies: [],\n // Os FATOS da agenda — só expostos enquanto o módulo está ATIVO.\n events: buildAgendaDomainEvents(),\n declaredFeatures: [\n { id: 'agenda', label: config.labels.pageTitle, group: config.labels.pageTitle },\n { id: 'agenda.schedules', label: 'Schedule Management', group: config.labels.pageTitle },\n ],\n // Recurring monthly quota — counts appointment rows created this month.\n // (Clients/patients are the app's CRUD entity, so their cap is declared by\n // the app's EntityDef.limitKey, not here.)\n declaredLimits: [\n { key: 'bookings_month', label: 'Appointments this month', table: 'appointments', period: 'month' },\n ],\n queryEntities: [\n {\n key: 'agenda:appointments',\n entity: {\n name: 'Appointment',\n namePlural: 'Appointments',\n icon: 'Calendar',\n permission: { feature: 'agenda', action: 'read' },\n // Keys are the PROVIDER's output shape (camelCase) — what filters/\n // dateField/groupBy match against, not the raw DB columns.\n fields: [\n { key: 'startsAt', label: 'Starts at', type: 'text' },\n { key: 'endsAt', label: 'Ends at', type: 'text' },\n { key: 'status', label: 'Status', type: 'text' },\n { key: 'clientName', label: 'Client', type: 'text', searchable: true },\n { key: 'professionalName', label: 'Professional', type: 'text', searchable: true },\n { key: 'orderTotal', label: 'Order total', type: 'number' },\n { key: 'totalDurationMinutes', label: 'Duration (min)', type: 'number' },\n { key: 'createdAt', label: 'Created at', type: 'text' },\n ],\n data: {\n table: 'v_appointments',\n tenantScoped: true,\n searchColumns: ['client_name', 'professional_name'],\n },\n },\n },\n ],\n declaredRpcs: [\n {\n name: 'agent_agenda_create_appointment',\n kind: 'write' as const,\n description:\n 'Guarded appointment create: agent_guard (role→plan→bookings_month cap), working hours, race-safe conflict check, audited.',\n audits: true,\n },\n {\n name: 'agent_agenda_update_appointment',\n kind: 'write' as const,\n description:\n 'Guarded appointment reschedule/reassign/cancel: agent_guard (role→plan, no cap), working hours, race-safe conflict check that skips the appointment itself, audited.',\n audits: true,\n },\n ],\n\n // GATED ON `agenda.*`, NOT `appointments.*`.\n //\n // Both exist in the permission catalog for the same capability, and the two\n // never aliased: RLS on public.appointments/schedules is keyed on `agenda.*`\n // (migration 043) and 37 roles hold `agenda.read`, while only the 13 owner\n // roles — which got everything — hold `appointments.read`. So the UI was\n // hiding from a receptionist exactly what the database would have let her\n // read: no Agenda, no Check-in, and \"acesso restrito\" on a screen built for\n // her. app.v1_permission_map records this divergence and maps V1's\n // `checkin_dashboard` to `agenda.read`.\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 2,\n label: config.labels.pageTitle,\n route: '/agenda',\n icon: 'Calendar',\n permission: { feature: 'agenda', action: 'read' as const },\n },\n // AO LADO da Agenda, e não dentro dela: a recepção abre esta tela e fica\n // nela a manhã inteira. A rota é `/checkin` e não `/agenda/checkin` de\n // propósito — a casca agrupa num menu suspenso tudo que compartilha o\n // prefixo da rota, e sob `/agenda` o check-in virava um item escondido\n // atrás de um clique na Agenda, que é o oposto de entrada dedicada.\n ...(options?.checkin\n ? [{\n section: options?.navSection ?? 'main',\n position: (options?.navPosition ?? 2) + 0.5,\n label: 'Check-in',\n route: '/checkin',\n icon: 'LogIn',\n permission: { feature: 'agenda', action: 'read' as const },\n }]\n : []),\n ],\n\n routes: [\n {\n path: '/agenda',\n component: PageComponent,\n permission: { feature: 'agenda', action: 'read' as const },\n // Matches the ref agent_agenda_create_appointment returns.\n entityRoutes: ['schedule:appointment'],\n },\n ...(options?.checkin\n ? [{\n path: '/checkin',\n component: (() => React.createElement(CheckinPage, {\n config, provider, store,\n onReceive: options?.onCheckinReceive\n ? (b: any) => options.onCheckinReceive!({ id: b.id, orderId: b.orderId, clientName: b.clientName })\n : undefined,\n // `onOpenBooking` fica de FORA de propósito: sem ele a fila abre o\n // formulário nela mesma. Mandar para /agenda tirava a recepção da\n // tela em que ela está trabalhando para corrigir um horário, e a\n // volta ficava por conta dela. O host ainda pode passar o seu\n // quando quiser outro destino.\n })) as React.ComponentType<unknown>,\n permission: { feature: 'agenda', action: 'read' as const },\n }]\n : []),\n ],\n\n widgets: [],\n\n aiTools: [\n {\n id: 'agenda.list-appointments',\n name: 'listAppointments',\n description: 'Lists upcoming appointments for a given date or date range, optionally filtered by professional.',\n icon: 'Calendar',\n mode: 'read' as const,\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n date: { type: 'string' as const, description: 'Date (YYYY-MM-DD) or \"today\", \"tomorrow\", \"this week\"' },\n professional: { type: 'string' as const, description: 'Professional name to filter by' },\n },\n },\n suggestions: [\n { label: \"What's on the agenda today?\" },\n { label: 'Show me tomorrow\\'s appointments' },\n { label: 'Who has the most bookings this week?' },\n ],\n permission: { feature: 'agenda', action: 'read' as const },\n },\n {\n id: 'agenda.create-appointment',\n name: 'createAppointment',\n description:\n 'Creates a new appointment. Takes IDS, not names: resolve the client/service/professional ids first via findAnything/searchRecords, then call this with an ISO start time in the tenant timezone. The user confirms before booking.',\n icon: 'CalendarPlus',\n mode: 'persist' as const,\n limitKey: 'bookings_month',\n execution: { plane: 'server' as const, kind: 'rpc' as const, rpc: 'agent_agenda_create_appointment' },\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n client_id: { type: 'string' as const, description: 'Client id (from a search)' },\n service_id: { type: 'string' as const, description: 'Service id (from a search)' },\n professional_id: { type: 'string' as const, description: 'Professional id (optional — auto-assigned when omitted)' },\n starts_at: { type: 'string' as const, description: \"LOCAL date-time of the business, NO timezone suffix — e.g. '2026-07-27T10:00' for 10h. The system applies the tenant timezone.\" },\n notes: { type: 'string' as const, description: 'Optional notes' },\n },\n required: ['client_id', 'service_id', 'starts_at'],\n },\n suggestions: [\n { label: 'Book a haircut for Sarah tomorrow at 10am' },\n ],\n permission: { feature: 'agenda', action: 'create' as const },\n },\n {\n id: 'agenda.update-appointment',\n name: 'updateAppointment',\n description:\n 'Changes an appointment that ALREADY EXISTS: reschedule (starts_at), reassign (professional_id), cancel or confirm (status), or annotate (notes). ' +\n 'This is the ONLY way to change an appointment — the appointments entity is a read-only view, so updateRecord cannot touch it. ' +\n 'NEVER answer a reschedule or a cancellation by creating a new appointment: that leaves the original standing and double-books the professional. ' +\n 'Takes the appointment id from a previous search. The duration is preserved automatically. The user confirms before anything changes.',\n icon: 'CalendarClock',\n mode: 'persist' as const,\n execution: { plane: 'server' as const, kind: 'rpc' as const, rpc: 'agent_agenda_update_appointment' },\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n appointment_id: { type: 'string' as const, description: 'Id of the appointment to change (from a search)' },\n starts_at: { type: 'string' as const, description: \"New LOCAL date-time of the business, NO timezone suffix — e.g. '2026-07-27T16:30'. Omit to keep the current time.\" },\n professional_id: { type: 'string' as const, description: 'Move to another professional (optional)' },\n status: {\n type: 'string' as const,\n description: 'New status — use \"cancelled\" to cancel',\n enum: ['scheduled', 'confirmed', 'in_progress', 'completed', 'cancelled', 'no_show'],\n },\n notes: { type: 'string' as const, description: 'Optional notes' },\n },\n required: ['appointment_id'],\n },\n suggestions: [\n { label: 'Remarca o Gustavo para 16:30' },\n { label: 'Cancela o atendimento das 10h' },\n ],\n permission: { feature: 'agenda', action: 'edit' as const },\n },\n {\n id: 'agenda.check-availability',\n name: 'checkAvailability',\n description: 'Checks available time slots for a professional on a given date.',\n icon: 'Clock',\n mode: 'read' as const,\n category: 'Scheduling',\n parameters: {\n type: 'object' as const,\n properties: {\n professional: { type: 'string' as const, description: 'Professional name' },\n date: { type: 'string' as const, description: 'Date (YYYY-MM-DD) or \"today\", \"tomorrow\"' },\n duration: { type: 'number' as const, description: 'Required duration in minutes' },\n },\n required: ['professional', 'date'],\n },\n suggestions: [\n { label: 'When is Ana available tomorrow?' },\n { label: 'Find a 90-minute slot for Carlos this week' },\n ],\n permission: { feature: 'agenda', action: 'read' as const },\n },\n ],\n\n registries,\n\n settings: [\n {\n id: 'agenda',\n label: 'Agenda',\n icon: 'Calendar',\n // Standard layout: General | Integrations (Google Calendar addon) | Properties.\n component: (() => {\n const AgendaSettingsTab: React.FC = () => React.createElement(PluginSettingsPanel, {\n title: 'Agenda',\n generalSettings: React.createElement(AgendaGeneralSettings),\n registries,\n hostPluginId: 'agenda',\n routeBase: '/settings/agenda',\n })\n AgendaSettingsTab.displayName = 'AgendaSettingsTab'\n return AgendaSettingsTab as unknown as React.ComponentType<unknown>\n })(),\n order: 5,\n permission: { feature: 'agenda', action: 'read' as const },\n },\n ],\n // Every file, not just the first. The manifest declared one of twenty-one\n // until Phase 2 put this plugin in the canonical chain — a plugin whose SQL\n // is outside its manifest is a plugin whose tables are a coincidence.\n migrations: MIGRATIONS.map((m) => ({\n id: `agenda-${m.id}`,\n version: '1.0.0',\n sql: m.sql,\n description: m.id,\n })),\n\n // Google Calendar is the connector this module's addon already ships;\n // Calendly and WhatsApp are the two the Fayz plugin page has been\n // promising since the catalogue was written.\n integrations: ['google-calendar', 'calendly', 'whatsapp'],\n locales: agendaLocales,\n }\n}\n\n// Re-export types for consumers\nexport type { AgendaPluginOptions } from './config'\nexport type { ResolvedAgendaConfig } from './config'\nexport type { AgendaDataProvider } from './data/types'\n// Seedable in-memory provider — apps pass a seed to render the calendar with\n// app-specific events instead of the built-in salon sample.\nexport { createMockAgendaProvider } from './data/mock'\nexport type { MockAgendaSeed, MockAgendaProviderOptions } from './data/mock'\nexport type { AgendaFinancialBridge, BookingPaymentStatus, BookingPaymentSummary, BookingPaymentDetail } from './bridges/financial-bridge'\nexport { createFinancialBridge, computeCommissionAmount } from './bridges/create-financial-bridge'\n\n// Google Calendar integration (official addon) — settings-only plugin + helpers\nexport { createGoogleCalendarPlugin, createGoogleCalendarProvider, googleCalendarConnector, bookingToEvent, eventToBookingPatch } from './integrations/google-calendar'\n\n// O catálogo de fatos da agenda — exposto para quem quiser ler o contrato sem\n// instalar o módulo (documentação, testes, um consumidor de webhook).\nexport { buildAgendaDomainEvents, buildAgendaMessageDefaults } from './lib/message-events'\n"]}
|