@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
@@ -1,14 +1,130 @@
1
1
  'use strict';
2
2
 
3
- var chunkGAJVIEXM_cjs = require('../chunk-GAJVIEXM.cjs');
4
- require('../chunk-SYDBDI3Q.cjs');
3
+ var chunkLFUELUIT_cjs = require('../chunk-LFUELUIT.cjs');
5
4
  var react = require('react');
5
+ var lucideReact = require('lucide-react');
6
6
  var core = require('@fayz-ai/core');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
- var lucideReact = require('lucide-react');
9
8
 
9
+ // src/public/data.ts
10
+ function createMockPublicBookingProvider(options) {
11
+ const inner = chunkLFUELUIT_cjs.createMockAgendaProvider({ seed: options.seed });
12
+ const { services, professionalId } = options;
13
+ return {
14
+ async getServices() {
15
+ return services;
16
+ },
17
+ async getAvailableSlots(query) {
18
+ return inner.getAvailableSlots({
19
+ assigneeId: query.assigneeId ?? professionalId,
20
+ date: query.date,
21
+ durationMinutes: query.durationMinutes,
22
+ slotInterval: query.slotInterval
23
+ });
24
+ },
25
+ async createBooking(input) {
26
+ const service = services.find((s) => s.id === input.serviceId);
27
+ if (!service) throw new Error("Servi\xE7o inv\xE1lido");
28
+ const booking = await inner.createBooking({
29
+ kind: "appointment",
30
+ // Mock: the customer is captured as the booking title; the Supabase
31
+ // path upserts a person record server-side instead.
32
+ clientId: "public-guest",
33
+ professionalId,
34
+ startsAt: input.startsAt,
35
+ title: input.contact.name,
36
+ notes: [input.contact.phone, input.contact.email, input.contact.notes].filter(Boolean).join(" \xB7 ") || void 0,
37
+ services: [
38
+ {
39
+ serviceId: service.id,
40
+ name: service.name,
41
+ durationMinutes: service.durationMinutes,
42
+ price: service.price,
43
+ assigneeId: professionalId
44
+ }
45
+ ]
46
+ });
47
+ const endsAt = booking.endsAt ?? new Date(new Date(input.startsAt).getTime() + service.durationMinutes * 6e4).toISOString();
48
+ return { bookingId: booking.id, startsAt: booking.startsAt, endsAt };
49
+ }
50
+ };
51
+ }
52
+ function getClient() {
53
+ return core.getSupabaseClientOptional() ?? core.getFayzCloudClient();
54
+ }
55
+ function toPhoneDigits(phone) {
56
+ return (phone ?? "").replace(/\D/g, "");
57
+ }
58
+ function createSupabasePublicBookingProvider(options) {
59
+ const { tenantId } = options;
60
+ return {
61
+ async getServices() {
62
+ const { data, error } = await getClient().from("v_public_services").select("id, name, description, price, currency, duration_minutes, sort_order").eq("tenant_id", tenantId).order("sort_order", { ascending: true });
63
+ if (error) throw new Error(`[plugin-agenda/public] getServices: ${error.message}`);
64
+ return (data ?? []).map((row) => ({
65
+ id: String(row.id),
66
+ name: String(row.name),
67
+ description: row.description ?? void 0,
68
+ price: Number(row.price ?? 0),
69
+ durationMinutes: Number(row.duration_minutes ?? 30)
70
+ }));
71
+ },
72
+ async getAvailableSlots(query) {
73
+ const { data, error } = await getClient().rpc("get_available_slots", {
74
+ p_tenant_id: tenantId,
75
+ p_assignee_id: query.assigneeId,
76
+ p_date: query.date,
77
+ p_duration_minutes: query.durationMinutes,
78
+ p_slot_interval: query.slotInterval
79
+ });
80
+ if (error) throw new Error(`[plugin-agenda/public] getAvailableSlots: ${error.message}`);
81
+ return (data ?? []).map((row) => ({
82
+ start: row.slot_start,
83
+ end: row.slot_end
84
+ }));
85
+ },
86
+ async createBooking(input) {
87
+ const phone = toPhoneDigits(input.contact.phone);
88
+ const { data, error } = await getClient().rpc("create_public_booking", {
89
+ p_tenant_id: tenantId,
90
+ p_service_id: input.serviceId,
91
+ p_starts_at: input.startsAt,
92
+ p_name: input.contact.name.trim(),
93
+ p_phone: phone,
94
+ p_email: input.contact.email?.trim() || null,
95
+ p_notes: input.contact.notes?.trim() || null
96
+ });
97
+ if (error) throw new Error(`[plugin-agenda/public] createBooking: ${error.message}`);
98
+ const row = Array.isArray(data) ? data[0] : data;
99
+ if (!row) throw new Error("[plugin-agenda/public] createBooking: empty RPC response");
100
+ return { bookingId: row.booking_id, startsAt: row.starts_at, endsAt: row.ends_at };
101
+ }
102
+ };
103
+ }
10
104
  var PublicBookingContext = react.createContext(null);
11
- function BookingProvider({ value, children }) {
105
+ function BookingProvider({ base, staticServices, children }) {
106
+ const [fetched, setFetched] = react.useState(null);
107
+ const [loading, setLoading] = react.useState(staticServices === null);
108
+ react.useEffect(() => {
109
+ if (staticServices !== null) return;
110
+ let active = true;
111
+ setLoading(true);
112
+ base.provider.getServices().then((result) => {
113
+ if (active) setFetched(result);
114
+ }).catch((err) => {
115
+ console.error("[plugin-agenda/public] failed to load services:", err);
116
+ if (active) setFetched([]);
117
+ }).finally(() => {
118
+ if (active) setLoading(false);
119
+ });
120
+ return () => {
121
+ active = false;
122
+ };
123
+ }, [base.provider, staticServices]);
124
+ const value = react.useMemo(
125
+ () => ({ ...base, services: staticServices ?? fetched ?? [], servicesLoading: loading }),
126
+ [base, staticServices, fetched, loading]
127
+ );
12
128
  return /* @__PURE__ */ jsxRuntime.jsx(PublicBookingContext.Provider, { value, children });
13
129
  }
14
130
  function useBooking() {
@@ -21,6 +137,10 @@ function useBooking() {
21
137
  function useServices() {
22
138
  return useBooking().services;
23
139
  }
140
+ function usePublicServices() {
141
+ const { services, servicesLoading } = useBooking();
142
+ return { services, loading: servicesLoading };
143
+ }
24
144
  function useAvailableSlots(params) {
25
145
  const { provider, professionalId, services, window: window2 } = useBooking();
26
146
  const [slots, setSlots] = react.useState([]);
@@ -53,36 +173,17 @@ function useAvailableSlots(params) {
53
173
  return { slots, loading, error };
54
174
  }
55
175
  function useCreateBooking() {
56
- const { provider, professionalId, services } = useBooking();
176
+ const { provider } = useBooking();
57
177
  const [submitting, setSubmitting] = react.useState(false);
58
178
  const [error, setError] = react.useState(null);
59
179
  const [done, setDone] = react.useState(false);
60
180
  async function submit(input) {
61
- const service = services.find((s) => s.id === input.serviceId);
62
- if (!service) throw new Error("Servi\xE7o inv\xE1lido");
63
181
  setSubmitting(true);
64
182
  setError(null);
65
183
  try {
66
- await provider.createBooking({
67
- kind: "appointment",
68
- // POC: the customer is captured as the booking title; a real flow would
69
- // upsert a client/person record and pass its id here.
70
- clientId: "public-guest",
71
- professionalId,
72
- startsAt: input.startsAt,
73
- title: input.contact.name,
74
- notes: [input.contact.phone, input.contact.email, input.contact.notes].filter(Boolean).join(" \xB7 ") || void 0,
75
- services: [
76
- {
77
- serviceId: service.id,
78
- name: service.name,
79
- durationMinutes: service.durationMinutes,
80
- price: service.price,
81
- assigneeId: professionalId
82
- }
83
- ]
84
- });
184
+ const result = await provider.createBooking(input);
85
185
  setDone(true);
186
+ return result;
86
187
  } catch (err) {
87
188
  const e = err instanceof Error ? err : new Error(String(err));
88
189
  setError(e);
@@ -131,7 +232,368 @@ function formatSlotRange(startIso, durationMin, fmt) {
131
232
  const end = new Date(start.getTime() + durationMin * 6e4);
132
233
  return `${fmt.dateShort.format(start)} \u2013 ${fmt.time.format(start)} at\xE9 ${fmt.time.format(end)} (${durationMin}min)`;
133
234
  }
134
- var PIX_PAYLOAD = "00020126840014br.gov.bcb.pix2562qrcode.hempdent.com.br/pix/v2/9d8f7a6b-consulta-canabica5204000053039865802BR5913HEMPDENT6009SAO PAULO62070503***6304AB12";
235
+ function OverviewStep({
236
+ services,
237
+ servicesLoading,
238
+ businessHours,
239
+ professionalName,
240
+ labels,
241
+ brand,
242
+ fmt,
243
+ components: C,
244
+ onStartBooking
245
+ }) {
246
+ const openDays = new Set(businessHours.daysOfWeek);
247
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_18rem]", children: [
248
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
249
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "rounded-2xl border border-border bg-card p-6 shadow-sm", children: [
250
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-4 font-heading text-lg font-bold text-foreground", children: labels.servicesHeading }),
251
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: servicesLoading ? Array.from({ length: 2 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-24 animate-pulse rounded-2xl bg-muted" }, i)) : services.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
252
+ C.ServiceCard,
253
+ {
254
+ service: s,
255
+ featured: i === 0,
256
+ onSelect: () => onStartBooking(s.id),
257
+ fmt,
258
+ brand
259
+ },
260
+ s.id
261
+ )) })
262
+ ] }),
263
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "rounded-2xl border border-border bg-card p-6 shadow-sm", children: [
264
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-lg font-bold text-foreground", children: labels.aboutHeading }),
265
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 mb-2 flex items-center gap-1.5 text-sm font-medium text-muted-foreground", children: [
266
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" }),
267
+ " ",
268
+ labels.openingHoursHeading
269
+ ] }),
270
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "divide-y divide-border border-l-2 border-primary/20 pl-4", children: WEEK_ORDER.map((day) => {
271
+ const open = openDays.has(day);
272
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between py-2 text-sm", children: [
273
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: DAY_NAMES[day] }),
274
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: open ? "tabular-nums text-foreground" : "text-muted-foreground", children: open ? `${businessHours.start} \u2013 ${businessHours.end}` : labels.closedLabel })
275
+ ] }, day);
276
+ }) })
277
+ ] })
278
+ ] }),
279
+ /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "lg:sticky lg:top-24 lg:self-start", children: /* @__PURE__ */ jsxRuntime.jsx(
280
+ C.SidebarExtras,
281
+ {
282
+ professionalName,
283
+ brand,
284
+ labels,
285
+ onStartBooking: () => onStartBooking()
286
+ }
287
+ ) })
288
+ ] });
289
+ }
290
+ function DateTimeStep({
291
+ labels,
292
+ fmt,
293
+ week,
294
+ weekOffset,
295
+ maxWeekOffset,
296
+ onWeekOffset,
297
+ businessHours,
298
+ date,
299
+ onSelectDate,
300
+ slots,
301
+ slotsLoading,
302
+ slotStart,
303
+ onSelectSlot,
304
+ onContinue
305
+ }) {
306
+ const openDays = new Set(businessHours.daysOfWeek);
307
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
308
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [
309
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-xl font-bold text-foreground", children: labels.dateStep }),
310
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
311
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3.5 w-3.5" }),
312
+ " ",
313
+ labels.timezoneNote
314
+ ] })
315
+ ] }),
316
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 flex items-center justify-between", children: [
317
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold capitalize text-foreground", children: fmt.month.format(week[0].date) }),
318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
319
+ /* @__PURE__ */ jsxRuntime.jsx(
320
+ "button",
321
+ {
322
+ type: "button",
323
+ disabled: weekOffset === 0,
324
+ onClick: () => onWeekOffset((w) => Math.max(0, w - 1)),
325
+ className: "flex h-9 w-9 items-center justify-center rounded-lg border border-border text-foreground transition-colors hover:bg-accent disabled:opacity-40 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
326
+ "aria-label": labels.prevWeek,
327
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
328
+ }
329
+ ),
330
+ /* @__PURE__ */ jsxRuntime.jsx(
331
+ "button",
332
+ {
333
+ type: "button",
334
+ disabled: weekOffset >= maxWeekOffset,
335
+ onClick: () => onWeekOffset((w) => Math.min(maxWeekOffset, w + 1)),
336
+ className: "flex h-9 w-9 items-center justify-center rounded-lg border border-border text-foreground transition-colors hover:bg-accent disabled:opacity-40 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
337
+ "aria-label": labels.nextWeek,
338
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
339
+ }
340
+ )
341
+ ] })
342
+ ] }),
343
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 grid grid-cols-7 gap-1.5", children: week.map((d) => {
344
+ const selected = date === d.iso;
345
+ const closed = !openDays.has(d.date.getDay());
346
+ return /* @__PURE__ */ jsxRuntime.jsxs(
347
+ "button",
348
+ {
349
+ type: "button",
350
+ disabled: closed,
351
+ onClick: () => onSelectDate(d.iso),
352
+ className: [
353
+ "flex flex-col items-center gap-0.5 rounded-xl border py-2.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
354
+ closed ? "cursor-not-allowed border-transparent text-muted-foreground/40" : selected ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary/60 hover:bg-accent/40"
355
+ ].join(" "),
356
+ children: [
357
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium capitalize opacity-80", children: fmt.weekday.format(d.date).replace(".", "") }),
358
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold tabular-nums", children: fmt.dayNum.format(d.date) })
359
+ ]
360
+ },
361
+ d.iso
362
+ );
363
+ }) }),
364
+ date ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6", children: [
365
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-sm font-semibold text-foreground", children: labels.slotsHeading }),
366
+ slotsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2 sm:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 animate-pulse rounded-lg bg-muted" }, i)) }) : slots.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-dashed border-border p-6 text-center text-sm text-muted-foreground", children: labels.noSlots }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2 sm:grid-cols-4", children: slots.map((s) => {
367
+ const selected = slotStart === s.start;
368
+ return /* @__PURE__ */ jsxRuntime.jsx(
369
+ "button",
370
+ {
371
+ type: "button",
372
+ onClick: () => onSelectSlot(s.start),
373
+ className: [
374
+ "rounded-lg border py-2.5 text-sm font-semibold tabular-nums transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
375
+ selected ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary/60 hover:bg-accent/40"
376
+ ].join(" "),
377
+ children: fmt.time.format(new Date(s.start))
378
+ },
379
+ s.start
380
+ );
381
+ }) })
382
+ ] }) : null,
383
+ /* @__PURE__ */ jsxRuntime.jsx(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ disabled: !slotStart,
388
+ onClick: onContinue,
389
+ className: "mt-6 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
390
+ children: labels.continueCta
391
+ }
392
+ )
393
+ ] });
394
+ }
395
+ function ContactStep({
396
+ labels,
397
+ contact,
398
+ onContactChange,
399
+ contactStep,
400
+ country,
401
+ onCountryChange,
402
+ code,
403
+ onCodeChange,
404
+ codeError,
405
+ onSendCode,
406
+ onConfirmCode,
407
+ onBackToPhone,
408
+ onSubmitDetails,
409
+ payment,
410
+ submitting,
411
+ error
412
+ }) {
413
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
414
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-xl font-bold text-foreground", children: labels.contactStep }),
415
+ contactStep === "phone" ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
416
+ e.preventDefault();
417
+ onSendCode();
418
+ }, children: [
419
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: labels.contactIntro }),
420
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5", children: [
421
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-phone", className: "mb-1 block text-sm font-medium text-foreground", children: labels.phoneLabel }),
422
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
423
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
424
+ /* @__PURE__ */ jsxRuntime.jsx(
425
+ "select",
426
+ {
427
+ "aria-label": "Pa\xEDs",
428
+ value: country.iso2,
429
+ onChange: (e) => onCountryChange(e.target.value),
430
+ className: "h-full appearance-none rounded-l-xl border border-r-0 border-border bg-muted py-3 pl-3 pr-8 text-sm font-medium text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring",
431
+ children: core.COUNTRIES.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.iso2, children: [
432
+ c.flag,
433
+ " ",
434
+ c.dial
435
+ ] }, c.iso2))
436
+ }
437
+ ),
438
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" })
439
+ ] }),
440
+ /* @__PURE__ */ jsxRuntime.jsx(
441
+ "input",
442
+ {
443
+ id: "bk-phone",
444
+ type: "tel",
445
+ autoComplete: "tel",
446
+ inputMode: "tel",
447
+ value: contact.phone,
448
+ onChange: (e) => onContactChange({ ...contact, phone: core.maskPhone(e.target.value, country.mask) }),
449
+ className: "w-full rounded-r-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
450
+ placeholder: `Ex.: ${core.maskPhone("11987654321", country.mask)}`
451
+ }
452
+ )
453
+ ] }),
454
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: labels.phoneHint })
455
+ ] }),
456
+ /* @__PURE__ */ jsxRuntime.jsx(
457
+ "button",
458
+ {
459
+ type: "submit",
460
+ disabled: core.unmaskPhone(contact.phone).length < 8,
461
+ className: "mt-5 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
462
+ children: labels.sendCodeCta
463
+ }
464
+ )
465
+ ] }) : null,
466
+ contactStep === "details" ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
467
+ e.preventDefault();
468
+ onSubmitDetails();
469
+ }, children: [
470
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: labels.contactIntro }),
471
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between rounded-xl border border-border bg-muted/40 px-4 py-3", children: [
472
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-sm text-foreground", children: [
473
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-4 w-4 text-primary" }),
474
+ " ",
475
+ labels.phoneVerified,
476
+ " \xB7 ",
477
+ country.flag,
478
+ " ",
479
+ country.dial,
480
+ " ",
481
+ contact.phone
482
+ ] }),
483
+ /* @__PURE__ */ jsxRuntime.jsx(
484
+ "button",
485
+ {
486
+ type: "button",
487
+ onClick: onBackToPhone,
488
+ className: "rounded text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
489
+ children: labels.changePhone
490
+ }
491
+ )
492
+ ] }),
493
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3", children: [
494
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
495
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-name", className: "mb-1 block text-sm font-medium text-foreground", children: labels.nameLabel }),
496
+ /* @__PURE__ */ jsxRuntime.jsx(
497
+ "input",
498
+ {
499
+ id: "bk-name",
500
+ type: "text",
501
+ autoComplete: "name",
502
+ value: contact.name,
503
+ onChange: (e) => onContactChange({ ...contact, name: e.target.value }),
504
+ className: "w-full rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
505
+ placeholder: labels.namePlaceholder
506
+ }
507
+ )
508
+ ] }),
509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
510
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-email", className: "mb-1 block text-sm font-medium text-foreground", children: labels.emailLabel }),
511
+ /* @__PURE__ */ jsxRuntime.jsx(
512
+ "input",
513
+ {
514
+ id: "bk-email",
515
+ type: "email",
516
+ autoComplete: "email",
517
+ inputMode: "email",
518
+ value: contact.email,
519
+ onChange: (e) => onContactChange({ ...contact, email: e.target.value }),
520
+ className: "w-full rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
521
+ placeholder: labels.emailPlaceholder
522
+ }
523
+ ),
524
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: labels.emailHint })
525
+ ] }),
526
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
527
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-notes", className: "mb-1 block text-sm font-medium text-foreground", children: labels.notesLabel }),
528
+ /* @__PURE__ */ jsxRuntime.jsx(
529
+ "textarea",
530
+ {
531
+ id: "bk-notes",
532
+ rows: 3,
533
+ value: contact.notes,
534
+ onChange: (e) => onContactChange({ ...contact, notes: e.target.value }),
535
+ className: "w-full resize-none rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
536
+ placeholder: labels.notesPlaceholder
537
+ }
538
+ )
539
+ ] })
540
+ ] }),
541
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: labels.submitError }) : null,
542
+ /* @__PURE__ */ jsxRuntime.jsxs(
543
+ "button",
544
+ {
545
+ type: "submit",
546
+ disabled: !contact.name.trim() || submitting,
547
+ className: "mt-5 flex w-full items-center justify-center gap-2 rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
548
+ children: [
549
+ submitting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }),
550
+ payment ? labels.saveAndContinueCta : labels.confirmCta
551
+ ]
552
+ }
553
+ ),
554
+ !payment ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 flex items-center justify-center gap-1.5 text-xs text-muted-foreground", children: [
555
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-3.5 w-3.5" }),
556
+ " ",
557
+ labels.noChargeNote
558
+ ] }) : null
559
+ ] }) : null,
560
+ contactStep === "code" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-foreground/40 p-4", role: "dialog", "aria-modal": "true", "aria-label": labels.codeTitle, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-xl", children: [
561
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-heading text-lg font-bold text-foreground", children: labels.codeTitle }),
562
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: labels.codeBody }),
563
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
564
+ e.preventDefault();
565
+ onConfirmCode();
566
+ }, children: [
567
+ /* @__PURE__ */ jsxRuntime.jsx(
568
+ "input",
569
+ {
570
+ type: "text",
571
+ inputMode: "numeric",
572
+ value: code,
573
+ autoFocus: true,
574
+ onChange: (e) => onCodeChange(e.target.value),
575
+ className: "mt-4 w-full rounded-xl border border-border bg-background px-4 py-3 text-center text-lg tracking-[0.4em] text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring placeholder:text-sm placeholder:tracking-normal",
576
+ placeholder: "Digite o c\xF3digo"
577
+ }
578
+ ),
579
+ codeError ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-2 text-sm text-destructive", children: labels.codeInvalid }) : null,
580
+ /* @__PURE__ */ jsxRuntime.jsx(
581
+ "button",
582
+ {
583
+ type: "submit",
584
+ className: "mt-4 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
585
+ children: labels.codeConfirmCta
586
+ }
587
+ )
588
+ ] }),
589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-between text-xs text-muted-foreground", children: [
590
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.codeResendHint }),
591
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onBackToPhone, className: "font-medium text-primary hover:underline", children: labels.back })
592
+ ] })
593
+ ] }) }) : null
594
+ ] });
595
+ }
596
+ var PIX_PAYLOAD = "00020126840014br.gov.bcb.pix2562qrcode.fayz.ai/pix/v2/9d8f7a6b-agendamento5204000053039865802BR5904FAYZ6009SAO PAULO62070503***6304AB12";
135
597
  function QrPlaceholder({ data }) {
136
598
  const size = 25;
137
599
  let seed = 0;
@@ -144,9 +606,9 @@ function QrPlaceholder({ data }) {
144
606
  for (let y = 0; y < size; y++) {
145
607
  for (let x = 0; x < size; x++) {
146
608
  if (isFinder(x, y)) {
147
- const local = (bx, by) => ({ lx: x - bx, ly: y - by });
148
609
  const corner = x < 7 && y < 7 ? { bx: 0, by: 0 } : x >= size - 7 && y < 7 ? { bx: size - 7, by: 0 } : { bx: 0, by: size - 7 };
149
- const { lx, ly } = local(corner.bx, corner.by);
610
+ const lx = x - corner.bx;
611
+ const ly = y - corner.by;
150
612
  const outer = lx === 0 || lx === 6 || ly === 0 || ly === 6;
151
613
  const inner = lx >= 2 && lx <= 4 && ly >= 2 && ly <= 4;
152
614
  if (outer || inner) cells.push({ x, y });
@@ -160,84 +622,197 @@ function QrPlaceholder({ data }) {
160
622
  cells.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx("rect", { x: c.x, y: c.y, width: 1, height: 1, fill: "currentColor", className: "text-foreground" }, i))
161
623
  ] });
162
624
  }
163
- function BrandHeader() {
164
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-5 flex items-center gap-3 rounded-2xl border border-border bg-card px-5 py-4 shadow-sm", children: [
165
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-11 w-11 items-center justify-center rounded-xl bg-primary text-lg font-bold text-primary-foreground", children: "H" }),
166
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
167
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-heading text-base font-bold text-foreground", children: "HempDent \xB7 Consulta Can\xE1bica" }),
168
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
169
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-3.5 w-3.5 text-primary" }),
170
- " Agendamento online seguro \xB7 CRO-SP 166513"
171
- ] })
172
- ] })
173
- ] });
174
- }
175
- function ServiceRow({
625
+ function PaymentStep({
176
626
  service,
177
- featured,
178
- onSelect,
179
- fmt
627
+ payment,
628
+ paymentStep,
629
+ charge,
630
+ busy,
631
+ error,
632
+ copied,
633
+ fmt,
634
+ onPayWithPix,
635
+ onCopy,
636
+ onSimulatePaid
180
637
  }) {
181
- return /* @__PURE__ */ jsxRuntime.jsxs(
182
- "button",
183
- {
184
- type: "button",
185
- onClick: onSelect,
186
- className: "group flex w-full items-center gap-4 rounded-2xl border border-border p-4 text-left transition-colors hover:border-primary hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
187
- children: [
188
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "h-5 w-5" }) }),
189
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
190
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
191
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: service.name }),
192
- featured ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-accent px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-primary", children: "Mais procurado" }) : null
638
+ const feePct = payment.reservationFeePercent;
639
+ const fee = Math.round(service.price * feePct) / 100;
640
+ const remaining = Math.round((service.price - fee) * 100) / 100;
641
+ if (paymentStep === "choose") {
642
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
643
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border p-4", children: [
644
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between font-semibold text-foreground", children: [
645
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: service.name }),
646
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(service.price) })
647
+ ] }),
648
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-2 text-sm", children: [
649
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-foreground", children: [
650
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
651
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) }),
652
+ "Taxa de reserva ",
653
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: [
654
+ feePct,
655
+ "%"
656
+ ] })
657
+ ] }),
658
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(fee) })
193
659
  ] }),
194
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-0.5 flex items-center gap-1 text-xs text-muted-foreground", children: [
195
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3 w-3" }),
196
- " ",
197
- service.durationMinutes,
198
- " min \xB7 Online"
660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-muted-foreground", children: [
661
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
662
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-4 w-4 rounded border border-border" }),
663
+ " Valor restante"
664
+ ] }),
665
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: remaining <= 0 ? "Gr\xE1tis" : fmt.price.format(remaining) })
199
666
  ] }),
200
- service.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 block text-sm text-muted-foreground", children: service.description }) : null
667
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "flex items-center gap-1 text-sm font-medium text-primary hover:underline", children: [
668
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
669
+ " Adicionar cupom"
670
+ ] })
201
671
  ] }),
202
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-right", children: [
203
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block font-semibold tabular-nums text-primary", children: fmt.price.format(service.price) }),
204
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto mt-1 h-4 w-4 text-muted-foreground transition-transform group-hover:translate-x-0.5" })
672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-between border-t border-dashed border-border pt-3 font-semibold text-foreground", children: [
673
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Valor total" }),
674
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(service.price) })
205
675
  ] })
206
- ]
207
- }
208
- );
209
- }
210
- function StepRail({
211
- n,
212
- label,
213
- state,
214
- children
215
- }) {
216
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pl-11", children: [
217
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute left-[15px] top-8 bottom-[-18px] w-px bg-border last:hidden" }),
676
+ ] }),
677
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex items-center justify-between", children: [
678
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-lg font-bold text-foreground", children: "Escolha como pagar" }),
679
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
680
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-3.5 w-3.5 text-primary" }),
681
+ " Pagamento seguro"
682
+ ] })
683
+ ] }),
684
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-2xl border-2 border-primary bg-accent/20 p-4", children: [
685
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 font-semibold text-foreground", children: [
686
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) }),
687
+ "Pix"
688
+ ] }),
689
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3", children: [
690
+ { icon: lucideReact.Check, t: 'Finalize o agendamento clicando em "Pagar com Pix".' },
691
+ { icon: lucideReact.QrCode, t: "Mostraremos um QR Code e o Pix copia-e-cola." },
692
+ { icon: lucideReact.CalendarCheck, t: "Ap\xF3s o pagamento, seu agendamento \xE9 reservado." }
693
+ ].map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
694
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-2 flex h-8 w-8 items-center justify-center rounded-lg bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(s.icon, { className: "h-4 w-4" }) }),
695
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-foreground", children: [
696
+ i + 1,
697
+ "."
698
+ ] }),
699
+ " ",
700
+ s.t
701
+ ] }, i)) })
702
+ ] }),
703
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: "N\xE3o foi poss\xEDvel iniciar o pagamento. Tente novamente." }) : null,
704
+ /* @__PURE__ */ jsxRuntime.jsxs(
705
+ "button",
706
+ {
707
+ type: "button",
708
+ disabled: busy,
709
+ onClick: () => onPayWithPix(fee),
710
+ className: "mt-6 flex w-full items-center justify-center gap-2 rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
711
+ children: [
712
+ busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
713
+ "Pagar ",
714
+ fmt.price.format(fee),
715
+ " com Pix"
716
+ ]
717
+ }
718
+ )
719
+ ] });
720
+ }
721
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
722
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-amber-300/60 bg-amber-50 p-4 dark:border-amber-400/30 dark:bg-amber-950/30", children: [
723
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
724
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
725
+ " Realize o pagamento para finalizar"
726
+ ] }),
727
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Este c\xF3digo Pix \xE9 v\xE1lido por somente 5 minutos. N\xE3o feche esta p\xE1gina at\xE9 receber a confirma\xE7\xE3o do pagamento." })
728
+ ] }),
729
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mt-6 font-heading text-lg font-bold text-foreground", children: "Escaneie ou copie este c\xF3digo para pagar" }),
730
+ /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "mt-2 space-y-1 text-sm text-muted-foreground", children: [
731
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "1. Acesse o app do seu banco, pagamentos ou Internet Banking." }),
732
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "2. Escolha pagar via Pix." }),
733
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "3. Escaneie o QR Code ou use o Pix copia-e-cola:" })
734
+ ] }),
735
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 w-fit rounded-xl border border-border bg-white p-3", children: /* @__PURE__ */ jsxRuntime.jsx(QrPlaceholder, { data: charge?.pixQrCode ?? PIX_PAYLOAD }) }),
736
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex max-w-md items-center gap-2", children: [
737
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "flex-1 truncate rounded-lg border border-border bg-muted px-3 py-2 text-xs text-muted-foreground", children: charge?.pixCopyPaste ?? PIX_PAYLOAD }),
738
+ /* @__PURE__ */ jsxRuntime.jsxs(
739
+ "button",
740
+ {
741
+ type: "button",
742
+ onClick: onCopy,
743
+ className: "inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-foreground px-3 py-2 text-xs font-medium text-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
744
+ children: [
745
+ copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }),
746
+ " ",
747
+ copied ? "Copiado" : "Copiar"
748
+ ]
749
+ }
750
+ )
751
+ ] }),
218
752
  /* @__PURE__ */ jsxRuntime.jsx(
219
- "span",
753
+ "button",
220
754
  {
221
- className: [
222
- "absolute left-0 top-0 flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold transition-colors",
223
- state === "done" ? "bg-primary text-primary-foreground" : state === "active" ? "bg-accent text-primary ring-2 ring-primary" : "bg-muted text-muted-foreground"
224
- ].join(" "),
225
- children: state === "done" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) : n
755
+ type: "button",
756
+ onClick: onSimulatePaid,
757
+ className: "mt-6 w-full rounded-xl border border-primary py-3 font-semibold text-primary transition-colors hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
758
+ children: "J\xE1 paguei \u2014 confirmar (simula\xE7\xE3o)"
226
759
  }
227
- ),
228
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: `pt-1 text-sm font-semibold ${state === "todo" ? "text-muted-foreground" : "text-foreground"}`, children: label }),
229
- children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children }) : null
760
+ )
761
+ ] });
762
+ }
763
+ function SummaryRail({
764
+ title,
765
+ railState,
766
+ service,
767
+ professionalName,
768
+ slotStart,
769
+ contactSummary,
770
+ payment,
771
+ paymentReached,
772
+ labels,
773
+ fmt,
774
+ components: C,
775
+ serviceMeta
776
+ }) {
777
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-24 rounded-2xl border border-border bg-card p-5 shadow-sm", children: [
778
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-5 font-heading text-sm font-bold uppercase tracking-wide text-muted-foreground", children: title }),
779
+ /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "space-y-6", children: [
780
+ /* @__PURE__ */ jsxRuntime.jsx(C.StepRailItem, { n: 1, label: labels.railService, state: railState.service, children: service ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border bg-background p-3", children: [
781
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: service.name }),
782
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 flex items-center justify-between text-xs text-muted-foreground", children: [
783
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
784
+ serviceMeta ? `${serviceMeta} \xB7 ` : "",
785
+ service.durationMinutes,
786
+ " min"
787
+ ] }),
788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold tabular-nums text-primary", children: fmt.price.format(service.price) })
789
+ ] })
790
+ ] }) : null }),
791
+ /* @__PURE__ */ jsxRuntime.jsx(C.StepRailItem, { n: 2, label: labels.railProfessional, state: railState.professional, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: professionalName.charAt(0) }),
793
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground", children: professionalName })
794
+ ] }) }),
795
+ /* @__PURE__ */ jsxRuntime.jsx(C.StepRailItem, { n: 3, label: labels.railDatetime, state: railState.datetime, children: slotStart && service ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm tabular-nums text-foreground", children: formatSlotRange(slotStart, service.durationMinutes, fmt) }) : null }),
796
+ /* @__PURE__ */ jsxRuntime.jsx(C.StepRailItem, { n: 4, label: labels.railContact, state: railState.contact, children: contactSummary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground", children: contactSummary }) : null }),
797
+ payment ? /* @__PURE__ */ jsxRuntime.jsx(C.StepRailItem, { n: 5, label: labels.railPayment, state: railState.payment, children: paymentReached ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-sm text-foreground", children: [
798
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-3.5 w-3.5 text-primary" }),
799
+ " Pix \xE0 vista"
800
+ ] }) : null }) : null
801
+ ] })
230
802
  ] });
231
803
  }
232
804
  function BookingWidget() {
233
805
  const {
234
806
  services,
807
+ servicesLoading,
235
808
  professionalName,
236
809
  businessHours,
237
810
  payment,
238
811
  paymentProvider,
239
812
  onIdentityVerified,
240
813
  labels,
814
+ brand,
815
+ components: C,
241
816
  window: bookingWindow,
242
817
  locale,
243
818
  currency
@@ -265,6 +840,12 @@ function BookingWidget() {
265
840
  const [charge, setCharge] = react.useState(null);
266
841
  const [charging, setCharging] = react.useState(false);
267
842
  const pollRef = react.useRef(null);
843
+ react.useEffect(() => {
844
+ if (preselected && step === "overview") {
845
+ setServiceId(preselected);
846
+ setStep("datetime");
847
+ }
848
+ }, [preselected]);
268
849
  react.useEffect(() => {
269
850
  if (!(step === "payment" && paymentStep === "pix" && charge && paymentProvider)) return;
270
851
  let active = true;
@@ -298,7 +879,9 @@ function BookingWidget() {
298
879
  const bookableSlots = slots.filter((s) => new Date(s.start).getTime() >= minTime);
299
880
  const service = services.find((s) => s.id === serviceId) ?? null;
300
881
  const maxWeekOffset = Math.floor(bookingWindow.maxAdvanceDays / 7);
301
- const openDays = new Set(businessHours.daysOfWeek);
882
+ function contactForSubmit() {
883
+ return { ...contact, phone: `${country.dial} ${contact.phone}` };
884
+ }
302
885
  function startBooking(id) {
303
886
  setServiceId(id ?? serviceId ?? services[0]?.id ?? null);
304
887
  setDate(todayIso);
@@ -308,7 +891,7 @@ function BookingWidget() {
308
891
  async function handleConfirm() {
309
892
  if (!serviceId || !slotStart || !contact.name.trim()) return;
310
893
  try {
311
- await submit({ serviceId, startsAt: slotStart, contact });
894
+ await submit({ serviceId, startsAt: slotStart, contact: contactForSubmit() });
312
895
  setStep("success");
313
896
  } catch {
314
897
  }
@@ -343,17 +926,17 @@ function BookingWidget() {
343
926
  setStep("payment");
344
927
  } else void handleConfirm();
345
928
  }
346
- async function payWithPix(fee, svcId, svcName) {
347
- if (charging) return;
929
+ async function payWithPix(fee) {
930
+ if (charging || !service || !slotStart) return;
348
931
  setCharging(true);
349
932
  try {
350
- await submit({ serviceId: svcId, startsAt: slotStart, contact });
933
+ await submit({ serviceId: service.id, startsAt: slotStart, contact: contactForSubmit() });
351
934
  if (paymentProvider) {
352
935
  const c = await paymentProvider.createCharge({
353
936
  amount: fee,
354
937
  currency,
355
938
  method: "pix",
356
- description: svcName,
939
+ description: service.name,
357
940
  customer: { name: contact.name, email: contact.email || void 0, phone: contact.phone || void 0 }
358
941
  });
359
942
  setCharge(c);
@@ -364,61 +947,32 @@ function BookingWidget() {
364
947
  setCharging(false);
365
948
  }
366
949
  }
950
+ function copyPixPayload() {
951
+ const payload = charge?.pixCopyPaste ?? PIX_PAYLOAD;
952
+ try {
953
+ void navigator.clipboard?.writeText(payload);
954
+ setCopied(true);
955
+ } catch {
956
+ setCopied(true);
957
+ }
958
+ }
367
959
  if (step === "overview") {
368
960
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto max-w-4xl", children: [
369
- /* @__PURE__ */ jsxRuntime.jsx(BrandHeader, {}),
370
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_18rem]", children: [
371
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
372
- /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "rounded-2xl border border-border bg-card p-6 shadow-sm", children: [
373
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-4 font-heading text-lg font-bold text-foreground", children: "Servi\xE7os" }),
374
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: services.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(ServiceRow, { service: s, featured: i === 0, onSelect: () => startBooking(s.id), fmt }, s.id)) })
375
- ] }),
376
- /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "rounded-2xl border border-border bg-card p-6 shadow-sm", children: [
377
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-lg font-bold text-foreground", children: "Sobre" }),
378
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 mb-2 flex items-center gap-1.5 text-sm font-medium text-muted-foreground", children: [
379
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" }),
380
- " Hor\xE1rio de funcionamento"
381
- ] }),
382
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "divide-y divide-border border-l-2 border-primary/20 pl-4", children: WEEK_ORDER.map((day) => {
383
- const open = openDays.has(day);
384
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between py-2 text-sm", children: [
385
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: DAY_NAMES[day] }),
386
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: open ? "tabular-nums text-foreground" : "text-muted-foreground", children: open ? `${businessHours.start} \u2013 ${businessHours.end}` : "Fechado" })
387
- ] }, day);
388
- }) })
389
- ] })
390
- ] }),
391
- /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "lg:sticky lg:top-24 lg:self-start", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border bg-card p-5 shadow-sm", children: [
392
- /* @__PURE__ */ jsxRuntime.jsx(
393
- "button",
394
- {
395
- type: "button",
396
- onClick: () => startBooking(),
397
- className: "w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
398
- children: "Agendar agora"
399
- }
400
- ),
401
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 space-y-2 border-t border-border pt-4 text-xs text-muted-foreground", children: [
402
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
403
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { className: "h-3.5 w-3.5 text-primary" }),
404
- " Consulta 100% online"
405
- ] }),
406
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
407
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-3.5 w-3.5 text-primary" }),
408
- " Atende todo o Brasil"
409
- ] }),
410
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
411
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-3.5 w-3.5 text-primary" }),
412
- " Aceitamos Pix"
413
- ] }),
414
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
415
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-3.5 w-3.5 text-primary" }),
416
- " ",
417
- professionalName
418
- ] })
419
- ] })
420
- ] }) })
421
- ] })
961
+ /* @__PURE__ */ jsxRuntime.jsx(C.BrandHeader, { brand }),
962
+ /* @__PURE__ */ jsxRuntime.jsx(
963
+ OverviewStep,
964
+ {
965
+ services,
966
+ servicesLoading,
967
+ businessHours,
968
+ professionalName,
969
+ labels,
970
+ brand,
971
+ fmt,
972
+ components: C,
973
+ onStartBooking: startBooking
974
+ }
975
+ )
422
976
  ] });
423
977
  }
424
978
  const railState = {
@@ -428,9 +982,10 @@ function BookingWidget() {
428
982
  contact: step === "payment" || step === "success" ? "done" : step === "contact" ? "active" : "todo",
429
983
  payment: step === "success" ? "done" : step === "payment" ? "active" : "todo"
430
984
  };
431
- const railTitle = step === "payment" && paymentStep === "pix" ? "Aguardando pagamento" : "Passos para agendar";
985
+ const railTitle = step === "payment" && paymentStep === "pix" ? labels.railWaitingPayment : labels.railTitle;
986
+ const contactSummary = (contact.name || contact.phone) && (step === "payment" || step === "success" || contactStep === "details") ? `${contact.name || "Contato"}${contact.phone ? ` \xB7 ${country.dial} ${contact.phone}` : ""}` : null;
432
987
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto max-w-4xl", children: [
433
- /* @__PURE__ */ jsxRuntime.jsx(BrandHeader, {}),
988
+ /* @__PURE__ */ jsxRuntime.jsx(C.BrandHeader, { brand }),
434
989
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_18rem]", children: [
435
990
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border bg-card p-6 md:p-7 shadow-sm", children: [
436
991
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-5 flex items-center gap-1.5 lg:hidden", children: ["datetime", "contact"].map((s) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: `h-1.5 flex-1 rounded-full ${railState[s] !== "todo" ? "bg-primary" : "bg-muted"}` }, s)) }),
@@ -443,470 +998,226 @@ function BookingWidget() {
443
998
  children: [
444
999
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" }),
445
1000
  " ",
446
- step === "datetime" ? "Servi\xE7os" : "Voltar"
1001
+ step === "datetime" ? labels.backToServices : labels.back
447
1002
  ]
448
1003
  }
449
1004
  ) : null,
450
- step === "datetime" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
451
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [
452
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-xl font-bold text-foreground", children: labels.dateStep }),
453
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
454
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3.5 w-3.5" }),
455
- " Fuso: Hor\xE1rio de Bras\xEDlia"
456
- ] })
457
- ] }),
458
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 flex items-center justify-between", children: [
459
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold capitalize text-foreground", children: fmt.month.format(week[0].date) }),
460
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
461
- /* @__PURE__ */ jsxRuntime.jsx(
462
- "button",
463
- {
464
- type: "button",
465
- disabled: weekOffset === 0,
466
- onClick: () => setWeekOffset((w) => Math.max(0, w - 1)),
467
- className: "flex h-9 w-9 items-center justify-center rounded-lg border border-border text-foreground transition-colors hover:bg-accent disabled:opacity-40 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
468
- "aria-label": "Semana anterior",
469
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
470
- }
471
- ),
472
- /* @__PURE__ */ jsxRuntime.jsx(
473
- "button",
474
- {
475
- type: "button",
476
- disabled: weekOffset >= maxWeekOffset,
477
- onClick: () => setWeekOffset((w) => Math.min(maxWeekOffset, w + 1)),
478
- className: "flex h-9 w-9 items-center justify-center rounded-lg border border-border text-foreground transition-colors hover:bg-accent disabled:opacity-40 disabled:hover:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
479
- "aria-label": "Pr\xF3xima semana",
480
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
481
- }
482
- )
483
- ] })
1005
+ step === "datetime" ? /* @__PURE__ */ jsxRuntime.jsx(
1006
+ DateTimeStep,
1007
+ {
1008
+ labels,
1009
+ fmt,
1010
+ week,
1011
+ weekOffset,
1012
+ maxWeekOffset,
1013
+ onWeekOffset: setWeekOffset,
1014
+ businessHours,
1015
+ date,
1016
+ onSelectDate: (iso) => {
1017
+ setDate(iso);
1018
+ setSlotStart(null);
1019
+ },
1020
+ slots: bookableSlots,
1021
+ slotsLoading,
1022
+ slotStart,
1023
+ onSelectSlot: setSlotStart,
1024
+ onContinue: () => setStep("contact")
1025
+ }
1026
+ ) : null,
1027
+ step === "contact" ? /* @__PURE__ */ jsxRuntime.jsx(
1028
+ ContactStep,
1029
+ {
1030
+ labels,
1031
+ contact,
1032
+ onContactChange: setContact,
1033
+ contactStep,
1034
+ country,
1035
+ onCountryChange: (iso2) => {
1036
+ const c = core.getCountry(iso2);
1037
+ setCountryIso(c.iso2);
1038
+ setContact((prev) => ({ ...prev, phone: core.maskPhone(core.unmaskPhone(prev.phone), c.mask) }));
1039
+ },
1040
+ code,
1041
+ onCodeChange: (v) => {
1042
+ setCode(v);
1043
+ setCodeError(false);
1044
+ },
1045
+ codeError,
1046
+ onSendCode: sendCode,
1047
+ onConfirmCode: confirmCode,
1048
+ onBackToPhone: () => setContactStep("phone"),
1049
+ onSubmitDetails: submitDetails,
1050
+ payment,
1051
+ submitting,
1052
+ error
1053
+ }
1054
+ ) : null,
1055
+ step === "payment" && service && payment ? /* @__PURE__ */ jsxRuntime.jsx(
1056
+ PaymentStep,
1057
+ {
1058
+ service,
1059
+ payment,
1060
+ paymentStep,
1061
+ charge,
1062
+ busy: submitting || charging,
1063
+ error,
1064
+ copied,
1065
+ fmt,
1066
+ onPayWithPix: (fee) => void payWithPix(fee),
1067
+ onCopy: copyPixPayload,
1068
+ onSimulatePaid: () => setStep("success")
1069
+ }
1070
+ ) : null,
1071
+ step === "success" ? /* @__PURE__ */ jsxRuntime.jsx(
1072
+ C.SuccessPanel,
1073
+ {
1074
+ service,
1075
+ slotStart,
1076
+ professionalName,
1077
+ labels,
1078
+ fmt
1079
+ }
1080
+ ) : null
1081
+ ] }),
1082
+ /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "hidden lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(
1083
+ SummaryRail,
1084
+ {
1085
+ title: railTitle,
1086
+ railState,
1087
+ service,
1088
+ professionalName,
1089
+ slotStart,
1090
+ contactSummary,
1091
+ payment,
1092
+ paymentReached: step === "payment" || step === "success",
1093
+ labels,
1094
+ fmt,
1095
+ components: C,
1096
+ serviceMeta: brand.serviceMeta
1097
+ }
1098
+ ) })
1099
+ ] })
1100
+ ] });
1101
+ }
1102
+ function DefaultBrandHeader({ brand }) {
1103
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-5 flex items-center gap-3 rounded-2xl border border-border bg-card px-5 py-4 shadow-sm", children: [
1104
+ brand.logoUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: brand.logoUrl, alt: brand.name, className: "h-11 w-11 rounded-xl object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-11 w-11 items-center justify-center rounded-xl bg-primary text-lg font-bold text-primary-foreground", children: brand.initials }),
1105
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1106
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-heading text-base font-bold text-foreground", children: brand.name }),
1107
+ brand.tagline ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1108
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-3.5 w-3.5 text-primary" }),
1109
+ " ",
1110
+ brand.tagline
1111
+ ] }) : null
1112
+ ] })
1113
+ ] });
1114
+ }
1115
+ function DefaultServiceCard({ service, featured, onSelect, fmt, brand }) {
1116
+ const Icon = brand.serviceIcon;
1117
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1118
+ "button",
1119
+ {
1120
+ type: "button",
1121
+ onClick: onSelect,
1122
+ className: "group flex w-full items-center gap-4 rounded-2xl border border-border p-4 text-left transition-colors hover:border-primary hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1123
+ children: [
1124
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-5 w-5" }) }),
1125
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
1127
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: service.name }),
1128
+ featured && brand.featuredBadge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-accent px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-primary", children: brand.featuredBadge }) : null
484
1129
  ] }),
485
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 grid grid-cols-7 gap-1.5", children: week.map((d) => {
486
- const selected = date === d.iso;
487
- const closed = !openDays.has(d.date.getDay());
488
- return /* @__PURE__ */ jsxRuntime.jsxs(
489
- "button",
490
- {
491
- type: "button",
492
- disabled: closed,
493
- onClick: () => {
494
- setDate(d.iso);
495
- setSlotStart(null);
496
- },
497
- className: [
498
- "flex flex-col items-center gap-0.5 rounded-xl border py-2.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
499
- closed ? "cursor-not-allowed border-transparent text-muted-foreground/40" : selected ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary/60 hover:bg-accent/40"
500
- ].join(" "),
501
- children: [
502
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium capitalize opacity-80", children: fmt.weekday.format(d.date).replace(".", "") }),
503
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold tabular-nums", children: fmt.dayNum.format(d.date) })
504
- ]
505
- },
506
- d.iso
507
- );
508
- }) }),
509
- date ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6", children: [
510
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-sm font-semibold text-foreground", children: "Hor\xE1rios dispon\xEDveis" }),
511
- slotsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2 sm:grid-cols-4", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 animate-pulse rounded-lg bg-muted" }, i)) }) : bookableSlots.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-dashed border-border p-6 text-center text-sm text-muted-foreground", children: "Nenhum hor\xE1rio dispon\xEDvel neste dia. Tente outra data." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2 sm:grid-cols-4", children: bookableSlots.map((s) => {
512
- const selected = slotStart === s.start;
513
- return /* @__PURE__ */ jsxRuntime.jsx(
514
- "button",
515
- {
516
- type: "button",
517
- onClick: () => setSlotStart(s.start),
518
- className: [
519
- "rounded-lg border py-2.5 text-sm font-semibold tabular-nums transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
520
- selected ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary/60 hover:bg-accent/40"
521
- ].join(" "),
522
- children: fmt.time.format(new Date(s.start))
523
- },
524
- s.start
525
- );
526
- }) })
527
- ] }) : null,
528
- /* @__PURE__ */ jsxRuntime.jsx(
529
- "button",
530
- {
531
- type: "button",
532
- disabled: !slotStart,
533
- onClick: () => setStep("contact"),
534
- className: "mt-6 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
535
- children: "Continuar"
536
- }
537
- )
538
- ] }) : null,
539
- step === "contact" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
540
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-xl font-bold text-foreground", children: labels.contactStep }),
541
- contactStep === "phone" ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
542
- e.preventDefault();
543
- sendCode();
544
- }, children: [
545
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Preencha as informa\xE7\xF5es abaixo para que seu agendamento seja identificado." }),
546
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5", children: [
547
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-phone", className: "mb-1 block text-sm font-medium text-foreground", children: "Celular" }),
548
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
549
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
550
- /* @__PURE__ */ jsxRuntime.jsx(
551
- "select",
552
- {
553
- "aria-label": "Pa\xEDs",
554
- value: countryIso,
555
- onChange: (e) => {
556
- const c = core.getCountry(e.target.value);
557
- setCountryIso(c.iso2);
558
- setContact({ ...contact, phone: core.maskPhone(core.unmaskPhone(contact.phone), c.mask) });
559
- },
560
- className: "h-full appearance-none rounded-l-xl border border-r-0 border-border bg-muted py-3 pl-3 pr-8 text-sm font-medium text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring",
561
- children: core.COUNTRIES.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.iso2, children: [
562
- c.flag,
563
- " ",
564
- c.dial
565
- ] }, c.iso2))
566
- }
567
- ),
568
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" })
569
- ] }),
570
- /* @__PURE__ */ jsxRuntime.jsx(
571
- "input",
572
- {
573
- id: "bk-phone",
574
- type: "tel",
575
- autoComplete: "tel",
576
- inputMode: "tel",
577
- value: contact.phone,
578
- onChange: (e) => setContact({ ...contact, phone: core.maskPhone(e.target.value, country.mask) }),
579
- className: "w-full rounded-r-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
580
- placeholder: `Ex.: ${core.maskPhone("11987654321", country.mask)}`
581
- }
582
- )
583
- ] }),
584
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Enviaremos um c\xF3digo para confirmar que o n\xFAmero de telefone \xE9 seu. Usaremos este n\xFAmero para associar as suas informa\xE7\xF5es \xE0 sua conta." })
585
- ] }),
586
- /* @__PURE__ */ jsxRuntime.jsx(
587
- "button",
588
- {
589
- type: "submit",
590
- disabled: core.unmaskPhone(contact.phone).length < 8,
591
- className: "mt-5 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
592
- children: "Enviar c\xF3digo via WhatsApp"
593
- }
594
- )
595
- ] }) : null,
596
- contactStep === "details" ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
597
- e.preventDefault();
598
- submitDetails();
599
- }, children: [
600
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Preencha as informa\xE7\xF5es abaixo para que seu agendamento seja identificado." }),
601
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between rounded-xl border border-border bg-muted/40 px-4 py-3", children: [
602
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-sm text-foreground", children: [
603
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-4 w-4 text-primary" }),
604
- " Celular verificado \xB7 ",
605
- country.flag,
606
- " ",
607
- country.dial,
608
- " ",
609
- contact.phone
610
- ] }),
611
- /* @__PURE__ */ jsxRuntime.jsx(
612
- "button",
613
- {
614
- type: "button",
615
- onClick: () => setContactStep("phone"),
616
- className: "rounded text-sm font-medium text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
617
- children: "Trocar telefone"
618
- }
619
- )
620
- ] }),
621
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3", children: [
622
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
623
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-name", className: "mb-1 block text-sm font-medium text-foreground", children: "Nome completo *" }),
624
- /* @__PURE__ */ jsxRuntime.jsx(
625
- "input",
626
- {
627
- id: "bk-name",
628
- type: "text",
629
- autoComplete: "name",
630
- value: contact.name,
631
- onChange: (e) => setContact({ ...contact, name: e.target.value }),
632
- className: "w-full rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
633
- placeholder: "Seu nome"
634
- }
635
- )
636
- ] }),
637
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
638
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-email", className: "mb-1 block text-sm font-medium text-foreground", children: "E-mail" }),
639
- /* @__PURE__ */ jsxRuntime.jsx(
640
- "input",
641
- {
642
- id: "bk-email",
643
- type: "email",
644
- autoComplete: "email",
645
- inputMode: "email",
646
- value: contact.email,
647
- onChange: (e) => setContact({ ...contact, email: e.target.value }),
648
- className: "w-full rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
649
- placeholder: "voce@email.com"
650
- }
651
- ),
652
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Enviaremos uma confirma\xE7\xE3o e um lembrete antes do agendamento." })
653
- ] }),
654
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
655
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "bk-notes", className: "mb-1 block text-sm font-medium text-foreground", children: "Observa\xE7\xE3o" }),
656
- /* @__PURE__ */ jsxRuntime.jsx(
657
- "textarea",
658
- {
659
- id: "bk-notes",
660
- rows: 3,
661
- value: contact.notes,
662
- onChange: (e) => setContact({ ...contact, notes: e.target.value }),
663
- className: "w-full resize-none rounded-xl border border-border bg-background px-4 py-3 text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring",
664
- placeholder: "Use esse espa\xE7o para deixar uma observa\xE7\xE3o sobre este agendamento"
665
- }
666
- )
667
- ] })
668
- ] }),
669
- error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: "N\xE3o foi poss\xEDvel concluir o agendamento. Tente novamente." }) : null,
670
- /* @__PURE__ */ jsxRuntime.jsxs(
671
- "button",
672
- {
673
- type: "submit",
674
- disabled: !contact.name.trim() || submitting,
675
- className: "mt-5 flex w-full items-center justify-center gap-2 rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
676
- children: [
677
- submitting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }),
678
- payment ? "Salvar e continuar" : labels.confirmCta
679
- ]
680
- }
681
- ),
682
- !payment ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 flex items-center justify-center gap-1.5 text-xs text-muted-foreground", children: [
683
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-3.5 w-3.5" }),
684
- " Pagamento via Pix \xB7 Sem cobran\xE7a agora"
685
- ] }) : null
686
- ] }) : null
687
- ] }) : null,
688
- step === "contact" && contactStep === "code" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-foreground/40 p-4", role: "dialog", "aria-modal": "true", "aria-label": "Verifica\xE7\xE3o de c\xF3digo", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-xl", children: [
689
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-heading text-lg font-bold text-foreground", children: "Insira o c\xF3digo" }),
690
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Enviamos um c\xF3digo via WhatsApp para voc\xEA confirmar seu n\xFAmero." }),
691
- /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => {
692
- e.preventDefault();
693
- confirmCode();
694
- }, children: [
695
- /* @__PURE__ */ jsxRuntime.jsx(
696
- "input",
697
- {
698
- type: "text",
699
- inputMode: "numeric",
700
- value: code,
701
- autoFocus: true,
702
- onChange: (e) => {
703
- setCode(e.target.value);
704
- setCodeError(false);
705
- },
706
- className: "mt-4 w-full rounded-xl border border-border bg-background px-4 py-3 text-center text-lg tracking-[0.4em] text-foreground outline-none transition-colors focus:border-primary focus-visible:ring-2 focus-visible:ring-ring placeholder:text-sm placeholder:tracking-normal",
707
- placeholder: "Digite o c\xF3digo"
708
- }
709
- ),
710
- codeError ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-2 text-sm text-destructive", children: "C\xF3digo inv\xE1lido. Para testar, use 0000." }) : null,
711
- /* @__PURE__ */ jsxRuntime.jsx(
712
- "button",
713
- {
714
- type: "submit",
715
- className: "mt-4 w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
716
- children: "Confirmar"
717
- }
718
- )
1130
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mt-0.5 flex items-center gap-1 text-xs text-muted-foreground", children: [
1131
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3 w-3" }),
1132
+ " ",
1133
+ service.durationMinutes,
1134
+ " min",
1135
+ brand.serviceMeta ? ` \xB7 ${brand.serviceMeta}` : ""
719
1136
  ] }),
720
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-between text-xs text-muted-foreground", children: [
721
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reenviar c\xF3digo via WhatsApp em 28 segundos." }),
722
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setContactStep("phone"), className: "font-medium text-primary hover:underline", children: "Voltar" })
723
- ] })
724
- ] }) }) : null,
725
- step === "payment" && service ? (() => {
726
- const feePct = payment?.reservationFeePercent ?? 100;
727
- const fee = Math.round(service.price * feePct) / 100;
728
- const remaining = Math.round((service.price - fee) * 100) / 100;
729
- return /* @__PURE__ */ jsxRuntime.jsx("div", { children: paymentStep === "choose" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
730
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border p-4", children: [
731
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between font-semibold text-foreground", children: [
732
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: service.name }),
733
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(service.price) })
734
- ] }),
735
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-2 text-sm", children: [
736
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-foreground", children: [
737
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
738
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) }),
739
- "Taxa de reserva ",
740
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: [
741
- feePct,
742
- "%"
743
- ] })
744
- ] }),
745
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(fee) })
746
- ] }),
747
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-muted-foreground", children: [
748
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
749
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-4 w-4 rounded border border-border" }),
750
- " Valor restante"
751
- ] }),
752
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: remaining <= 0 ? "Gr\xE1tis" : fmt.price.format(remaining) })
753
- ] }),
754
- /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "flex items-center gap-1 text-sm font-medium text-primary hover:underline", children: [
755
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
756
- " Adicionar cupom"
757
- ] })
758
- ] }),
759
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-between border-t border-dashed border-border pt-3 font-semibold text-foreground", children: [
760
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Valor total" }),
761
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: fmt.price.format(service.price) })
762
- ] })
763
- ] }),
764
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex items-center justify-between", children: [
765
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-lg font-bold text-foreground", children: "Escolha como pagar" }),
766
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
767
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "h-3.5 w-3.5 text-primary" }),
768
- " Pagamento seguro"
769
- ] })
770
- ] }),
771
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-2xl border-2 border-primary bg-accent/20 p-4", children: [
772
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 font-semibold text-foreground", children: [
773
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) }),
774
- "Pix"
775
- ] }),
776
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3", children: [
777
- { icon: lucideReact.Check, t: 'Finalize o agendamento clicando em "Pagar com Pix".' },
778
- { icon: lucideReact.QrCode, t: "Mostraremos um QR Code e o Pix copia-e-cola." },
779
- { icon: lucideReact.CalendarCheck, t: "Ap\xF3s o pagamento, seu agendamento \xE9 reservado." }
780
- ].map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
781
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-2 flex h-8 w-8 items-center justify-center rounded-lg bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(s.icon, { className: "h-4 w-4" }) }),
782
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-foreground", children: [
783
- i + 1,
784
- "."
785
- ] }),
786
- " ",
787
- s.t
788
- ] }, i)) })
789
- ] }),
790
- error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: "N\xE3o foi poss\xEDvel iniciar o pagamento. Tente novamente." }) : null,
791
- /* @__PURE__ */ jsxRuntime.jsxs(
792
- "button",
793
- {
794
- type: "button",
795
- disabled: submitting || charging,
796
- onClick: () => void payWithPix(fee, service.id, service.name),
797
- className: "mt-6 flex w-full items-center justify-center gap-2 rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
798
- children: [
799
- submitting || charging ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
800
- "Pagar ",
801
- fmt.price.format(fee),
802
- " com Pix"
803
- ]
804
- }
805
- )
806
- ] }) : (
807
- /* Pix QR — aguardando pagamento */
808
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
809
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-amber-300/60 bg-amber-50 p-4 dark:border-amber-400/30 dark:bg-amber-950/30", children: [
810
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
811
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
812
- " Realize o pagamento para finalizar"
813
- ] }),
814
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Este c\xF3digo Pix \xE9 v\xE1lido por somente 5 minutos. N\xE3o feche esta p\xE1gina at\xE9 receber a confirma\xE7\xE3o do pagamento." })
815
- ] }),
816
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mt-6 font-heading text-lg font-bold text-foreground", children: "Escaneie ou copie este c\xF3digo para pagar" }),
817
- /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "mt-2 space-y-1 text-sm text-muted-foreground", children: [
818
- /* @__PURE__ */ jsxRuntime.jsx("li", { children: "1. Acesse o app do seu banco, pagamentos ou Internet Banking." }),
819
- /* @__PURE__ */ jsxRuntime.jsx("li", { children: "2. Escolha pagar via Pix." }),
820
- /* @__PURE__ */ jsxRuntime.jsx("li", { children: "3. Escaneie o QR Code ou use o Pix copia-e-cola:" })
821
- ] }),
822
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 w-fit rounded-xl border border-border bg-white p-3", children: /* @__PURE__ */ jsxRuntime.jsx(QrPlaceholder, { data: charge?.pixQrCode ?? PIX_PAYLOAD }) }),
823
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex max-w-md items-center gap-2", children: [
824
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "flex-1 truncate rounded-lg border border-border bg-muted px-3 py-2 text-xs text-muted-foreground", children: charge?.pixCopyPaste ?? PIX_PAYLOAD }),
825
- /* @__PURE__ */ jsxRuntime.jsxs(
826
- "button",
827
- {
828
- type: "button",
829
- onClick: () => {
830
- const payload = charge?.pixCopyPaste ?? PIX_PAYLOAD;
831
- try {
832
- void navigator.clipboard?.writeText(payload);
833
- setCopied(true);
834
- } catch {
835
- setCopied(true);
836
- }
837
- },
838
- className: "inline-flex shrink-0 items-center gap-1.5 rounded-lg bg-foreground px-3 py-2 text-xs font-medium text-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
839
- children: [
840
- copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }),
841
- " ",
842
- copied ? "Copiado" : "Copiar"
843
- ]
844
- }
845
- )
846
- ] }),
847
- /* @__PURE__ */ jsxRuntime.jsx(
848
- "button",
849
- {
850
- type: "button",
851
- onClick: () => setStep("success"),
852
- className: "mt-6 w-full rounded-xl border border-primary py-3 font-semibold text-primary transition-colors hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
853
- children: "J\xE1 paguei \u2014 confirmar (simula\xE7\xE3o)"
854
- }
855
- )
856
- ] })
857
- ) });
858
- })() : null,
859
- step === "success" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-8 text-center", children: [
860
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-8 w-8" }) }),
861
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-2xl font-bold text-foreground", children: labels.successTitle }),
862
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mx-auto mt-2 max-w-sm text-muted-foreground", children: labels.successBody }),
863
- service && slotStart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto mt-6 max-w-sm rounded-2xl border border-border bg-muted/50 p-4 text-left", children: [
864
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-foreground", children: service.name }),
865
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 flex items-center gap-1.5 text-sm tabular-nums text-muted-foreground", children: [
866
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4 text-primary" }),
867
- " ",
868
- formatSlotRange(slotStart, service.durationMinutes, fmt)
869
- ] }),
870
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 flex items-center gap-1.5 text-sm text-muted-foreground", children: [
871
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4 text-primary" }),
872
- " ",
873
- professionalName
874
- ] })
875
- ] }) : null
876
- ] }) : null
877
- ] }),
878
- /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "hidden lg:block", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-24 rounded-2xl border border-border bg-card p-5 shadow-sm", children: [
879
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-5 font-heading text-sm font-bold uppercase tracking-wide text-muted-foreground", children: railTitle }),
880
- /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "space-y-6", children: [
881
- /* @__PURE__ */ jsxRuntime.jsx(StepRail, { n: 1, label: "Servi\xE7o", state: railState.service, children: service ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border bg-background p-3", children: [
882
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: service.name }),
883
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 flex items-center justify-between text-xs text-muted-foreground", children: [
884
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
885
- "Online \xB7 ",
886
- service.durationMinutes,
887
- " min"
888
- ] }),
889
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold tabular-nums text-primary", children: fmt.price.format(service.price) })
890
- ] })
891
- ] }) : null }),
892
- /* @__PURE__ */ jsxRuntime.jsx(StepRail, { n: 2, label: "Profissional", state: railState.professional, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
893
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: professionalName.charAt(0) }),
894
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground", children: professionalName })
895
- ] }) }),
896
- /* @__PURE__ */ jsxRuntime.jsx(StepRail, { n: 3, label: "Data e hor\xE1rio", state: railState.datetime, children: slotStart && service ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm tabular-nums text-foreground", children: formatSlotRange(slotStart, service.durationMinutes, fmt) }) : null }),
897
- /* @__PURE__ */ jsxRuntime.jsx(StepRail, { n: 4, label: "Informa\xE7\xF5es pessoais", state: railState.contact, children: (contact.name || contact.phone) && (step === "payment" || step === "success" || contactStep === "details") ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-foreground", children: [
898
- contact.name || "Contato",
899
- contact.phone ? ` \xB7 ${country.dial} ${contact.phone}` : ""
900
- ] }) : null }),
901
- payment ? /* @__PURE__ */ jsxRuntime.jsx(StepRail, { n: 5, label: "Pagamento", state: railState.payment, children: step === "payment" || step === "success" ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-sm text-foreground", children: [
902
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-3.5 w-3.5 text-primary" }),
903
- " Pix \xE0 vista"
904
- ] }) : null }) : null
1137
+ service.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 block text-sm text-muted-foreground", children: service.description }) : null
1138
+ ] }),
1139
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-right", children: [
1140
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block font-semibold tabular-nums text-primary", children: fmt.price.format(service.price) }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto mt-1 h-4 w-4 text-muted-foreground transition-transform group-hover:translate-x-0.5" })
905
1142
  ] })
906
- ] }) })
1143
+ ]
1144
+ }
1145
+ );
1146
+ }
1147
+ function DefaultSidebarExtras({ professionalName, brand, onStartBooking, labels }) {
1148
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border bg-card p-5 shadow-sm", children: [
1149
+ /* @__PURE__ */ jsxRuntime.jsx(
1150
+ "button",
1151
+ {
1152
+ type: "button",
1153
+ onClick: onStartBooking,
1154
+ className: "w-full rounded-xl bg-primary py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1155
+ children: labels.bookNowCta
1156
+ }
1157
+ ),
1158
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 space-y-2 border-t border-border pt-4 text-xs text-muted-foreground", children: [
1159
+ brand.highlights.map((h, i) => {
1160
+ const Icon = h.icon ?? lucideReact.User;
1161
+ return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
1162
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5 text-primary" }),
1163
+ " ",
1164
+ h.text
1165
+ ] }, i);
1166
+ }),
1167
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2", children: [
1168
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-3.5 w-3.5 text-primary" }),
1169
+ " ",
1170
+ professionalName
1171
+ ] })
907
1172
  ] })
908
1173
  ] });
909
1174
  }
1175
+ function DefaultStepRailItem({ n, label, state, children }) {
1176
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pl-11", children: [
1177
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute left-[15px] top-8 bottom-[-18px] w-px bg-border last:hidden" }),
1178
+ /* @__PURE__ */ jsxRuntime.jsx(
1179
+ "span",
1180
+ {
1181
+ className: [
1182
+ "absolute left-0 top-0 flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold transition-colors",
1183
+ state === "done" ? "bg-primary text-primary-foreground" : state === "active" ? "bg-accent text-primary ring-2 ring-primary" : "bg-muted text-muted-foreground"
1184
+ ].join(" "),
1185
+ children: state === "done" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) : n
1186
+ }
1187
+ ),
1188
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `pt-1 text-sm font-semibold ${state === "todo" ? "text-muted-foreground" : "text-foreground"}`, children: label }),
1189
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children }) : null
1190
+ ] });
1191
+ }
1192
+ function DefaultSuccessPanel({ service, slotStart, professionalName, labels, fmt }) {
1193
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-8 text-center", children: [
1194
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-accent text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-8 w-8" }) }),
1195
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-heading text-2xl font-bold text-foreground", children: labels.successTitle }),
1196
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mx-auto mt-2 max-w-sm text-muted-foreground", children: labels.successBody }),
1197
+ service && slotStart ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto mt-6 max-w-sm rounded-2xl border border-border bg-muted/50 p-4 text-left", children: [
1198
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-foreground", children: service.name }),
1199
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 flex items-center gap-1.5 text-sm tabular-nums text-muted-foreground", children: [
1200
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4 text-primary" }),
1201
+ " ",
1202
+ formatSlotRange(slotStart, service.durationMinutes, fmt)
1203
+ ] }),
1204
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 flex items-center gap-1.5 text-sm text-muted-foreground", children: [
1205
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4 text-primary" }),
1206
+ " ",
1207
+ professionalName
1208
+ ] })
1209
+ ] }) : null
1210
+ ] });
1211
+ }
1212
+
1213
+ // src/public/components/defaults.ts
1214
+ var DEFAULT_BOOKING_COMPONENTS = {
1215
+ BrandHeader: DefaultBrandHeader,
1216
+ ServiceCard: DefaultServiceCard,
1217
+ SidebarExtras: DefaultSidebarExtras,
1218
+ StepRailItem: DefaultStepRailItem,
1219
+ SuccessPanel: DefaultSuccessPanel
1220
+ };
910
1221
 
911
1222
  // src/public/createPublicBookingPlugin.ts
912
1223
  var DEFAULT_LABELS = {
@@ -916,10 +1227,71 @@ var DEFAULT_LABELS = {
916
1227
  contactStep: "Seus dados",
917
1228
  confirmCta: "Confirmar agendamento",
918
1229
  successTitle: "Agendamento confirmado!",
919
- successBody: "Voc\xEA receber\xE1 os detalhes em breve. At\xE9 logo!"
1230
+ successBody: "Voc\xEA receber\xE1 os detalhes em breve. At\xE9 logo!",
1231
+ // overview
1232
+ servicesHeading: "Servi\xE7os",
1233
+ aboutHeading: "Sobre",
1234
+ openingHoursHeading: "Hor\xE1rio de funcionamento",
1235
+ closedLabel: "Fechado",
1236
+ bookNowCta: "Agendar agora",
1237
+ // datetime
1238
+ timezoneNote: "Fuso: Hor\xE1rio de Bras\xEDlia",
1239
+ slotsHeading: "Hor\xE1rios dispon\xEDveis",
1240
+ noSlots: "Nenhum hor\xE1rio dispon\xEDvel neste dia. Tente outra data.",
1241
+ continueCta: "Continuar",
1242
+ backToServices: "Servi\xE7os",
1243
+ back: "Voltar",
1244
+ prevWeek: "Semana anterior",
1245
+ nextWeek: "Pr\xF3xima semana",
1246
+ // contact
1247
+ contactIntro: "Preencha as informa\xE7\xF5es abaixo para que seu agendamento seja identificado.",
1248
+ phoneLabel: "Celular",
1249
+ phoneHint: "Enviaremos um c\xF3digo para confirmar que o n\xFAmero de telefone \xE9 seu. Usaremos este n\xFAmero para associar as suas informa\xE7\xF5es \xE0 sua conta.",
1250
+ sendCodeCta: "Enviar c\xF3digo via WhatsApp",
1251
+ codeTitle: "Insira o c\xF3digo",
1252
+ codeBody: "Enviamos um c\xF3digo via WhatsApp para voc\xEA confirmar seu n\xFAmero.",
1253
+ codeInvalid: "C\xF3digo inv\xE1lido. Para testar, use 0000.",
1254
+ codeConfirmCta: "Confirmar",
1255
+ codeResendHint: "Reenviar c\xF3digo via WhatsApp em 28 segundos.",
1256
+ phoneVerified: "Celular verificado",
1257
+ changePhone: "Trocar telefone",
1258
+ nameLabel: "Nome completo *",
1259
+ namePlaceholder: "Seu nome",
1260
+ emailLabel: "E-mail",
1261
+ emailPlaceholder: "voce@email.com",
1262
+ emailHint: "Enviaremos uma confirma\xE7\xE3o e um lembrete antes do agendamento.",
1263
+ notesLabel: "Observa\xE7\xE3o",
1264
+ notesPlaceholder: "Use esse espa\xE7o para deixar uma observa\xE7\xE3o sobre este agendamento",
1265
+ saveAndContinueCta: "Salvar e continuar",
1266
+ submitError: "N\xE3o foi poss\xEDvel concluir o agendamento. Tente novamente.",
1267
+ noChargeNote: "Pagamento via Pix \xB7 Sem cobran\xE7a agora",
1268
+ // right rail
1269
+ railTitle: "Passos para agendar",
1270
+ railWaitingPayment: "Aguardando pagamento",
1271
+ railService: "Servi\xE7o",
1272
+ railProfessional: "Profissional",
1273
+ railDatetime: "Data e hor\xE1rio",
1274
+ railContact: "Informa\xE7\xF5es pessoais",
1275
+ railPayment: "Pagamento"
920
1276
  };
921
1277
  var DEFAULT_WINDOW = { minAdvanceHours: 2, maxAdvanceDays: 21, slotInterval: 30 };
922
1278
  var DEFAULT_HOURS = { daysOfWeek: [1, 2, 3, 4, 5, 6], start: "09:00", end: "18:00" };
1279
+ function resolveBrand(brand, labels) {
1280
+ const name = brand?.name ?? labels.title;
1281
+ return {
1282
+ name,
1283
+ initials: brand?.initials ?? name.charAt(0).toUpperCase(),
1284
+ logoUrl: brand?.logoUrl,
1285
+ tagline: brand?.tagline === void 0 ? "Agendamento online seguro" : brand.tagline,
1286
+ serviceIcon: brand?.serviceIcon ?? lucideReact.Video,
1287
+ serviceMeta: brand?.serviceMeta === void 0 ? "Online" : brand.serviceMeta,
1288
+ featuredBadge: brand?.featuredBadge === void 0 ? "Mais procurado" : brand.featuredBadge,
1289
+ highlights: brand?.highlights ?? [
1290
+ { icon: lucideReact.CalendarCheck, text: "Confirma\xE7\xE3o imediata" },
1291
+ { icon: lucideReact.ShieldCheck, text: "Agendamento seguro" }
1292
+ ]
1293
+ };
1294
+ }
923
1295
  var scheduleId = 0;
924
1296
  function buildSchedules(professionalId, hours) {
925
1297
  return hours.daysOfWeek.map((day) => ({
@@ -938,19 +1310,23 @@ function buildSchedules(professionalId, hours) {
938
1310
  }
939
1311
  function createPublicBookingPlugin(options) {
940
1312
  const basePath = options.basePath ?? "/agendar";
941
- const professionalId = options.professional?.id ?? "dr-hiago";
1313
+ const mockProfessionalId = options.professional?.id ?? "pro-1";
1314
+ const professionalId = options.professional?.id ?? null;
942
1315
  const professionalName = options.professional?.name ?? "Especialista";
943
1316
  const window2 = { ...DEFAULT_WINDOW, ...options.window };
944
1317
  const labels = { ...DEFAULT_LABELS, ...options.labels };
1318
+ const brand = resolveBrand(options.brand, labels);
1319
+ const components = { ...DEFAULT_BOOKING_COMPONENTS, ...options.components };
945
1320
  const currency = options.currency ?? "BRL";
946
1321
  const locale = options.locale ?? "pt-BR";
947
1322
  const hours = options.workingHours ?? DEFAULT_HOURS;
1323
+ const staticServices = options.services ?? null;
948
1324
  const payment = options.payment?.enabled ? {
949
1325
  reservationFeePercent: options.payment.reservationFeePercent ?? 100,
950
1326
  method: options.payment.method ?? "pix"
951
1327
  } : null;
952
1328
  const professional = {
953
- id: professionalId,
1329
+ id: mockProfessionalId,
954
1330
  name: professionalName,
955
1331
  avatarUrl: null,
956
1332
  locationId: null,
@@ -959,28 +1335,42 @@ function createPublicBookingPlugin(options) {
959
1335
  };
960
1336
  const mockSeed = options.seed ?? {
961
1337
  professionals: [professional],
962
- schedules: buildSchedules(professionalId, hours),
1338
+ schedules: buildSchedules(mockProfessionalId, hours),
963
1339
  bookings: []
964
1340
  };
965
- const provider = options.dataProvider ?? core.createSafeDataProvider(
966
- () => chunkGAJVIEXM_cjs.createSupabaseAgendaProvider(),
967
- () => chunkGAJVIEXM_cjs.createMockAgendaProvider({ seed: mockSeed })
968
- );
969
- const value = {
1341
+ let provider;
1342
+ if (options.dataProvider) {
1343
+ provider = options.dataProvider;
1344
+ } else if (options.tenantId) {
1345
+ provider = createSupabasePublicBookingProvider({ tenantId: options.tenantId });
1346
+ } else {
1347
+ if (typeof console !== "undefined") {
1348
+ console.warn(
1349
+ "[plugin-agenda/public] no `tenantId` and no `dataProvider` \u2014 falling back to the seeded MOCK provider. Pass `tenantId` to book against Fayz Cloud, or inject a dataProvider."
1350
+ );
1351
+ }
1352
+ provider = createMockPublicBookingProvider({
1353
+ seed: mockSeed,
1354
+ services: staticServices ?? [],
1355
+ professionalId: mockProfessionalId
1356
+ });
1357
+ }
1358
+ const base = {
970
1359
  provider,
971
1360
  professionalId,
972
1361
  professionalName,
973
- services: options.services,
974
1362
  businessHours: hours,
975
1363
  payment,
976
1364
  paymentProvider: options.paymentProvider ?? null,
977
1365
  onIdentityVerified: options.onIdentityVerified ?? null,
978
1366
  window: window2,
979
1367
  labels,
1368
+ brand,
1369
+ components,
980
1370
  currency,
981
1371
  locale
982
1372
  };
983
- const Provider = ({ children }) => react.createElement(BookingProvider, { value, children });
1373
+ const Provider = ({ children }) => react.createElement(BookingProvider, { base, staticServices, children });
984
1374
  Provider.displayName = "PublicBookingProvider";
985
1375
  const BookingScreen = () => react.createElement(
986
1376
  "section",
@@ -996,7 +1386,7 @@ function createPublicBookingPlugin(options) {
996
1386
  id: "booking",
997
1387
  name: "Agendamento",
998
1388
  icon: "CalendarCheck",
999
- version: "0.1.0",
1389
+ version: "0.4.0",
1000
1390
  scope: options.scope ?? "universal",
1001
1391
  verticalId: options.verticalId,
1002
1392
  scaffolds: ["website", "landing_page"],
@@ -1011,10 +1401,23 @@ function createPublicBookingPlugin(options) {
1011
1401
 
1012
1402
  exports.BookingProvider = BookingProvider;
1013
1403
  exports.BookingWidget = BookingWidget;
1404
+ exports.DAY_NAMES = DAY_NAMES;
1405
+ exports.DEFAULT_BOOKING_COMPONENTS = DEFAULT_BOOKING_COMPONENTS;
1406
+ exports.DefaultBrandHeader = DefaultBrandHeader;
1407
+ exports.DefaultServiceCard = DefaultServiceCard;
1408
+ exports.DefaultSidebarExtras = DefaultSidebarExtras;
1409
+ exports.DefaultStepRailItem = DefaultStepRailItem;
1410
+ exports.DefaultSuccessPanel = DefaultSuccessPanel;
1411
+ exports.WEEK_ORDER = WEEK_ORDER;
1412
+ exports.createMockPublicBookingProvider = createMockPublicBookingProvider;
1014
1413
  exports.createPublicBookingPlugin = createPublicBookingPlugin;
1414
+ exports.createSupabasePublicBookingProvider = createSupabasePublicBookingProvider;
1415
+ exports.formatSlotRange = formatSlotRange;
1015
1416
  exports.useAvailableSlots = useAvailableSlots;
1016
1417
  exports.useBooking = useBooking;
1017
1418
  exports.useCreateBooking = useCreateBooking;
1419
+ exports.useFormatters = useFormatters;
1420
+ exports.usePublicServices = usePublicServices;
1018
1421
  exports.useServices = useServices;
1019
1422
  //# sourceMappingURL=index.cjs.map
1020
1423
  //# sourceMappingURL=index.cjs.map