@fayz-ai/plugin-agenda 0.2.1 → 0.8.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.
Files changed (102) hide show
  1. package/README.md +2 -0
  2. package/dist/bridges/create-financial-bridge.d.ts.map +1 -1
  3. package/dist/chunk-DRZF6CV2.js +421 -0
  4. package/dist/chunk-DRZF6CV2.js.map +1 -0
  5. package/dist/chunk-LFUELUIT.cjs +423 -0
  6. package/dist/chunk-LFUELUIT.cjs.map +1 -0
  7. package/dist/config.d.ts +2 -2
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/data/supabase.d.ts.map +1 -1
  10. package/dist/index.cjs +765 -22
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +765 -22
  14. package/dist/index.js.map +1 -1
  15. package/dist/migrations/index.d.ts +9 -0
  16. package/dist/migrations/index.d.ts.map +1 -0
  17. package/dist/public/BookingWidget.d.ts +4 -2
  18. package/dist/public/BookingWidget.d.ts.map +1 -1
  19. package/dist/public/components/BrandHeader.d.ts +6 -0
  20. package/dist/public/components/BrandHeader.d.ts.map +1 -0
  21. package/dist/public/components/ServiceCard.d.ts +5 -0
  22. package/dist/public/components/ServiceCard.d.ts.map +1 -0
  23. package/dist/public/components/SidebarExtras.d.ts +4 -0
  24. package/dist/public/components/SidebarExtras.d.ts.map +1 -0
  25. package/dist/public/components/StepRailItem.d.ts +4 -0
  26. package/dist/public/components/StepRailItem.d.ts.map +1 -0
  27. package/dist/public/components/SuccessPanel.d.ts +4 -0
  28. package/dist/public/components/SuccessPanel.d.ts.map +1 -0
  29. package/dist/public/components/SummaryRail.d.ts +27 -0
  30. package/dist/public/components/SummaryRail.d.ts.map +1 -0
  31. package/dist/public/components/defaults.d.ts +3 -0
  32. package/dist/public/components/defaults.d.ts.map +1 -0
  33. package/dist/public/context.d.ts +22 -8
  34. package/dist/public/context.d.ts.map +1 -1
  35. package/dist/public/createPublicBookingPlugin.d.ts +27 -10
  36. package/dist/public/createPublicBookingPlugin.d.ts.map +1 -1
  37. package/dist/public/data.d.ts +37 -0
  38. package/dist/public/data.d.ts.map +1 -0
  39. package/dist/public/data.supabase.d.ts +7 -0
  40. package/dist/public/data.supabase.d.ts.map +1 -0
  41. package/dist/public/format.d.ts +18 -0
  42. package/dist/public/format.d.ts.map +1 -0
  43. package/dist/public/hooks.d.ts +13 -11
  44. package/dist/public/hooks.d.ts.map +1 -1
  45. package/dist/public/index.cjs +1018 -615
  46. package/dist/public/index.cjs.map +1 -1
  47. package/dist/public/index.d.ts +15 -4
  48. package/dist/public/index.d.ts.map +1 -1
  49. package/dist/public/index.js +1008 -618
  50. package/dist/public/index.js.map +1 -1
  51. package/dist/public/steps/ContactStep.d.ts +30 -0
  52. package/dist/public/steps/ContactStep.d.ts.map +1 -0
  53. package/dist/public/steps/DateTimeStep.d.ts +23 -0
  54. package/dist/public/steps/DateTimeStep.d.ts.map +1 -0
  55. package/dist/public/steps/OverviewStep.d.ts +16 -0
  56. package/dist/public/steps/OverviewStep.d.ts.map +1 -0
  57. package/dist/public/steps/PaymentStep.d.ts +20 -0
  58. package/dist/public/steps/PaymentStep.d.ts.map +1 -0
  59. package/dist/public/types.d.ts +134 -0
  60. package/dist/public/types.d.ts.map +1 -1
  61. package/dist/registries.d.ts.map +1 -1
  62. package/dist/types.d.ts +3 -3
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +11 -5
  65. package/src/bridges/create-financial-bridge.ts +6 -8
  66. package/src/components/AppointmentModal.tsx +4 -4
  67. package/src/config.ts +2 -2
  68. package/src/data/supabase.ts +26 -25
  69. package/src/index.ts +11 -0
  70. package/src/integrations/google-calendar/index.ts +1 -1
  71. package/src/integrations/google-calendar/migrations/001_google_calendar.sql +6 -6
  72. package/src/migrations/000b_v_bookings_rename.sql +21 -0
  73. package/src/migrations/000c_dedupe_customer_phones.sql +43 -0
  74. package/src/migrations/001_public_booking.sql +291 -0
  75. package/src/migrations/002_v_bookings_compat.sql +14 -0
  76. package/src/migrations/index.ts +387 -0
  77. package/src/public/BookingWidget.tsx +136 -713
  78. package/src/public/components/BrandHeader.tsx +27 -0
  79. package/src/public/components/ServiceCard.tsx +39 -0
  80. package/src/public/components/SidebarExtras.tsx +30 -0
  81. package/src/public/components/StepRailItem.tsx +27 -0
  82. package/src/public/components/SuccessPanel.tsx +27 -0
  83. package/src/public/components/SummaryRail.tsx +90 -0
  84. package/src/public/components/defaults.ts +14 -0
  85. package/src/public/context.tsx +64 -7
  86. package/src/public/createPublicBookingPlugin.ts +138 -25
  87. package/src/public/data.supabase.ts +94 -0
  88. package/src/public/data.ts +99 -0
  89. package/src/public/format.ts +61 -0
  90. package/src/public/hooks.ts +22 -34
  91. package/src/public/index.ts +57 -4
  92. package/src/public/steps/ContactStep.tsx +179 -0
  93. package/src/public/steps/DateTimeStep.tsx +138 -0
  94. package/src/public/steps/OverviewStep.tsx +81 -0
  95. package/src/public/steps/PaymentStep.tsx +180 -0
  96. package/src/public/types.ts +169 -3
  97. package/src/registries.ts +1 -2
  98. package/src/types.ts +4 -4
  99. package/dist/chunk-GAJVIEXM.cjs +0 -870
  100. package/dist/chunk-GAJVIEXM.cjs.map +0 -1
  101. package/dist/chunk-U6VTLOHN.js +0 -867
  102. package/dist/chunk-U6VTLOHN.js.map +0 -1
@@ -0,0 +1,9 @@
1
+ export declare 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";
2
+ export declare 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";
3
+ export declare 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\u2013010) does not define:\n-- \u00A70 converted-pool cleanup \u2014 drop the pre-rename v_bookings view / indexes\n-- \u00A71 order_items columns the admin provider writes (duration/assignee)\n-- \u00A72 public.v_appointments \u2014 admin read model (authenticated, RLS applies)\n-- \u00A73 public.v_public_services \u2014 anon-readable service catalog\n-- \u00A74 public.get_available_slots \u2014 anon RPC (mirrors the mock algorithm)\n-- \u00A75 public.create_public_booking \u2014 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 (\u00A73) and SECURITY DEFINER RPCs (\u00A74, \u00A75)\n-- with tight input validation and hardcoded statuses.\n-- ============================================================================\n\n-- \u00A70 \u2014 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 \u2192 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-- \u00A71 \u2014 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-- Upsert key for public customers (per tenant, by normalized phone)\nCREATE UNIQUE 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-- \u00A72 \u2014 admin read model (security_invoker \u2192 underlying RLS applies; anon sees 0 rows)\nCREATE OR REPLACE 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-- \u00A73 \u2014 anon-readable public catalog (owner-rights view = deliberate, whitelisted)\nCREATE OR REPLACE 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-- \u00A74 \u2014 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 \u2192 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-- \u00A75 \u2014 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) \u2014 matches people_tenant_customer_phone\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 ON CONFLICT (tenant_id, phone) WHERE kind = 'customer' AND phone IS NOT NULL\n DO UPDATE SET\n name = EXCLUDED.name,\n email = COALESCE(EXCLUDED.email, people.email),\n updated_at = now()\n RETURNING id INTO v_person_id;\n\n -- order + booking + order_item (statuses hardcoded \u2014 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";
4
+ export declare 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";
5
+ export declare const MIGRATIONS: Array<{
6
+ id: string;
7
+ sql: string;
8
+ }>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gCAAgC,09BAqB5C,CAAA;AAED,eAAO,MAAM,qCAAqC,giDA2CjD,CAAA;AAED,eAAO,MAAM,4BAA4B,mgZAmSxC,CAAA;AAED,eAAO,MAAM,+BAA+B,0sBAc3C,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAKzD,CAAA"}
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Customer-facing booking surface. Default view is an overview (services +
3
3
  * opening hours + CTA) like Quaddro; picking a service — or landing with
4
- * ?service=… — enters a stepped flow (date → time → contact → confirmation)
4
+ * ?service=… — enters a stepped flow (date → time → contact → [payment])
5
5
  * with a live progress + summary rail. Token-only, keyboard-accessible, 44px
6
- * targets. Runs on mock slots today; real availability is a provider swap.
6
+ * targets. Brand-visible parts render via the host-overridable
7
+ * `components`/`brand` seams; data flows through PublicBookingDataProvider
8
+ * (mock seed or Supabase RPCs — same calls).
7
9
  */
8
10
  export declare function BookingWidget(): import("react").JSX.Element;
9
11
  //# sourceMappingURL=BookingWidget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BookingWidget.d.ts","sourceRoot":"","sources":["../../src/public/BookingWidget.tsx"],"names":[],"mappings":"AAmMA;;;;;;GAMG;AACH,wBAAgB,aAAa,gCAirB5B"}
1
+ {"version":3,"file":"BookingWidget.d.ts","sourceRoot":"","sources":["../../src/public/BookingWidget.tsx"],"names":[],"mappings":"AAgBA;;;;;;;;GAQG;AACH,wBAAgB,aAAa,gCAiS5B"}
@@ -0,0 +1,6 @@
1
+ import type { BrandHeaderProps } from '../types';
2
+ /** Default brand header shown above every booking view. Override via
3
+ * `components.BrandHeader` when the structure must change; text/logo-only
4
+ * changes need just the `brand` option. */
5
+ export declare function DefaultBrandHeader({ brand }: BrandHeaderProps): import("react").JSX.Element;
6
+ //# sourceMappingURL=BrandHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrandHeader.d.ts","sourceRoot":"","sources":["../../../src/public/components/BrandHeader.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD;;4CAE4C;AAC5C,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,+BAoB7D"}
@@ -0,0 +1,5 @@
1
+ import type { ServiceCardProps } from '../types';
2
+ /** Default service row (overview list). Icon/badge/meta come from `brand`;
3
+ * swap the whole card via `components.ServiceCard`. */
4
+ export declare function DefaultServiceCard({ service, featured, onSelect, fmt, brand }: ServiceCardProps): import("react").JSX.Element;
5
+ //# sourceMappingURL=ServiceCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceCard.d.ts","sourceRoot":"","sources":["../../../src/public/components/ServiceCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD;wDACwD;AACxD,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,gBAAgB,+BAiC/F"}
@@ -0,0 +1,4 @@
1
+ import type { SidebarExtrasProps } from '../types';
2
+ /** Default overview sidebar: primary CTA + brand highlights + professional. */
3
+ export declare function DefaultSidebarExtras({ professionalName, brand, onStartBooking, labels }: SidebarExtrasProps): import("react").JSX.Element;
4
+ //# sourceMappingURL=SidebarExtras.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarExtras.d.ts","sourceRoot":"","sources":["../../../src/public/components/SidebarExtras.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAElD,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,kBAAkB,+BAyB3G"}
@@ -0,0 +1,4 @@
1
+ import type { StepRailItemProps } from '../types';
2
+ /** One row in the wizard's right-hand progress rail. */
3
+ export declare function DefaultStepRailItem({ n, label, state, children }: StepRailItemProps): import("react").JSX.Element;
4
+ //# sourceMappingURL=StepRailItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StepRailItem.d.ts","sourceRoot":"","sources":["../../../src/public/components/StepRailItem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjD,wDAAwD;AACxD,wBAAgB,mBAAmB,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,iBAAiB,+BAsBnF"}
@@ -0,0 +1,4 @@
1
+ import type { SuccessPanelProps } from '../types';
2
+ /** Default confirmation panel (final step). */
3
+ export declare function DefaultSuccessPanel({ service, slotStart, professionalName, labels, fmt }: SuccessPanelProps): import("react").JSX.Element;
4
+ //# sourceMappingURL=SuccessPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SuccessPanel.d.ts","sourceRoot":"","sources":["../../../src/public/components/SuccessPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjD,+CAA+C;AAC/C,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,iBAAiB,+BAqB3G"}
@@ -0,0 +1,27 @@
1
+ import type { BookingComponents, BookingFormatters, PublicBookingLabels, PublicService, ResolvedPayment, StepState } from '../types';
2
+ export interface RailState {
3
+ service: StepState;
4
+ professional: StepState;
5
+ datetime: StepState;
6
+ contact: StepState;
7
+ payment: StepState;
8
+ }
9
+ interface SummaryRailProps {
10
+ title: string;
11
+ railState: RailState;
12
+ service: PublicService | null;
13
+ professionalName: string;
14
+ slotStart: string | null;
15
+ /** Display string for the verified contact ("Nome · +55 (11) …"), or null. */
16
+ contactSummary: string | null;
17
+ payment: ResolvedPayment | null;
18
+ paymentReached: boolean;
19
+ labels: PublicBookingLabels;
20
+ fmt: BookingFormatters;
21
+ components: BookingComponents;
22
+ serviceMeta: string | null;
23
+ }
24
+ /** Right-hand progress + summary rail (internal; rows via components.StepRailItem). */
25
+ export declare function SummaryRail({ title, railState, service, professionalName, slotStart, contactSummary, payment, paymentReached, labels, fmt, components: C, serviceMeta, }: SummaryRailProps): import("react").JSX.Element;
26
+ export {};
27
+ //# sourceMappingURL=SummaryRail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SummaryRail.d.ts","sourceRoot":"","sources":["../../../src/public/components/SummaryRail.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,SAAS,EACV,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,SAAS,CAAA;IAClB,YAAY,EAAE,SAAS,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;IACnB,OAAO,EAAE,SAAS,CAAA;IAClB,OAAO,EAAE,SAAS,CAAA;CACnB;AAED,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;IAC/B,cAAc,EAAE,OAAO,CAAA;IACvB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,GAAG,EAAE,iBAAiB,CAAA;IACtB,UAAU,EAAE,iBAAiB,CAAA;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EACtE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,WAAW,GACjE,EAAE,gBAAgB,+BAkDlB"}
@@ -0,0 +1,3 @@
1
+ import type { BookingComponents } from '../types';
2
+ export declare const DEFAULT_BOOKING_COMPONENTS: BookingComponents;
3
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/public/components/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAOjD,eAAO,MAAM,0BAA0B,EAAE,iBAMxC,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { PaymentProvider } from '@fayz-ai/core';
3
- import type { AgendaDataProvider } from '../data/types';
4
- import type { PublicService, BookingWindow, PublicBookingLabels, WorkingHours, ResolvedPayment } from './types';
3
+ import type { PublicBookingDataProvider } from './data';
4
+ import type { BookingComponents, BookingWindow, PublicBookingLabels, PublicService, ResolvedBookingBrand, ResolvedPayment, WorkingHours } from './types';
5
5
  /** Emitted when the customer's phone is verified / identity captured, for the
6
6
  * host to bridge to auth (booking stays decoupled — data-only, optional). */
7
7
  export type OnIdentityVerified = (identity: {
@@ -10,11 +10,13 @@ export type OnIdentityVerified = (identity: {
10
10
  email?: string;
11
11
  }) => void;
12
12
  export interface PublicBookingContextValue {
13
- provider: AgendaDataProvider;
14
- /** The professional/resource bookings are created against (POC: single professional). */
15
- professionalId: string;
13
+ provider: PublicBookingDataProvider;
14
+ /** The professional/resource bookings are created against; null → any. */
15
+ professionalId: string | null;
16
16
  professionalName: string;
17
+ /** Resolved catalog: static `services` option, or fetched from the provider. */
17
18
  services: PublicService[];
19
+ servicesLoading: boolean;
18
20
  /** Business opening hours, shown on the overview "Sobre" section. */
19
21
  businessHours: WorkingHours;
20
22
  /** Payment step config, or null when the flow ends at confirmation. */
@@ -25,13 +27,25 @@ export interface PublicBookingContextValue {
25
27
  onIdentityVerified: OnIdentityVerified | null;
26
28
  window: BookingWindow;
27
29
  labels: PublicBookingLabels;
30
+ /** Brand personalization (resolved with defaults). */
31
+ brand: ResolvedBookingBrand;
32
+ /** Host-overridable subcomponents (resolved with defaults). */
33
+ components: BookingComponents;
28
34
  /** Currency code for price formatting (e.g. 'BRL'). */
29
35
  currency: string;
30
36
  locale: string;
31
37
  }
32
- export declare function BookingProvider({ value, children }: {
33
- value: PublicBookingContextValue;
38
+ export interface BookingProviderProps {
39
+ /** Everything but the (possibly async) service catalog. */
40
+ base: Omit<PublicBookingContextValue, 'services' | 'servicesLoading'>;
41
+ /** Static catalog from options — wins over the provider fetch when present. */
42
+ staticServices: PublicService[] | null;
34
43
  children: ReactNode;
35
- }): import("react").JSX.Element;
44
+ }
45
+ /**
46
+ * Owns the service-catalog resolution: static services pass through untouched;
47
+ * otherwise the provider is queried once (e.g. Supabase v_public_services).
48
+ */
49
+ export declare function BookingProvider({ base, staticServices, children }: BookingProviderProps): import("react").JSX.Element;
36
50
  export declare function useBooking(): PublicBookingContextValue;
37
51
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/public/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE/G;8EAC8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAA;AAEpG,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAA;IACtB,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,qEAAqE;IACrE,aAAa,EAAE,YAAY,CAAA;IAC3B,uEAAuE;IACvE,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;IAC/B,gFAAgF;IAChF,eAAe,EAAE,eAAe,GAAG,IAAI,CAAA;IACvC,+EAA+E;IAC/E,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC7C,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;IAAE,KAAK,EAAE,yBAAyB,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAE7G;AAED,wBAAgB,UAAU,IAAI,yBAAyB,CAMtD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/public/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC/F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,YAAY,EACb,MAAM,SAAS,CAAA;AAEhB;8EAC8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG,CAAC,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAA;AAEpG,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,yBAAyB,CAAA;IACnC,0EAA0E;IAC1E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gFAAgF;IAChF,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,eAAe,EAAE,OAAO,CAAA;IACxB,qEAAqE;IACrE,aAAa,EAAE,YAAY,CAAA;IAC3B,uEAAuE;IACvE,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;IAC/B,gFAAgF;IAChF,eAAe,EAAE,eAAe,GAAG,IAAI,CAAA;IACvC,+EAA+E;IAC/E,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC7C,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,mBAAmB,CAAA;IAC3B,sDAAsD;IACtD,KAAK,EAAE,oBAAoB,CAAA;IAC3B,+DAA+D;IAC/D,UAAU,EAAE,iBAAiB,CAAA;IAC7B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAID,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,IAAI,EAAE,IAAI,CAAC,yBAAyB,EAAE,UAAU,GAAG,iBAAiB,CAAC,CAAA;IACrE,+EAA+E;IAC/E,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAA;IACtC,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,oBAAoB,+BAiCvF;AAED,wBAAgB,UAAU,IAAI,yBAAyB,CAMtD"}
@@ -1,24 +1,41 @@
1
1
  import { type FC, type ReactNode } from 'react';
2
2
  import type { PluginManifest, PluginScope, VerticalId, PaymentProvider } from '@fayz-ai/core';
3
- import type { AgendaDataProvider } from '../data/types';
4
- import { type MockAgendaSeed } from '../data/mock';
3
+ import type { MockAgendaSeed } from '../data/mock';
4
+ import { type PublicBookingDataProvider } from './data';
5
5
  import { type OnIdentityVerified } from './context';
6
- import type { PublicService, BookingWindow, PublicBookingLabels, WorkingHours, PaymentConfig } from './types';
6
+ import type { BookingBrand, BookingComponents, BookingWindow, PaymentConfig, PublicBookingLabels, PublicService, WorkingHours } from './types';
7
7
  export interface PublicBookingOptions {
8
8
  /** Mount path for the public booking route. Default '/agendar'. */
9
9
  basePath?: string;
10
- /** The single professional/resource bookings target (POC). */
10
+ /**
11
+ * Tenant this public page books against. REQUIRED when a Supabase client is
12
+ * configured (setGlobalSupabaseClient) — it scopes services/slots/bookings.
13
+ */
14
+ tenantId?: string;
15
+ /**
16
+ * The single professional/resource bookings target. With Supabase this must
17
+ * be the staff person UUID; omit → any active professional (RPC unions
18
+ * schedules across staff).
19
+ */
11
20
  professional?: {
12
21
  id?: string;
13
22
  name?: string;
14
23
  };
15
- /** Bookable services shown in the widget. */
16
- services: PublicService[];
17
- /** Working hours used to seed the mock provider's availability. */
24
+ /**
25
+ * Bookable services. Optional: when omitted, the widget fetches the catalog
26
+ * from the provider (Supabase v_public_services). Static wins when provided.
27
+ */
28
+ services?: PublicService[];
29
+ /** Working hours used to seed mock availability + the overview "Sobre" card. */
18
30
  workingHours?: WorkingHours;
19
31
  /** Booking-window bounds for the date/slot picker. */
20
32
  window?: Partial<BookingWindow>;
33
+ /** Every user-visible string (all defaulted, pt-BR). */
21
34
  labels?: Partial<PublicBookingLabels>;
35
+ /** Brand personalization: name/logo/tagline/icons/badges/highlights. */
36
+ brand?: BookingBrand;
37
+ /** Swap whole subcomponents when structure must change (defaults exported). */
38
+ components?: Partial<BookingComponents>;
22
39
  /** Adds a final Pagamento (Pix) step. Omit/disable to end the flow at confirmation. */
23
40
  payment?: PaymentConfig;
24
41
  /** Charge provider (from a payments plugin) used by the Pagamento step. Optional. */
@@ -27,8 +44,8 @@ export interface PublicBookingOptions {
27
44
  onIdentityVerified?: OnIdentityVerified;
28
45
  currency?: string;
29
46
  locale?: string;
30
- /** Inject a custom provider (real availability). Overrides the safe resolver. */
31
- dataProvider?: AgendaDataProvider;
47
+ /** Inject a custom provider (overrides the mock/Supabase safe resolver). */
48
+ dataProvider?: PublicBookingDataProvider;
32
49
  /** Override the full mock seed (advanced). */
33
50
  seed?: MockAgendaSeed;
34
51
  scope?: PluginScope;
@@ -39,7 +56,7 @@ export interface PublicBookingPlugin {
39
56
  Provider: FC<{
40
57
  children: ReactNode;
41
58
  }>;
42
- dataProvider: AgendaDataProvider;
59
+ dataProvider: PublicBookingDataProvider;
43
60
  }
44
61
  export declare function createPublicBookingPlugin(options: PublicBookingOptions): PublicBookingPlugin;
45
62
  //# sourceMappingURL=createPublicBookingPlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createPublicBookingPlugin.d.ts","sourceRoot":"","sources":["../../src/public/createPublicBookingPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAE5E,OAAO,EAAmD,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAEpG,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAmB,MAAM,SAAS,CAAA;AAE9H,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8DAA8D;IAC9D,YAAY,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C,6CAA6C;IAC7C,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,mEAAmE;IACnE,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACrC,uFAAuF;IACvF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,qFAAqF;IACrF,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iFAAiF;IACjF,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAE,EAAE,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IACrC,YAAY,EAAE,kBAAkB,CAAA;CACjC;AAkCD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CA6E5F"}
1
+ {"version":3,"file":"createPublicBookingPlugin.d.ts","sourceRoot":"","sources":["../../src/public/createPublicBookingPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAmC,KAAK,yBAAyB,EAAE,MAAM,QAAQ,CAAA;AAExF,OAAO,EAAmD,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAGpG,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,aAAa,EAGb,YAAY,EACb,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAA;IAC1B,gFAAgF;IAChF,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/B,wDAAwD;IACxD,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACrC,wEAAwE;IACxE,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACvC,uFAAuF;IACvF,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,qFAAqF;IACrF,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,YAAY,CAAC,EAAE,yBAAyB,CAAA;IACxC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAE,EAAE,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IACrC,YAAY,EAAE,yBAAyB,CAAA;CACxC;AAiGD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAmG5F"}
@@ -0,0 +1,37 @@
1
+ import type { TimeSlot } from '../types';
2
+ import { type MockAgendaSeed } from '../data/mock';
3
+ import type { PublicService, ContactInfo } from './types';
4
+ export interface PublicSlotQuery {
5
+ /** Staff person id; null → any active professional for the tenant. */
6
+ assigneeId: string | null;
7
+ /** 'YYYY-MM-DD' local calendar day. */
8
+ date: string;
9
+ durationMinutes: number;
10
+ slotInterval: number;
11
+ }
12
+ export interface PublicCreateBookingInput {
13
+ serviceId: string;
14
+ /** ISO datetime of the chosen slot start. */
15
+ startsAt: string;
16
+ /** name required; phone should include the country dial for real backends. */
17
+ contact: ContactInfo;
18
+ }
19
+ export interface PublicBookingResult {
20
+ bookingId: string;
21
+ startsAt: string;
22
+ endsAt: string;
23
+ }
24
+ export interface PublicBookingDataProvider {
25
+ /** Bookable catalog. Used when the host doesn't pass static `services`. */
26
+ getServices(): Promise<PublicService[]>;
27
+ getAvailableSlots(query: PublicSlotQuery): Promise<TimeSlot[]>;
28
+ createBooking(input: PublicCreateBookingInput): Promise<PublicBookingResult>;
29
+ }
30
+ export interface MockPublicBookingOptions {
31
+ seed: MockAgendaSeed;
32
+ services: PublicService[];
33
+ /** The seed professional bookings are created against. */
34
+ professionalId: string;
35
+ }
36
+ export declare function createMockPublicBookingProvider(options: MockPublicBookingOptions): PublicBookingDataProvider;
37
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/public/data.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAEzD,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,WAAW,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAAA;IACvC,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC9D,aAAa,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;CAC7E;AAOD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,cAAc,CAAA;IACpB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,wBAAwB,GAAG,yBAAyB,CA4C5G"}
@@ -0,0 +1,7 @@
1
+ import type { PublicBookingDataProvider } from './data';
2
+ export interface SupabasePublicBookingOptions {
3
+ /** The tenant this public page books against (RPC arg — required). */
4
+ tenantId: string;
5
+ }
6
+ export declare function createSupabasePublicBookingProvider(options: SupabasePublicBookingOptions): PublicBookingDataProvider;
7
+ //# sourceMappingURL=data.supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.supabase.d.ts","sourceRoot":"","sources":["../../src/public/data.supabase.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAA;AAEvD,MAAM,WAAW,4BAA4B;IAC3C,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAA;CACjB;AAkBD,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,4BAA4B,GAAG,yBAAyB,CAsDpH"}
@@ -0,0 +1,18 @@
1
+ import type { BookingFormatters } from './types';
2
+ export declare const DAY_NAMES: string[];
3
+ export declare const WEEK_ORDER: number[];
4
+ export declare function useFormatters(locale: string, currency: string): BookingFormatters;
5
+ /** Local 'YYYY-MM-DD' for a Date. */
6
+ export declare function toIso(d: Date): string;
7
+ /** Read a preselected service id from the URL (?service=…), router-agnostic. */
8
+ export declare function readServiceParam(): string | null;
9
+ export interface DayCell {
10
+ iso: string;
11
+ date: Date;
12
+ isToday: boolean;
13
+ }
14
+ /** 7 consecutive days starting `weekOffset*7` days from today. */
15
+ export declare function buildWeek(weekOffset: number): DayCell[];
16
+ /** "13/07/2026 – 21:30 até 22:00 (30min)" */
17
+ export declare function formatSlotRange(startIso: string, durationMin: number, fmt: BookingFormatters): string;
18
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/public/format.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,eAAO,MAAM,SAAS,UAAuG,CAAA;AAC7H,eAAO,MAAM,UAAU,UAAwB,CAAA;AAE/C,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAajF;AAED,qCAAqC;AACrC,wBAAgB,KAAK,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAErC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAGhD;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CASvD;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAIrG"}
@@ -1,7 +1,14 @@
1
- import type { PublicService, ContactInfo } from './types';
1
+ import type { PublicService } from './types';
2
+ import type { PublicCreateBookingInput, PublicBookingResult } from './data';
2
3
  import type { TimeSlot } from '../types';
3
- /** The configured bookable services (from context; POC-static, ERP-driven later). */
4
+ /** The resolved bookable services (static option or fetched from the provider). */
4
5
  export declare function useServices(): PublicService[];
6
+ export interface UsePublicServicesResult {
7
+ services: PublicService[];
8
+ loading: boolean;
9
+ }
10
+ /** Like useServices, but exposes the fetch state for skeletons. */
11
+ export declare function usePublicServices(): UsePublicServicesResult;
5
12
  export interface UseAvailableSlotsResult {
6
13
  slots: TimeSlot[];
7
14
  loading: boolean;
@@ -9,24 +16,19 @@ export interface UseAvailableSlotsResult {
9
16
  }
10
17
  /**
11
18
  * Available time slots for a service on a given date. Delegates to
12
- * provider.getAvailableSlots — mock now, real availability later, same call.
19
+ * provider.getAvailableSlots — mock now, Supabase RPC when configured, same call.
13
20
  */
14
21
  export declare function useAvailableSlots(params: {
15
22
  serviceId: string | null;
16
23
  date: string | null;
17
24
  }): UseAvailableSlotsResult;
18
- export interface CreatePublicBookingInput {
19
- serviceId: string;
20
- /** ISO datetime of the chosen slot start. */
21
- startsAt: string;
22
- contact: ContactInfo;
23
- }
25
+ export type CreatePublicBookingInput = PublicCreateBookingInput;
24
26
  export interface UseCreateBookingResult {
25
- submit: (input: CreatePublicBookingInput) => Promise<void>;
27
+ submit: (input: CreatePublicBookingInput) => Promise<PublicBookingResult>;
26
28
  submitting: boolean;
27
29
  error: Error | null;
28
30
  done: boolean;
29
31
  }
30
- /** Create a booking via the provider. POC: mock append; real persistence later. */
32
+ /** Create a booking via the provider (mock append / Supabase RPC). */
31
33
  export declare function useCreateBooking(): UseCreateBookingResult;
32
34
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/public/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,qFAAqF;AACrF,wBAAgB,WAAW,IAAI,aAAa,EAAE,CAE7C;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,uBAAuB,CAqCpH;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,IAAI,sBAAsB,CA0CzD"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/public/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,KAAK,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,mFAAmF;AACnF,wBAAgB,WAAW,IAAI,aAAa,EAAE,CAE7C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,IAAI,uBAAuB,CAG3D;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,uBAAuB,CAqCpH;AAED,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,CAAA;AAE/D,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACzE,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,IAAI,sBAAsB,CAuBzD"}