@anker-in/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3077 @@
1
+ 'use strict';
2
+
3
+ var React2 = require('react');
4
+ var clsx = require('clsx');
5
+ var tailwindMerge = require('tailwind-merge');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var headlessUi = require('@anker-in/headless-ui');
8
+ var IndexBar = require('antd-mobile/es/components/index-bar');
9
+ var List = require('antd-mobile/es/components/list');
10
+ require('antd-mobile/es/components/index-bar/index-bar.css');
11
+ require('antd-mobile/es/components/list/list.css');
12
+ var react = require('swiper/react');
13
+ var modules = require('swiper/modules');
14
+ require('swiper/css');
15
+ require('swiper/css/navigation');
16
+ require('swiper/css/pagination');
17
+ var dayjs = require('dayjs');
18
+ require('dayjs/locale/zh-cn');
19
+ var antd = require('antd');
20
+ var dayLocaleData = require('dayjs/plugin/localeData');
21
+ var weekday = require('dayjs/plugin/weekday');
22
+ var weekOfYear = require('dayjs/plugin/weekOfYear');
23
+
24
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
25
+
26
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
27
+ var IndexBar__default = /*#__PURE__*/_interopDefault(IndexBar);
28
+ var List__default = /*#__PURE__*/_interopDefault(List);
29
+ var dayjs__default = /*#__PURE__*/_interopDefault(dayjs);
30
+ var dayLocaleData__default = /*#__PURE__*/_interopDefault(dayLocaleData);
31
+ var weekday__default = /*#__PURE__*/_interopDefault(weekday);
32
+ var weekOfYear__default = /*#__PURE__*/_interopDefault(weekOfYear);
33
+
34
+ function cn(...inputs) {
35
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
36
+ }
37
+ var defaultTabs = [
38
+ { id: "upcoming-events", label: "Upcoming Events" },
39
+ { id: "find-demoroom", label: "Find Demoroom" },
40
+ { id: "4-easy-steps", label: "4 Easy Steps" },
41
+ { id: "faq", label: "FAQ" }
42
+ ];
43
+ var HelpNav = ({
44
+ tabs = defaultTabs,
45
+ activeTabId: controlledActiveTabId,
46
+ onTabChange,
47
+ activeBorderColor = "#3ADB67",
48
+ className,
49
+ ...props
50
+ }) => {
51
+ const [internalActiveTabId, setInternalActiveTabId] = React2.useState(
52
+ tabs[1]?.id || tabs[0]?.id
53
+ );
54
+ const activeTabId = controlledActiveTabId ?? internalActiveTabId;
55
+ const handleTabClick = (tabId) => {
56
+ if (!controlledActiveTabId) {
57
+ setInternalActiveTabId(tabId);
58
+ }
59
+ onTabChange?.(tabId);
60
+ };
61
+ return /* @__PURE__ */ jsxRuntime.jsx(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "w-full pt-5 flex items-center justify-center gap-8 pb-8",
66
+ className
67
+ ),
68
+ ...props,
69
+ children: tabs.map((tab) => {
70
+ const isActive = tab.id === activeTabId;
71
+ return /* @__PURE__ */ jsxRuntime.jsxs(
72
+ "button",
73
+ {
74
+ onClick: () => handleTabClick(tab.id),
75
+ className: cn(
76
+ "relative text-[#080A0F]",
77
+ "pb-4",
78
+ "flex items-center gap-2",
79
+ "transition-all duration-200",
80
+ "outline-none focus:outline-none"
81
+ ),
82
+ style: {
83
+ fontSize: "18px",
84
+ fontWeight: 600,
85
+ letterSpacing: "-0.36px",
86
+ lineHeight: "25.2px"
87
+ },
88
+ children: [
89
+ tab.label,
90
+ isActive && /* @__PURE__ */ jsxRuntime.jsx(
91
+ "span",
92
+ {
93
+ className: "absolute bottom-0 left-0 right-0 h-1 rounded-t",
94
+ style: {
95
+ backgroundColor: activeBorderColor,
96
+ height: "4px"
97
+ }
98
+ }
99
+ )
100
+ ]
101
+ },
102
+ tab.id
103
+ );
104
+ })
105
+ }
106
+ );
107
+ };
108
+ HelpNav.displayName = "HelpNav";
109
+ var EventCard = ({
110
+ title,
111
+ description,
112
+ backgroundImage,
113
+ aspectRatio,
114
+ variant = "medium",
115
+ buttons = [],
116
+ subtitle,
117
+ className,
118
+ ...props
119
+ }) => {
120
+ const isLarge = variant === "large";
121
+ const isMedium = variant === "medium";
122
+ const isProduct = variant === "product";
123
+ return /* @__PURE__ */ jsxRuntime.jsx(
124
+ "div",
125
+ {
126
+ className: cn("rounded-3xl overflow-hidden relative", className),
127
+ style: {
128
+ backgroundImage: backgroundImage ? `url(${backgroundImage})` : void 0,
129
+ backgroundSize: "cover",
130
+ backgroundPosition: "center",
131
+ aspectRatio
132
+ },
133
+ ...props,
134
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
135
+ "div",
136
+ {
137
+ className: cn(
138
+ "relative h-full flex flex-col",
139
+ isLarge && "justify-center pl-8",
140
+ !isLarge && "justify-end pl-8 pb-8"
141
+ ),
142
+ children: [
143
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
144
+ /* @__PURE__ */ jsxRuntime.jsx(
145
+ "h3",
146
+ {
147
+ className: cn(
148
+ "font-semibold mb-3",
149
+ isLarge && "text-3xl text-gray-900",
150
+ isMedium && "text-2xl text-white",
151
+ isProduct && "text-2xl text-gray-900"
152
+ ),
153
+ children: title
154
+ }
155
+ ),
156
+ subtitle && isProduct && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600 mb-4", children: subtitle }),
157
+ description && /* @__PURE__ */ jsxRuntime.jsx(
158
+ "p",
159
+ {
160
+ className: cn(
161
+ "text-sm leading-relaxed",
162
+ isMedium && "text-white/90",
163
+ (isLarge || isProduct) && "text-gray-600"
164
+ ),
165
+ children: description
166
+ }
167
+ )
168
+ ] }),
169
+ buttons.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-3 mt-6", children: buttons.map((button, index) => /* @__PURE__ */ jsxRuntime.jsx(
170
+ "button",
171
+ {
172
+ onClick: button.onClick,
173
+ className: cn(
174
+ "px-6 py-3 rounded-full font-medium text-sm transition-all duration-200",
175
+ button.variant === "primary" && "bg-gray-900 text-white hover:bg-gray-800",
176
+ button.variant === "secondary" && "bg-white text-gray-900 border border-gray-300 hover:bg-gray-50"
177
+ ),
178
+ children: button.label
179
+ },
180
+ index
181
+ )) })
182
+ ]
183
+ }
184
+ )
185
+ }
186
+ );
187
+ };
188
+ EventCard.displayName = "EventCard";
189
+ var Title = ({
190
+ title = "",
191
+ ...props
192
+ }) => {
193
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full"), ...props, children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-[48px] font-semibold mb-12 text-[#080A0F]", children: title }) });
194
+ };
195
+ Title.displayName = "Title";
196
+ var defaultEvents = [
197
+ {
198
+ variant: "large",
199
+ title: "IFA 2025 Event Name Event Name",
200
+ description: "Corem ipsum dolor sit amet, consectetur adipiscing elit.",
201
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
202
+ buttons: [
203
+ {
204
+ label: "Schedule Now",
205
+ variant: "primary"
206
+ }
207
+ ],
208
+ aspectRatio: "1664 / 640"
209
+ },
210
+ {
211
+ variant: "medium",
212
+ title: "Local Event Name Local Event Name Local Event Name",
213
+ description: "Norem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis.",
214
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
215
+ buttons: [
216
+ {
217
+ label: "Schedule Now",
218
+ variant: "primary"
219
+ }
220
+ ],
221
+ aspectRatio: "824 / 640"
222
+ },
223
+ {
224
+ variant: "product",
225
+ title: "Anker Prime",
226
+ subtitle: "Anker Prime 240W GaN Desktop Charger (4 Ports) Feb. 5th - 16th",
227
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
228
+ buttons: [
229
+ {
230
+ label: "Learn More",
231
+ variant: "secondary"
232
+ },
233
+ {
234
+ label: "Shop Now",
235
+ variant: "primary"
236
+ }
237
+ ],
238
+ aspectRatio: "824 / 640"
239
+ },
240
+ {
241
+ variant: "medium",
242
+ title: "Local Event Name Local Event Name Local Event Name",
243
+ description: "Norem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis.",
244
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
245
+ buttons: [
246
+ {
247
+ label: "Schedule Now",
248
+ variant: "primary"
249
+ }
250
+ ],
251
+ aspectRatio: "824 / 640"
252
+ },
253
+ {
254
+ variant: "product",
255
+ title: "Anker Prime",
256
+ subtitle: "Anker Prime 240W GaN Desktop Charger (4 Ports) Feb. 5th - 16th",
257
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
258
+ buttons: [
259
+ {
260
+ label: "Learn More",
261
+ variant: "secondary"
262
+ },
263
+ {
264
+ label: "Shop Now",
265
+ variant: "primary"
266
+ }
267
+ ],
268
+ aspectRatio: "824 / 640"
269
+ }
270
+ ];
271
+ var UpcomingEvents = ({
272
+ title = "Upcoming Events",
273
+ events = defaultEvents,
274
+ showViewMore = true,
275
+ onViewMore,
276
+ className,
277
+ ...props
278
+ }) => {
279
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), ...props, children: [
280
+ /* @__PURE__ */ jsxRuntime.jsx(Title, { title }),
281
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-6 mb-[64px]", children: events.map((event, index) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(index === 0 ? "col-span-2" : ""), children: /* @__PURE__ */ jsxRuntime.jsx(EventCard, { ...event }) }, index)) }),
282
+ showViewMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
283
+ "button",
284
+ {
285
+ onClick: onViewMore,
286
+ className: "inline-flex items-center gap-2 text-gray-700 hover:text-gray-900 transition-colors duration-200",
287
+ children: [
288
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-bold", children: "View More" }),
289
+ /* @__PURE__ */ jsxRuntime.jsx(
290
+ "svg",
291
+ {
292
+ width: "16",
293
+ height: "16",
294
+ viewBox: "0 0 16 16",
295
+ fill: "none",
296
+ xmlns: "http://www.w3.org/2000/svg",
297
+ className: "transition-transform duration-200 group-hover:translate-y-0.5",
298
+ children: /* @__PURE__ */ jsxRuntime.jsx(
299
+ "path",
300
+ {
301
+ d: "M8 3L8 13M8 13L12 9M8 13L4 9",
302
+ stroke: "currentColor",
303
+ strokeWidth: "2",
304
+ strokeLinecap: "round",
305
+ strokeLinejoin: "round"
306
+ }
307
+ )
308
+ }
309
+ )
310
+ ]
311
+ }
312
+ ) })
313
+ ] });
314
+ };
315
+ UpcomingEvents.displayName = "UpcomingEvents";
316
+ var defaultBannerData = {
317
+ title: "See it. Touch it. Make it Locally.",
318
+ subTitle: "Visit your local studio right around the corner.",
319
+ backgroundImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
320
+ backgroundImageMobile: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
321
+ };
322
+ var Banner = ({
323
+ data = defaultBannerData,
324
+ className,
325
+ style,
326
+ ...props
327
+ }) => {
328
+ return /* @__PURE__ */ jsxRuntime.jsxs(
329
+ "div",
330
+ {
331
+ className: cn("relative"),
332
+ style: { aspectRatio: "1920/480", ...style },
333
+ ...props,
334
+ children: [
335
+ data?.backgroundImage && /* @__PURE__ */ jsxRuntime.jsx(
336
+ "img",
337
+ {
338
+ src: data.backgroundImage,
339
+ alt: "",
340
+ className: "inset-0 h-full w-full object-cover"
341
+ }
342
+ ),
343
+ /* @__PURE__ */ jsxRuntime.jsxs(
344
+ "div",
345
+ {
346
+ className: cn(
347
+ "absolute flex flex-col gap-4 justify-center m-auto top-0 bottom-0 left-0 right-0 z-10",
348
+ className
349
+ ),
350
+ children: [
351
+ /* @__PURE__ */ jsxRuntime.jsx(
352
+ headlessUi.Text,
353
+ {
354
+ className: "text-[48px] font-bold text-white leading-[1]",
355
+ html: data?.title
356
+ }
357
+ ),
358
+ /* @__PURE__ */ jsxRuntime.jsx(
359
+ headlessUi.Text,
360
+ {
361
+ className: "text-[18px] font-bold text-white leading-[1.4]",
362
+ html: data?.subTitle
363
+ }
364
+ )
365
+ ]
366
+ }
367
+ )
368
+ ]
369
+ }
370
+ );
371
+ };
372
+ Banner.displayName = "Banner";
373
+ var BreadCrumbs = ({
374
+ items,
375
+ className,
376
+ ...props
377
+ }) => {
378
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center py-6 gap-1 text-[18px]", className), ...props, children: items?.map((item, i) => {
379
+ const isLast = i === items?.length - 1;
380
+ return /* @__PURE__ */ jsxRuntime.jsxs(
381
+ headlessUi.Link,
382
+ {
383
+ className: cn(
384
+ "flex items-center gap-1 text-[#6D6D6F] no-underline",
385
+ isLast && "text-[#080A0F]",
386
+ item?.link ? "cursor-pointer" : "cursor-default hover:text-[#080A0F]"
387
+ ),
388
+ href: item?.link,
389
+ children: [
390
+ item?.label,
391
+ !isLast && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "/" })
392
+ ]
393
+ },
394
+ i
395
+ );
396
+ }) });
397
+ };
398
+ BreadCrumbs.displayName = "BreadCrumbs";
399
+ var defaultSteps = [
400
+ {
401
+ stepNumber: 1,
402
+ title: 'Find a demo room you would like to visit, and click "Schedule Now"',
403
+ description: 'Find a demo room you would like to visit, and click "Schedule Now"',
404
+ mapImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
405
+ },
406
+ {
407
+ stepNumber: 2,
408
+ title: "Fill out the form and confirm your time of visit",
409
+ description: "Fill out the form and confirm your time of visit",
410
+ mapImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
411
+ },
412
+ {
413
+ stepNumber: 3,
414
+ title: "Once you arrive at the demo room, scan the QR code to check in",
415
+ description: "Once you arrive at the demo room, scan the QR code to check in",
416
+ mapImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
417
+ },
418
+ {
419
+ stepNumber: 4,
420
+ title: "Have fun!",
421
+ description: "Have fun!",
422
+ mapImage: "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
423
+ }
424
+ ];
425
+ var EasySteps = ({
426
+ title = "Schedule in 4 Easy Steps",
427
+ steps = defaultSteps,
428
+ className,
429
+ ...props
430
+ }) => {
431
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), ...props, children: [
432
+ /* @__PURE__ */ jsxRuntime.jsx(Title, { title }),
433
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-2 gap-6", children: steps.map((step) => /* @__PURE__ */ jsxRuntime.jsxs(
434
+ "div",
435
+ {
436
+ className: cn(
437
+ "bg-white rounded-2xl overflow-hidden",
438
+ "border border-gray-200",
439
+ "hover:shadow-lg transition-shadow duration-200"
440
+ ),
441
+ children: [
442
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 pb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 mb-3", children: [
443
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold text-gray-900", children: [
444
+ "Step ",
445
+ step.stepNumber,
446
+ ":"
447
+ ] }),
448
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-900 font-medium flex-1", children: step.title })
449
+ ] }) }),
450
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full aspect-[356/220] bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(
451
+ "img",
452
+ {
453
+ src: step.mapImage,
454
+ alt: `Step ${step.stepNumber} - ${step.title}`,
455
+ className: "w-full h-full object-cover"
456
+ }
457
+ ) })
458
+ ]
459
+ },
460
+ step.stepNumber
461
+ )) })
462
+ ] });
463
+ };
464
+ EasySteps.displayName = "EasySteps";
465
+ var StudioCard = ({
466
+ code,
467
+ name,
468
+ availableTime,
469
+ address,
470
+ city,
471
+ state,
472
+ zipCode,
473
+ country = "United States",
474
+ euifyMakeModel,
475
+ onSchedule,
476
+ className,
477
+ ...props
478
+ }) => {
479
+ const fullAddress = `${address}, ${city}, ${state} ${country} ${zipCode}`;
480
+ const handleScheduleClick = () => {
481
+ onSchedule?.(code);
482
+ };
483
+ return /* @__PURE__ */ jsxRuntime.jsxs(
484
+ "div",
485
+ {
486
+ className: cn(
487
+ "p-6",
488
+ "hover:shadow-lg transition-shadow duration-200",
489
+ className
490
+ ),
491
+ ...props,
492
+ children: [
493
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-semibold text-gray-900 mb-4", children: name }),
494
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 mb-3", children: [
495
+ /* @__PURE__ */ jsxRuntime.jsxs(
496
+ "svg",
497
+ {
498
+ width: "20",
499
+ height: "20",
500
+ viewBox: "0 0 20 20",
501
+ fill: "none",
502
+ xmlns: "http://www.w3.org/2000/svg",
503
+ className: "flex-shrink-0 mt-0.5",
504
+ children: [
505
+ /* @__PURE__ */ jsxRuntime.jsx(
506
+ "rect",
507
+ {
508
+ x: "3",
509
+ y: "4",
510
+ width: "14",
511
+ height: "13",
512
+ rx: "2",
513
+ stroke: "currentColor",
514
+ strokeWidth: "1.5"
515
+ }
516
+ ),
517
+ /* @__PURE__ */ jsxRuntime.jsx(
518
+ "path",
519
+ {
520
+ d: "M3 8H17",
521
+ stroke: "currentColor",
522
+ strokeWidth: "1.5",
523
+ strokeLinecap: "round"
524
+ }
525
+ ),
526
+ /* @__PURE__ */ jsxRuntime.jsx(
527
+ "path",
528
+ {
529
+ d: "M6 2V4",
530
+ stroke: "currentColor",
531
+ strokeWidth: "1.5",
532
+ strokeLinecap: "round"
533
+ }
534
+ ),
535
+ /* @__PURE__ */ jsxRuntime.jsx(
536
+ "path",
537
+ {
538
+ d: "M14 2V4",
539
+ stroke: "currentColor",
540
+ strokeWidth: "1.5",
541
+ strokeLinecap: "round"
542
+ }
543
+ )
544
+ ]
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600", children: [
548
+ "Available ",
549
+ availableTime
550
+ ] }) })
551
+ ] }),
552
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 mb-3", children: [
553
+ /* @__PURE__ */ jsxRuntime.jsxs(
554
+ "svg",
555
+ {
556
+ width: "20",
557
+ height: "20",
558
+ viewBox: "0 0 20 20",
559
+ fill: "none",
560
+ xmlns: "http://www.w3.org/2000/svg",
561
+ className: "flex-shrink-0 mt-0.5",
562
+ children: [
563
+ /* @__PURE__ */ jsxRuntime.jsx(
564
+ "path",
565
+ {
566
+ d: "M10 10C11.1046 10 12 9.10457 12 8C12 6.89543 11.1046 6 10 6C8.89543 6 8 6.89543 8 8C8 9.10457 8.89543 10 10 10Z",
567
+ stroke: "currentColor",
568
+ strokeWidth: "1.5"
569
+ }
570
+ ),
571
+ /* @__PURE__ */ jsxRuntime.jsx(
572
+ "path",
573
+ {
574
+ d: "M10 18C10 18 16 13 16 8C16 4.68629 13.3137 2 10 2C6.68629 2 4 4.68629 4 8C4 13 10 18 10 18Z",
575
+ stroke: "currentColor",
576
+ strokeWidth: "1.5"
577
+ }
578
+ )
579
+ ]
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: fullAddress }) })
583
+ ] }),
584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 mb-6", children: [
585
+ /* @__PURE__ */ jsxRuntime.jsxs(
586
+ "svg",
587
+ {
588
+ width: "20",
589
+ height: "20",
590
+ viewBox: "0 0 20 20",
591
+ fill: "none",
592
+ xmlns: "http://www.w3.org/2000/svg",
593
+ className: "flex-shrink-0 mt-0.5",
594
+ children: [
595
+ /* @__PURE__ */ jsxRuntime.jsx(
596
+ "rect",
597
+ {
598
+ x: "3",
599
+ y: "5",
600
+ width: "14",
601
+ height: "10",
602
+ rx: "1.5",
603
+ stroke: "currentColor",
604
+ strokeWidth: "1.5"
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsxRuntime.jsx(
608
+ "path",
609
+ {
610
+ d: "M7 15V17",
611
+ stroke: "currentColor",
612
+ strokeWidth: "1.5",
613
+ strokeLinecap: "round"
614
+ }
615
+ ),
616
+ /* @__PURE__ */ jsxRuntime.jsx(
617
+ "path",
618
+ {
619
+ d: "M13 15V17",
620
+ stroke: "currentColor",
621
+ strokeWidth: "1.5",
622
+ strokeLinecap: "round"
623
+ }
624
+ ),
625
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "1.5", fill: "currentColor" })
626
+ ]
627
+ }
628
+ ),
629
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: euifyMakeModel }) })
630
+ ] }),
631
+ /* @__PURE__ */ jsxRuntime.jsx(
632
+ "button",
633
+ {
634
+ onClick: handleScheduleClick,
635
+ className: cn(
636
+ "w-full px-6 py-3 rounded-full",
637
+ "bg-white text-gray-900 border border-gray-900",
638
+ "font-medium text-sm",
639
+ "hover:bg-gray-900 hover:text-white",
640
+ "transition-all duration-200"
641
+ ),
642
+ children: "Schedule Now"
643
+ }
644
+ )
645
+ ]
646
+ }
647
+ );
648
+ };
649
+ StudioCard.displayName = "StudioCard";
650
+ var defaultLocations = [
651
+ {
652
+ id: "1",
653
+ name: "Design District Demo Room",
654
+ address: "111 8th St",
655
+ city: "San Francisco",
656
+ state: "CA",
657
+ zipCode: "94108",
658
+ country: "United States",
659
+ lat: 37.7749,
660
+ lng: -122.4194,
661
+ availableTime: "Oct 28, 2:00 PM",
662
+ euifyMakeModel: "euifyMake E1, euifyMake M5"
663
+ }
664
+ ];
665
+ var StudioMap = ({
666
+ googleMapsApiKey,
667
+ locations = defaultLocations,
668
+ defaultCenter = { lat: 39.8283, lng: -98.5795 },
669
+ // US center
670
+ defaultZoom = 4,
671
+ mapHeight = "600px",
672
+ onSchedule,
673
+ className,
674
+ ...props
675
+ }) => {
676
+ const [_selectedLocation, setSelectedLocation] = React2.useState(null);
677
+ const [isLoaded, setIsLoaded] = React2.useState(false);
678
+ const mapRef = React2__default.default.useRef(null);
679
+ const googleMapRef = React2__default.default.useRef(null);
680
+ const markersRef = React2__default.default.useRef([]);
681
+ const infoWindowRef = React2__default.default.useRef(null);
682
+ React2__default.default.useEffect(() => {
683
+ if (!googleMapsApiKey) {
684
+ console.error("Google Maps API Key is required");
685
+ return;
686
+ }
687
+ if (window.google && window.google.maps) {
688
+ setIsLoaded(true);
689
+ return;
690
+ }
691
+ const script = document.createElement("script");
692
+ script.src = `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&libraries=places`;
693
+ script.async = true;
694
+ script.defer = true;
695
+ script.onload = () => setIsLoaded(true);
696
+ script.onerror = () => console.error("Failed to load Google Maps script");
697
+ document.head.appendChild(script);
698
+ return () => {
699
+ if (script.parentNode) {
700
+ script.parentNode.removeChild(script);
701
+ }
702
+ };
703
+ }, [googleMapsApiKey]);
704
+ React2__default.default.useEffect(() => {
705
+ if (!isLoaded || !mapRef.current || googleMapRef.current) return;
706
+ const map = new google.maps.Map(mapRef.current, {
707
+ center: defaultCenter,
708
+ zoom: defaultZoom,
709
+ styles: [
710
+ {
711
+ featureType: "all",
712
+ elementType: "geometry",
713
+ stylers: [{ color: "#E0F2F1" }]
714
+ },
715
+ {
716
+ featureType: "water",
717
+ elementType: "geometry",
718
+ stylers: [{ color: "#B2EBF2" }]
719
+ },
720
+ {
721
+ featureType: "road",
722
+ elementType: "geometry",
723
+ stylers: [{ color: "#ffffff" }]
724
+ }
725
+ ],
726
+ mapTypeControl: false,
727
+ streetViewControl: false,
728
+ fullscreenControl: true
729
+ });
730
+ googleMapRef.current = map;
731
+ infoWindowRef.current = new google.maps.InfoWindow();
732
+ }, [isLoaded, defaultCenter, defaultZoom]);
733
+ React2__default.default.useEffect(() => {
734
+ if (!googleMapRef.current || !isLoaded) return;
735
+ markersRef.current.forEach((marker) => marker.setMap(null));
736
+ markersRef.current = [];
737
+ const validLocations = locations.filter((location) => {
738
+ const lat = Number(location.lat);
739
+ const lng = Number(location.lng);
740
+ const isValid = !isNaN(lat) && !isNaN(lng) && isFinite(lat) && isFinite(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180;
741
+ if (!isValid) {
742
+ console.warn("Invalid location coordinates:", location);
743
+ }
744
+ return isValid;
745
+ });
746
+ validLocations.forEach((location) => {
747
+ const lat = Number(location.lat);
748
+ const lng = Number(location.lng);
749
+ const marker = new google.maps.Marker({
750
+ position: { lat, lng },
751
+ map: googleMapRef.current,
752
+ title: location.name,
753
+ icon: {
754
+ path: google.maps.SymbolPath.CIRCLE,
755
+ scale: 10,
756
+ fillColor: "#000000",
757
+ fillOpacity: 1,
758
+ strokeColor: "#ffffff",
759
+ strokeWeight: 2
760
+ }
761
+ });
762
+ marker.addListener("click", () => {
763
+ setSelectedLocation(location);
764
+ const content = `
765
+ <div style="padding: 16px; max-width: 300px; font-family: system-ui, sans-serif;">
766
+ <h3 style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600;">${location.name}</h3>
767
+ ${location.availableTime ? `<div style="margin-bottom: 8px; color: #666;">
768
+ <svg style="display: inline-block; width: 16px; height: 16px; margin-right: 4px; vertical-align: middle;" fill="currentColor" viewBox="0 0 20 20">
769
+ <path d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z"/>
770
+ </svg>
771
+ <span style="vertical-align: middle;">Available ${location.availableTime}</span>
772
+ </div>` : ""}
773
+ <div style="margin-bottom: 8px; color: #666;">
774
+ <svg style="display: inline-block; width: 16px; height: 16px; margin-right: 4px; vertical-align: middle;" fill="currentColor" viewBox="0 0 20 20">
775
+ <path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd"/>
776
+ </svg>
777
+ <span style="vertical-align: middle;">${location.address}, ${location.city}, ${location.state} ${location.country} ${location.zipCode}</span>
778
+ </div>
779
+ ${location.euifyMakeModel ? `<div style="margin-bottom: 12px; color: #666;">
780
+ <svg style="display: inline-block; width: 16px; height: 16px; margin-right: 4px; vertical-align: middle;" fill="currentColor" viewBox="0 0 20 20">
781
+ <path d="M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z"/>
782
+ </svg>
783
+ <span style="vertical-align: middle;">${location.euifyMakeModel}</span>
784
+ </div>` : ""}
785
+ <button
786
+ id="schedule-btn-${location.id}"
787
+ style="
788
+ width: 100%;
789
+ padding: 10px 16px;
790
+ background: #000;
791
+ color: #fff;
792
+ border: none;
793
+ border-radius: 6px;
794
+ font-weight: 500;
795
+ cursor: pointer;
796
+ font-size: 14px;
797
+ "
798
+ onmouseover="this.style.background='#333'"
799
+ onmouseout="this.style.background='#000'"
800
+ >
801
+ Schedule Now
802
+ </button>
803
+ </div>
804
+ `;
805
+ if (infoWindowRef.current) {
806
+ infoWindowRef.current.setContent(content);
807
+ infoWindowRef.current.open(googleMapRef.current, marker);
808
+ google.maps.event.addListenerOnce(
809
+ infoWindowRef.current,
810
+ "domready",
811
+ () => {
812
+ const btn = document.getElementById(`schedule-btn-${location.id}`);
813
+ if (btn) {
814
+ btn.addEventListener("click", () => {
815
+ if (onSchedule) {
816
+ onSchedule(location);
817
+ }
818
+ });
819
+ }
820
+ }
821
+ );
822
+ }
823
+ googleMapRef.current?.panTo({ lat: location.lat, lng: location.lng });
824
+ });
825
+ markersRef.current.push(marker);
826
+ });
827
+ if (validLocations.length > 0 && googleMapRef.current) {
828
+ const bounds = new google.maps.LatLngBounds();
829
+ validLocations.forEach((location) => {
830
+ const lat = Number(location.lat);
831
+ const lng = Number(location.lng);
832
+ bounds.extend({ lat, lng });
833
+ });
834
+ googleMapRef.current.fitBounds(bounds);
835
+ }
836
+ }, [isLoaded, locations, onSchedule]);
837
+ if (!googleMapsApiKey) {
838
+ return /* @__PURE__ */ jsxRuntime.jsx(
839
+ "div",
840
+ {
841
+ className: cn(
842
+ "flex items-center justify-center bg-gray-100 rounded-lg",
843
+ className
844
+ ),
845
+ style: { height: mapHeight },
846
+ ...props,
847
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600", children: "Google Maps API Key is required" })
848
+ }
849
+ );
850
+ }
851
+ return /* @__PURE__ */ jsxRuntime.jsxs(
852
+ "div",
853
+ {
854
+ className: cn("relative w-full rounded-lg overflow-hidden", className),
855
+ ...props,
856
+ children: [
857
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: mapRef, style: { height: mapHeight } }),
858
+ !isLoaded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-block animate-spin rounded-full h-8 w-8 border-4 border-gray-300 border-t-gray-900 mb-2" }),
860
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600", children: "Loading map..." })
861
+ ] }) })
862
+ ]
863
+ }
864
+ );
865
+ };
866
+ StudioMap.displayName = "StudioMap";
867
+
868
+ // src/api/types.ts
869
+ var ApiError = class extends Error {
870
+ constructor(code, message, request_id) {
871
+ super(message);
872
+ this.code = code;
873
+ this.request_id = request_id;
874
+ this.name = "ApiError";
875
+ }
876
+ };
877
+
878
+ // src/api/hooks.ts
879
+ function useDemoRooms(client, params, options) {
880
+ const [state, setState] = React2.useState({
881
+ data: null,
882
+ loading: true,
883
+ error: null
884
+ });
885
+ const enabled = options?.enabled !== false;
886
+ React2.useEffect(() => {
887
+ if (!enabled) return;
888
+ let cancelled = false;
889
+ const fetchData = async () => {
890
+ setState((prev) => ({ ...prev, loading: true, error: null }));
891
+ try {
892
+ const data = await client.getDemoRooms(params);
893
+ if (!cancelled) {
894
+ setState({ data, loading: false, error: null });
895
+ }
896
+ } catch (error) {
897
+ if (!cancelled) {
898
+ setState({
899
+ data: null,
900
+ loading: false,
901
+ error: error instanceof ApiError ? error : new ApiError(1006, "Unknown error")
902
+ });
903
+ }
904
+ }
905
+ };
906
+ fetchData();
907
+ return () => {
908
+ cancelled = true;
909
+ };
910
+ }, [client, params.team_code, params.brand_website, params.locale, enabled]);
911
+ return state;
912
+ }
913
+ function useDemoRoom(client, code, locale, options) {
914
+ const [state, setState] = React2.useState({
915
+ data: null,
916
+ loading: true,
917
+ error: null
918
+ });
919
+ const enabled = options?.enabled !== false;
920
+ React2.useEffect(() => {
921
+ if (!enabled || !code) return;
922
+ let cancelled = false;
923
+ const fetchData = async () => {
924
+ setState((prev) => ({ ...prev, loading: true, error: null }));
925
+ try {
926
+ const data = await client.getDemoRoom(code, locale);
927
+ if (!cancelled) {
928
+ setState({ data, loading: false, error: null });
929
+ }
930
+ } catch (error) {
931
+ if (!cancelled) {
932
+ setState({
933
+ data: null,
934
+ loading: false,
935
+ error: error instanceof ApiError ? error : new ApiError(1006, "Unknown error")
936
+ });
937
+ }
938
+ }
939
+ };
940
+ fetchData();
941
+ return () => {
942
+ cancelled = true;
943
+ };
944
+ }, [client, code, locale, enabled]);
945
+ return state;
946
+ }
947
+ function useTimeslots(client, code, params, options) {
948
+ const [state, setState] = React2.useState({
949
+ data: null,
950
+ loading: true,
951
+ error: null
952
+ });
953
+ const enabled = options?.enabled !== false;
954
+ React2.useEffect(() => {
955
+ if (!enabled || !code || !params.start_date || !params.end_date) return;
956
+ let cancelled = false;
957
+ const fetchData = async () => {
958
+ setState((prev) => ({ ...prev, loading: true, error: null }));
959
+ try {
960
+ const data = await client.getTimeslots(code, params);
961
+ if (!cancelled) {
962
+ setState({ data, loading: false, error: null });
963
+ }
964
+ } catch (error) {
965
+ if (!cancelled) {
966
+ setState({
967
+ data: null,
968
+ loading: false,
969
+ error: error instanceof ApiError ? error : new ApiError(1006, "Unknown error")
970
+ });
971
+ }
972
+ }
973
+ };
974
+ fetchData();
975
+ return () => {
976
+ cancelled = true;
977
+ };
978
+ }, [client, code, params.start_date, params.end_date, params.timezone, enabled]);
979
+ return state;
980
+ }
981
+ function useQuestionnaire(client, code, questionnaire_id, locale, options) {
982
+ const [state, setState] = React2.useState({
983
+ data: null,
984
+ loading: true,
985
+ error: null
986
+ });
987
+ const enabled = options?.enabled !== false;
988
+ React2.useEffect(() => {
989
+ if (!enabled || !code || !questionnaire_id) return;
990
+ let cancelled = false;
991
+ const fetchData = async () => {
992
+ setState((prev) => ({ ...prev, loading: true, error: null }));
993
+ try {
994
+ const data = await client.getQuestionnaire(code, questionnaire_id, locale);
995
+ if (!cancelled) {
996
+ setState({ data, loading: false, error: null });
997
+ }
998
+ } catch (error) {
999
+ if (!cancelled) {
1000
+ setState({
1001
+ data: null,
1002
+ loading: false,
1003
+ error: error instanceof ApiError ? error : new ApiError(1006, "Unknown error")
1004
+ });
1005
+ }
1006
+ }
1007
+ };
1008
+ fetchData();
1009
+ return () => {
1010
+ cancelled = true;
1011
+ };
1012
+ }, [client, code, questionnaire_id, locale, enabled]);
1013
+ return state;
1014
+ }
1015
+ function useCreateBooking(client) {
1016
+ const [state, setState] = React2.useState({
1017
+ data: null,
1018
+ loading: false,
1019
+ error: null
1020
+ });
1021
+ const createBooking = React2.useCallback(
1022
+ async (data) => {
1023
+ setState({ data: null, loading: true, error: null });
1024
+ try {
1025
+ const result = await client.createBooking(data);
1026
+ setState({ data: result, loading: false, error: null });
1027
+ return result;
1028
+ } catch (error) {
1029
+ const apiError = error instanceof ApiError ? error : new ApiError(1006, "Unknown error");
1030
+ setState({ data: null, loading: false, error: apiError });
1031
+ throw apiError;
1032
+ }
1033
+ },
1034
+ [client]
1035
+ );
1036
+ return {
1037
+ ...state,
1038
+ createBooking
1039
+ };
1040
+ }
1041
+ var AntdMobileIsolated = ({
1042
+ children,
1043
+ className,
1044
+ style
1045
+ }) => {
1046
+ const containerRef = React2.useRef(null);
1047
+ React2.useEffect(() => {
1048
+ if (!containerRef.current) return;
1049
+ const container = containerRef.current;
1050
+ const originalStyles = {
1051
+ fontSize: container.style.fontSize,
1052
+ fontFamily: container.style.fontFamily,
1053
+ lineHeight: container.style.lineHeight,
1054
+ color: container.style.color
1055
+ };
1056
+ container.style.fontSize = "14px";
1057
+ container.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
1058
+ container.style.lineHeight = "1.5";
1059
+ container.style.color = "#333";
1060
+ return () => {
1061
+ container.style.fontSize = originalStyles.fontSize;
1062
+ container.style.fontFamily = originalStyles.fontFamily;
1063
+ container.style.lineHeight = originalStyles.lineHeight;
1064
+ container.style.color = originalStyles.color;
1065
+ };
1066
+ }, []);
1067
+ return /* @__PURE__ */ jsxRuntime.jsx(
1068
+ "div",
1069
+ {
1070
+ ref: containerRef,
1071
+ className: cn("antd-mobile-isolated", className),
1072
+ style: {
1073
+ // 使用 all: revert-layer 来隔离样式
1074
+ isolation: "isolate",
1075
+ contain: "layout style",
1076
+ ...style
1077
+ },
1078
+ children
1079
+ }
1080
+ );
1081
+ };
1082
+ AntdMobileIsolated.displayName = "AntdMobileIsolated";
1083
+
1084
+ // src/components/DemoRoom/utils/addressParser.ts
1085
+ function parseAddress(address) {
1086
+ const parts = address.split(",").map((part) => part.trim());
1087
+ let country = "United States";
1088
+ let state = "";
1089
+ let city = "";
1090
+ if (parts.length >= 3) {
1091
+ city = parts[1] || "";
1092
+ state = parts[2]?.split(" ")[0] || "";
1093
+ country = parts[3] || country;
1094
+ } else if (parts.length === 2) {
1095
+ city = parts[0] || "";
1096
+ state = parts[1]?.split(" ")[0] || "";
1097
+ } else if (parts.length === 1) {
1098
+ city = parts[0] || "";
1099
+ }
1100
+ return {
1101
+ country: country.trim(),
1102
+ state: state.trim(),
1103
+ city: city.trim()
1104
+ };
1105
+ }
1106
+ function groupByAlphabet(items) {
1107
+ const groups = /* @__PURE__ */ new Map();
1108
+ items.forEach((item) => {
1109
+ const firstChar = item.name.charAt(0).toUpperCase();
1110
+ const key = /[A-Z]/.test(firstChar) ? firstChar : "#";
1111
+ if (!groups.has(key)) {
1112
+ groups.set(key, []);
1113
+ }
1114
+ groups.get(key).push(item);
1115
+ });
1116
+ return Array.from(groups.entries()).sort(([a], [b]) => {
1117
+ if (a === "#") return 1;
1118
+ if (b === "#") return -1;
1119
+ return a.localeCompare(b);
1120
+ }).map(([title, items2]) => ({
1121
+ title,
1122
+ items: items2.sort((a, b) => a.name.localeCompare(b.name))
1123
+ }));
1124
+ }
1125
+
1126
+ // src/components/DemoRoom/components/RoomsList.module.css
1127
+ var RoomsList_default = {};
1128
+ var LocationFilter = ({
1129
+ locations,
1130
+ onSelect,
1131
+ visible = false,
1132
+ onClose
1133
+ }) => {
1134
+ const [currentLevel, setCurrentLevel] = React2.useState("country");
1135
+ const [selectedCountry, setSelectedCountry] = React2.useState();
1136
+ const [selectedState, setSelectedState] = React2.useState();
1137
+ const [searchQuery, setSearchQuery] = React2.useState("");
1138
+ const locationData = React2.useMemo(() => {
1139
+ const countries = /* @__PURE__ */ new Map();
1140
+ const states = /* @__PURE__ */ new Map();
1141
+ const cities = /* @__PURE__ */ new Map();
1142
+ locations.forEach((location) => {
1143
+ const { country, state, city } = parseAddress(location.address);
1144
+ if (country) {
1145
+ const existing = countries.get(country);
1146
+ countries.set(country, {
1147
+ name: country,
1148
+ code: country,
1149
+ count: (existing?.count || 0) + 1
1150
+ });
1151
+ }
1152
+ if (state) {
1153
+ const stateKey = `${country}/${state}`;
1154
+ const existing = states.get(stateKey);
1155
+ states.set(stateKey, {
1156
+ name: state,
1157
+ code: stateKey,
1158
+ count: (existing?.count || 0) + 1,
1159
+ parentCode: country
1160
+ });
1161
+ }
1162
+ if (city) {
1163
+ const cityKey = `${country}/${state}/${city}`;
1164
+ const existing = cities.get(cityKey);
1165
+ cities.set(cityKey, {
1166
+ name: city,
1167
+ code: cityKey,
1168
+ count: (existing?.count || 0) + 1,
1169
+ parentCode: `${country}/${state}`
1170
+ });
1171
+ }
1172
+ });
1173
+ return {
1174
+ countries: Array.from(countries.values()),
1175
+ states: Array.from(states.values()),
1176
+ cities: Array.from(cities.values())
1177
+ };
1178
+ }, [locations]);
1179
+ const filteredItems = React2.useMemo(() => {
1180
+ let items = [];
1181
+ switch (currentLevel) {
1182
+ case "country":
1183
+ items = locationData.countries;
1184
+ break;
1185
+ case "state":
1186
+ items = selectedCountry ? locationData.states.filter(
1187
+ (s) => s.parentCode === selectedCountry
1188
+ ) : [];
1189
+ break;
1190
+ case "city":
1191
+ items = selectedState ? locationData.cities.filter((c) => c.parentCode === selectedState) : [];
1192
+ break;
1193
+ }
1194
+ if (searchQuery) {
1195
+ items = items.filter(
1196
+ (item) => item.name.toLowerCase().includes(searchQuery.toLowerCase())
1197
+ );
1198
+ }
1199
+ return items;
1200
+ }, [currentLevel, selectedCountry, selectedState, locationData, searchQuery]);
1201
+ const groupedItems = React2.useMemo(
1202
+ () => groupByAlphabet(filteredItems),
1203
+ [filteredItems]
1204
+ );
1205
+ const handleItemClick = (item) => {
1206
+ if (currentLevel === "country") {
1207
+ setSelectedCountry(item.code);
1208
+ setCurrentLevel("state");
1209
+ } else if (currentLevel === "state") {
1210
+ setSelectedState(item.code);
1211
+ setCurrentLevel("city");
1212
+ } else if (currentLevel === "city") {
1213
+ const parts = item.code.split("/");
1214
+ onSelect?.({
1215
+ level: "city",
1216
+ country: parts[0],
1217
+ state: parts[1],
1218
+ city: parts[2]
1219
+ });
1220
+ onClose?.();
1221
+ }
1222
+ };
1223
+ const handleTabClick = (level) => {
1224
+ setCurrentLevel(level);
1225
+ if (level === "country") {
1226
+ setSelectedCountry(void 0);
1227
+ setSelectedState(void 0);
1228
+ } else if (level === "state") {
1229
+ setSelectedState(void 0);
1230
+ }
1231
+ };
1232
+ if (!visible) return null;
1233
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1234
+ "div",
1235
+ {
1236
+ style: { height: "794px" },
1237
+ className: cn(
1238
+ "w-full rounded-[12px] absolute z-10 top-0 left-0 bg-white border border-[#E4E5E6]",
1239
+ RoomsList_default.antdMobileScope
1240
+ ),
1241
+ children: [
1242
+ /* @__PURE__ */ jsxRuntime.jsxs(
1243
+ "div",
1244
+ {
1245
+ style: { background: "#F8F8F8" },
1246
+ className: "rounded-[12px] rounded-b-none h-[72px] font-bold text-[14px] flex flex-col",
1247
+ children: [
1248
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-[20px] pt-[12px] pb-[8px]", children: [
1249
+ /* @__PURE__ */ jsxRuntime.jsx(
1250
+ "input",
1251
+ {
1252
+ type: "text",
1253
+ placeholder: "Please enter the search city",
1254
+ value: searchQuery,
1255
+ onChange: (e) => setSearchQuery(e.target.value),
1256
+ className: "flex-1 h-[32px] px-[12px] rounded-[6px] border border-[#E4E5E6] text-[14px] outline-none focus:border-[#2E8B57]"
1257
+ }
1258
+ ),
1259
+ /* @__PURE__ */ jsxRuntime.jsx(
1260
+ "button",
1261
+ {
1262
+ onClick: onClose,
1263
+ className: "ml-[12px] w-[24px] h-[24px] flex items-center justify-center",
1264
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1265
+ "svg",
1266
+ {
1267
+ xmlns: "http://www.w3.org/2000/svg",
1268
+ width: "24",
1269
+ height: "24",
1270
+ viewBox: "0 0 24 24",
1271
+ fill: "none",
1272
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1273
+ "path",
1274
+ {
1275
+ d: "M6.4 19L5 17.6L10.6 12L5 6.4L6.4 5L12 10.6L17.6 5L19 6.4L13.4 12L19 17.6L17.6 19L12 13.4L6.4 19Z",
1276
+ fill: "#1D1D1F"
1277
+ }
1278
+ )
1279
+ }
1280
+ )
1281
+ }
1282
+ )
1283
+ ] }),
1284
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center px-[20px] gap-[16px] pb-[8px]", children: [
1285
+ /* @__PURE__ */ jsxRuntime.jsx(
1286
+ "button",
1287
+ {
1288
+ onClick: () => handleTabClick("country"),
1289
+ className: cn(
1290
+ "pb-[4px] transition-colors",
1291
+ currentLevel === "country" ? "text-[#1D1D1F] border-b-2 border-[#2E8B57]" : "text-[#767880]"
1292
+ ),
1293
+ children: "Country"
1294
+ }
1295
+ ),
1296
+ /* @__PURE__ */ jsxRuntime.jsx(
1297
+ "button",
1298
+ {
1299
+ onClick: () => handleTabClick("state"),
1300
+ disabled: !selectedCountry,
1301
+ className: cn(
1302
+ "pb-[4px] transition-colors",
1303
+ currentLevel === "state" ? "text-[#1D1D1F] border-b-2 border-[#2E8B57]" : "text-[#767880]",
1304
+ !selectedCountry && "opacity-50 cursor-not-allowed"
1305
+ ),
1306
+ children: "State"
1307
+ }
1308
+ ),
1309
+ /* @__PURE__ */ jsxRuntime.jsx(
1310
+ "button",
1311
+ {
1312
+ onClick: () => handleTabClick("city"),
1313
+ disabled: !selectedState,
1314
+ className: cn(
1315
+ "pb-[4px] transition-colors",
1316
+ currentLevel === "city" ? "text-[#1D1D1F] border-b-2 border-[#2E8B57]" : "text-[#767880]",
1317
+ !selectedState && "opacity-50 cursor-not-allowed"
1318
+ ),
1319
+ children: "City"
1320
+ }
1321
+ )
1322
+ ] })
1323
+ ]
1324
+ }
1325
+ ),
1326
+ /* @__PURE__ */ jsxRuntime.jsx(AntdMobileIsolated, { style: { height: "calc(100% - 72px)" }, children: /* @__PURE__ */ jsxRuntime.jsx(IndexBar__default.default, { style: { height: "100%" }, children: groupedItems.map((group) => {
1327
+ const { title, items } = group;
1328
+ return /* @__PURE__ */ jsxRuntime.jsx(IndexBar__default.default.Panel, { index: title, title, children: /* @__PURE__ */ jsxRuntime.jsx(List__default.default, { children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1329
+ List__default.default.Item,
1330
+ {
1331
+ clickable: true,
1332
+ onClick: () => handleItemClick(item),
1333
+ extra: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[8px]", children: [
1334
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[#767880] text-[14px]", children: item.count }),
1335
+ /* @__PURE__ */ jsxRuntime.jsx(
1336
+ "svg",
1337
+ {
1338
+ xmlns: "http://www.w3.org/2000/svg",
1339
+ width: "16",
1340
+ height: "16",
1341
+ viewBox: "0 0 16 16",
1342
+ fill: "none",
1343
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1344
+ "path",
1345
+ {
1346
+ d: "M6.4 12L5.6 11.2L9.06667 7.73333L5.6 4.26667L6.4 3.46667L10.6667 7.73333L6.4 12Z",
1347
+ fill: "#767880"
1348
+ }
1349
+ )
1350
+ }
1351
+ )
1352
+ ] }),
1353
+ children: item.name
1354
+ },
1355
+ item.code
1356
+ )) }) }, title);
1357
+ }) }) })
1358
+ ]
1359
+ }
1360
+ );
1361
+ };
1362
+ LocationFilter.displayName = "LocationFilter";
1363
+ var defaultStudioLocations = [
1364
+ {
1365
+ id: "1",
1366
+ name: "Design District Demo Room",
1367
+ address: "111 8th St",
1368
+ city: "San Francisco",
1369
+ state: "CA",
1370
+ zipCode: "94108",
1371
+ country: "United States",
1372
+ lat: 37.7749,
1373
+ lng: -122.4194,
1374
+ availableTime: "Oct 28, 2:00 PM",
1375
+ euifyMakeModel: "euifyMake E1, euifyMake M5"
1376
+ },
1377
+ {
1378
+ id: "2",
1379
+ name: "Brooklyn Creative Studio",
1380
+ address: "456 Broadway",
1381
+ city: "Brooklyn",
1382
+ state: "NY",
1383
+ zipCode: "11211",
1384
+ country: "United States",
1385
+ lat: 40.7128,
1386
+ lng: -74.006,
1387
+ availableTime: "Oct 29, 3:00 PM",
1388
+ euifyMakeModel: "euifyMake E1, euifyMake M5"
1389
+ },
1390
+ {
1391
+ id: "3",
1392
+ name: "Austin Innovation Hub",
1393
+ address: "789 Tech Blvd",
1394
+ city: "Austin",
1395
+ state: "TX",
1396
+ zipCode: "78701",
1397
+ country: "United States",
1398
+ lat: 30.2672,
1399
+ lng: -97.7431,
1400
+ availableTime: "Oct 30, 1:00 PM",
1401
+ euifyMakeModel: "euifyMake M5"
1402
+ },
1403
+ {
1404
+ id: "4",
1405
+ name: "Seattle Maker Space",
1406
+ address: "321 Pine St",
1407
+ city: "Seattle",
1408
+ state: "WA",
1409
+ zipCode: "98101",
1410
+ country: "United States",
1411
+ lat: 47.6062,
1412
+ lng: -122.3321,
1413
+ availableTime: "Oct 31, 11:00 AM",
1414
+ euifyMakeModel: "euifyMake E1"
1415
+ },
1416
+ {
1417
+ id: "5",
1418
+ name: "Chicago Design Center",
1419
+ address: "654 Michigan Ave",
1420
+ city: "Chicago",
1421
+ state: "IL",
1422
+ zipCode: "60611",
1423
+ country: "United States",
1424
+ lat: 41.8781,
1425
+ lng: -87.6298,
1426
+ availableTime: "Nov 1, 2:30 PM",
1427
+ euifyMakeModel: "euifyMake E1, euifyMake M5"
1428
+ },
1429
+ {
1430
+ id: "6",
1431
+ name: "Miami Beach Studio",
1432
+ address: "987 Ocean Drive",
1433
+ city: "Miami Beach",
1434
+ state: "FL",
1435
+ zipCode: "33139",
1436
+ country: "United States",
1437
+ lat: 25.7617,
1438
+ lng: -80.1918,
1439
+ availableTime: "Nov 2, 10:00 AM",
1440
+ euifyMakeModel: "euifyMake M5"
1441
+ },
1442
+ {
1443
+ id: "7",
1444
+ name: "Denver Mountain Studio",
1445
+ address: "147 16th St",
1446
+ city: "Denver",
1447
+ state: "CO",
1448
+ zipCode: "80202",
1449
+ country: "United States",
1450
+ lat: 39.7392,
1451
+ lng: -104.9903,
1452
+ availableTime: "Nov 3, 4:00 PM",
1453
+ euifyMakeModel: "euifyMake E1"
1454
+ },
1455
+ {
1456
+ id: "8",
1457
+ name: "Los Angeles Creative Lab",
1458
+ address: "258 Main St",
1459
+ city: "Los Angeles",
1460
+ state: "CA",
1461
+ zipCode: "90012",
1462
+ country: "United States",
1463
+ lat: 34.0522,
1464
+ lng: -118.2437,
1465
+ availableTime: "Nov 4, 1:00 PM",
1466
+ euifyMakeModel: "euifyMake E1, euifyMake M5"
1467
+ }
1468
+ ];
1469
+ var RoomsList = ({
1470
+ googleMapsApiKey,
1471
+ className,
1472
+ apiClient,
1473
+ teamCode,
1474
+ brandWebsite,
1475
+ onSchedule,
1476
+ ...props
1477
+ }) => {
1478
+ const [showLocationFilter, setShowLocationFilter] = React2.useState(false);
1479
+ const [selectedLocation, setSelectedLocation] = React2.useState();
1480
+ const {
1481
+ data: demoRooms,
1482
+ loading,
1483
+ error
1484
+ } = useDemoRooms(apiClient, {
1485
+ team_code: teamCode,
1486
+ brand_website: brandWebsite
1487
+ });
1488
+ console.log(demoRooms);
1489
+ const studioLocations = React2.useMemo(() => {
1490
+ if (!demoRooms) return defaultStudioLocations;
1491
+ return demoRooms.map((room) => {
1492
+ const timeslots = [
1493
+ {
1494
+ id: 130,
1495
+ start_time: "2026-01-13T09:00:00-05:00",
1496
+ end_time: "2026-01-13T10:00:00-05:00",
1497
+ capacity: 5,
1498
+ booked_count: 2,
1499
+ status: "available"
1500
+ },
1501
+ {
1502
+ id: 131,
1503
+ start_time: "2026-01-13T14:00:00-05:00",
1504
+ end_time: "2026-01-13T15:00:00-05:00",
1505
+ capacity: 5,
1506
+ booked_count: 5,
1507
+ status: "full"
1508
+ }
1509
+ ];
1510
+ const nextAvailableTimeslot = (room.timeslots?.length ? room.timeslots : timeslots)?.find((slot) => slot.status === "available");
1511
+ const { country, state, city } = parseAddress(room.address);
1512
+ return {
1513
+ id: room.code,
1514
+ name: room.name,
1515
+ address: room.address,
1516
+ city,
1517
+ state,
1518
+ zipCode: "",
1519
+ country,
1520
+ lat: Number(room.latitude) || 34.0522,
1521
+ lng: Number(room.longitude) || -118.2437,
1522
+ availableTime: nextAvailableTimeslot ? `${nextAvailableTimeslot.start_time}` : "No available time",
1523
+ euifyMakeModel: room?.description
1524
+ };
1525
+ });
1526
+ }, [demoRooms]);
1527
+ const filteredStudioLocations = React2.useMemo(() => {
1528
+ if (!selectedLocation) return studioLocations;
1529
+ return studioLocations.filter((location) => {
1530
+ const { country, state, city } = parseAddress(location.address);
1531
+ if (selectedLocation.city) {
1532
+ return country === selectedLocation.country && state === selectedLocation.state && city === selectedLocation.city;
1533
+ }
1534
+ if (selectedLocation.state) {
1535
+ return country === selectedLocation.country && state === selectedLocation.state;
1536
+ }
1537
+ if (selectedLocation.country) {
1538
+ return country === selectedLocation.country;
1539
+ }
1540
+ return true;
1541
+ });
1542
+ }, [studioLocations, selectedLocation]);
1543
+ const getSelectedLocationName = () => {
1544
+ if (!selectedLocation) return "All Locations";
1545
+ if (selectedLocation.city) return selectedLocation.city;
1546
+ if (selectedLocation.state) return selectedLocation.state;
1547
+ if (selectedLocation.country) return selectedLocation.country;
1548
+ return "All Locations";
1549
+ };
1550
+ const handleLocationSelect = (selection) => {
1551
+ setSelectedLocation(selection);
1552
+ setShowLocationFilter(false);
1553
+ };
1554
+ const handleClearFilter = () => {
1555
+ setSelectedLocation(void 0);
1556
+ };
1557
+ console.log(filteredStudioLocations);
1558
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, ...props, children: [
1559
+ /* @__PURE__ */ jsxRuntime.jsx(Title, { title: "Find a Studio Near You" }),
1560
+ loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[794px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-medium", children: "Loading demo rooms..." }) }) }),
1561
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[794px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-red-600", children: [
1562
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-medium", children: "Failed to load demo rooms" }),
1563
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm mt-2", children: error.message })
1564
+ ] }) }),
1565
+ !loading && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[794px] overflow-auto gap-4", children: [
1566
+ /* @__PURE__ */ jsxRuntime.jsxs(
1567
+ "div",
1568
+ {
1569
+ className: "flex-none relative w-[420px]",
1570
+ style: { height: "794px" },
1571
+ children: [
1572
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-[12px] items-center h-[72px] mb-4 font-bold text-[16px] gap-10 flex bg-white border border-[#E4E5E6] px-[20px] py-[16px]", children: [
1573
+ /* @__PURE__ */ jsxRuntime.jsxs(
1574
+ "button",
1575
+ {
1576
+ className: "flex cursor-pointer items-center hover:text-[#2E8B57] transition-colors",
1577
+ onClick: () => setShowLocationFilter(true),
1578
+ children: [
1579
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1", children: getSelectedLocationName() }),
1580
+ /* @__PURE__ */ jsxRuntime.jsx(
1581
+ "svg",
1582
+ {
1583
+ xmlns: "http://www.w3.org/2000/svg",
1584
+ width: "24",
1585
+ height: "24",
1586
+ viewBox: "0 0 24 24",
1587
+ fill: "none",
1588
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1589
+ "path",
1590
+ {
1591
+ d: "M16.7661 9.23364C17.078 9.5455 17.0779 10.0516 16.7661 10.3635L12.5991 14.5305C12.2874 14.842 11.782 14.8418 11.4702 14.5305L7.30322 10.3635C6.99135 10.0516 6.99135 9.54552 7.30322 9.23364C7.615 8.9221 8.1203 8.92219 8.43213 9.23364L12.0347 12.8362L15.6362 9.23364C15.9481 8.92183 16.4543 8.92181 16.7661 9.23364Z",
1592
+ fill: "currentColor"
1593
+ }
1594
+ )
1595
+ }
1596
+ )
1597
+ ]
1598
+ }
1599
+ ),
1600
+ selectedLocation && /* @__PURE__ */ jsxRuntime.jsx(
1601
+ "button",
1602
+ {
1603
+ onClick: handleClearFilter,
1604
+ className: "ml-auto text-[14px] text-[#2E8B57] hover:underline",
1605
+ children: "Clear"
1606
+ }
1607
+ ),
1608
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex text-[#767880] cursor-not-allowed", children: [
1609
+ "eufymake E1",
1610
+ /* @__PURE__ */ jsxRuntime.jsx(
1611
+ "svg",
1612
+ {
1613
+ xmlns: "http://www.w3.org/2000/svg",
1614
+ width: "24",
1615
+ height: "24",
1616
+ viewBox: "0 0 24 24",
1617
+ fill: "none",
1618
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1619
+ "path",
1620
+ {
1621
+ d: "M16.7661 9.23364C17.078 9.5455 17.0779 10.0516 16.7661 10.3635L12.5991 14.5305C12.2874 14.842 11.782 14.8418 11.4702 14.5305L7.30322 10.3635C6.99135 10.0516 6.99135 9.54552 7.30322 9.23364C7.615 8.9221 8.1203 8.92219 8.43213 9.23364L12.0347 12.8362L15.6362 9.23364C15.9481 8.92183 16.4543 8.92181 16.7661 9.23364Z",
1622
+ fill: "currentColor"
1623
+ }
1624
+ )
1625
+ }
1626
+ )
1627
+ ] })
1628
+ ] }),
1629
+ /* @__PURE__ */ jsxRuntime.jsx(
1630
+ "div",
1631
+ {
1632
+ style: { maxHeight: "706px", overflow: "auto" },
1633
+ className: "rounded-[12px] bg-white border border-[#E4E5E6]",
1634
+ children: filteredStudioLocations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-[200px] text-[#767880]", children: "No studios found in this location" }) : filteredStudioLocations.map((item) => {
1635
+ return /* @__PURE__ */ jsxRuntime.jsx(
1636
+ StudioCard,
1637
+ {
1638
+ code: item.id,
1639
+ name: item?.name,
1640
+ availableTime: item?.availableTime || "",
1641
+ address: item?.address,
1642
+ city: item?.city,
1643
+ state: item?.state,
1644
+ zipCode: item?.zipCode,
1645
+ euifyMakeModel: item?.euifyMakeModel || "",
1646
+ onSchedule
1647
+ },
1648
+ item.id
1649
+ );
1650
+ })
1651
+ }
1652
+ ),
1653
+ /* @__PURE__ */ jsxRuntime.jsx(
1654
+ LocationFilter,
1655
+ {
1656
+ locations: studioLocations.map((loc) => ({
1657
+ address: loc.address,
1658
+ id: loc.id
1659
+ })),
1660
+ visible: showLocationFilter,
1661
+ onSelect: handleLocationSelect,
1662
+ onClose: () => setShowLocationFilter(false)
1663
+ }
1664
+ )
1665
+ ]
1666
+ }
1667
+ ),
1668
+ googleMapsApiKey && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1"), children: /* @__PURE__ */ jsxRuntime.jsx(
1669
+ StudioMap,
1670
+ {
1671
+ googleMapsApiKey,
1672
+ locations: filteredStudioLocations,
1673
+ onSchedule: () => {
1674
+ console.log(111);
1675
+ },
1676
+ mapHeight: "794px"
1677
+ }
1678
+ ) })
1679
+ ] })
1680
+ ] });
1681
+ };
1682
+ RoomsList.displayName = "RoomsList";
1683
+
1684
+ // src/api/client.ts
1685
+ var DemoRoomApiClient = class {
1686
+ constructor(config) {
1687
+ this.config = {
1688
+ timeout: 3e4,
1689
+ ...config
1690
+ };
1691
+ }
1692
+ async request(endpoint, options = {}) {
1693
+ const url = `${this.config.baseUrl}${endpoint}`;
1694
+ const headers = {
1695
+ "X-API-Key": this.config.apiKey,
1696
+ "Content-Type": "application/json",
1697
+ ...options.headers
1698
+ };
1699
+ if (this.config.locale) {
1700
+ headers["Accept-Language"] = this.config.locale;
1701
+ }
1702
+ try {
1703
+ const controller = new AbortController();
1704
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
1705
+ const response = await fetch(url, {
1706
+ ...options,
1707
+ headers,
1708
+ signal: controller.signal
1709
+ });
1710
+ clearTimeout(timeoutId);
1711
+ const data = await response.json();
1712
+ if (data.code !== 0 /* SUCCESS */) {
1713
+ throw new ApiError(data.code, data.message, data.request_id);
1714
+ }
1715
+ return data.data;
1716
+ } catch (error) {
1717
+ if (error instanceof ApiError) {
1718
+ throw error;
1719
+ }
1720
+ if (error instanceof Error) {
1721
+ if (error.name === "AbortError") {
1722
+ throw new ApiError(1006 /* INTERNAL_ERROR */, "Request timeout");
1723
+ }
1724
+ throw new ApiError(1006 /* INTERNAL_ERROR */, error.message);
1725
+ }
1726
+ throw new ApiError(1006 /* INTERNAL_ERROR */, "Unknown error");
1727
+ }
1728
+ }
1729
+ /**
1730
+ * 获取门店列表
1731
+ * @param params.team_code 团队编码
1732
+ * @param params.brand_website 品牌站点
1733
+ * @param params.locale 语言偏好(可选)
1734
+ */
1735
+ async getDemoRooms(params) {
1736
+ const searchParams = new URLSearchParams();
1737
+ if (params.team_code) {
1738
+ searchParams.append("team_code", params.team_code);
1739
+ }
1740
+ if (params.brand_website) {
1741
+ searchParams.append("brand_website", params.brand_website);
1742
+ }
1743
+ if (params.locale) {
1744
+ searchParams.append("locale", params.locale);
1745
+ }
1746
+ const response = await this.request(
1747
+ `/api/v1/store/demorooms?${searchParams.toString()}`
1748
+ );
1749
+ return response.demorooms;
1750
+ }
1751
+ /**
1752
+ * 获取门店详情
1753
+ * @param code 门店编码
1754
+ * @param locale 语言偏好(可选)
1755
+ */
1756
+ async getDemoRoom(code, locale) {
1757
+ const searchParams = new URLSearchParams();
1758
+ if (locale) {
1759
+ searchParams.append("locale", locale);
1760
+ }
1761
+ const query = searchParams.toString();
1762
+ return this.request(
1763
+ `/api/v1/store/demorooms/${code}${query ? `?${query}` : ""}`
1764
+ );
1765
+ }
1766
+ /**
1767
+ * 查询门店时段
1768
+ * @param code 门店编码
1769
+ * @param params.start_date 开始日期 (YYYY-MM-DD)
1770
+ * @param params.end_date 结束日期 (YYYY-MM-DD)
1771
+ * @param params.timezone 时区(可选)
1772
+ */
1773
+ async getTimeslots(code, params) {
1774
+ const searchParams = new URLSearchParams({
1775
+ start_date: params.start_date,
1776
+ end_date: params.end_date
1777
+ });
1778
+ if (params.timezone) {
1779
+ searchParams.append("timezone", params.timezone);
1780
+ }
1781
+ return this.request(
1782
+ `/api/v1/store/demorooms/${code}/timeslots?${searchParams.toString()}`
1783
+ );
1784
+ }
1785
+ /**
1786
+ * 查询门店问卷
1787
+ * @param code 门店编码
1788
+ * @param questionnaire_id 问卷ID
1789
+ * @param locale 语言偏好(可选)
1790
+ */
1791
+ async getQuestionnaire(code, questionnaire_id, locale) {
1792
+ const searchParams = new URLSearchParams();
1793
+ if (locale) {
1794
+ searchParams.append("locale", locale);
1795
+ }
1796
+ const query = searchParams.toString();
1797
+ return this.request(
1798
+ `/api/v1/store/demorooms/${code}/questionnaires/${questionnaire_id}${query ? `?${query}` : ""}`
1799
+ );
1800
+ }
1801
+ /**
1802
+ * 提交预约
1803
+ * @param data 预约数据
1804
+ */
1805
+ async createBooking(data) {
1806
+ return this.request("/api/v1/store/bookings", {
1807
+ method: "POST",
1808
+ body: JSON.stringify(data)
1809
+ });
1810
+ }
1811
+ /**
1812
+ * 根据 token 获取预约信息
1813
+ * @param token 预约 token
1814
+ */
1815
+ async getBooking(token) {
1816
+ return this.request(`/api/v1/store/bookings/${token}`);
1817
+ }
1818
+ };
1819
+ function createDemoRoomApi(config) {
1820
+ return new DemoRoomApiClient(config);
1821
+ }
1822
+ var DemoRoom = ({
1823
+ className,
1824
+ layoutClassName = "w-safe11",
1825
+ googleMapsApiKey,
1826
+ apiConfig,
1827
+ teamCode,
1828
+ brandWebsite,
1829
+ onSchedule,
1830
+ ...props
1831
+ }) => {
1832
+ const apiClient = React2.useMemo(
1833
+ () => createDemoRoomApi(apiConfig),
1834
+ [apiConfig]
1835
+ );
1836
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(className), ...props, children: [
1837
+ /* @__PURE__ */ jsxRuntime.jsx(Banner, { className: layoutClassName }),
1838
+ /* @__PURE__ */ jsxRuntime.jsx(
1839
+ BreadCrumbs,
1840
+ {
1841
+ className: layoutClassName,
1842
+ items: [{ label: "Home", link: "/" }, { label: "Demo Room" }]
1843
+ }
1844
+ ),
1845
+ /* @__PURE__ */ jsxRuntime.jsx(HelpNav, {}),
1846
+ /* @__PURE__ */ jsxRuntime.jsx(UpcomingEvents, { className: layoutClassName }),
1847
+ /* @__PURE__ */ jsxRuntime.jsx(
1848
+ RoomsList,
1849
+ {
1850
+ className: layoutClassName,
1851
+ googleMapsApiKey,
1852
+ apiClient,
1853
+ teamCode,
1854
+ brandWebsite,
1855
+ onSchedule
1856
+ }
1857
+ ),
1858
+ /* @__PURE__ */ jsxRuntime.jsx(EasySteps, { className: layoutClassName })
1859
+ ] });
1860
+ };
1861
+ DemoRoom.displayName = "DemoRoom";
1862
+ var defaultDescriptions = [
1863
+ "Norem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis.",
1864
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."
1865
+ ];
1866
+ var defaultImages = [
1867
+ "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638",
1868
+ "https://cdn.shopify.com/s/files/1/0569/5147/2268/files/Component_3_1.png?v=1765274638"
1869
+ ];
1870
+ var DemoRoomDetail = ({
1871
+ apiClient,
1872
+ demoRoomCode,
1873
+ locale,
1874
+ title: titleProp,
1875
+ descriptions: descriptionsProp,
1876
+ devices: devicesProp,
1877
+ address: addressProp,
1878
+ mapsLink,
1879
+ images: imagesProp,
1880
+ className,
1881
+ ...props
1882
+ }) => {
1883
+ const {
1884
+ data: demoRoom,
1885
+ loading,
1886
+ error
1887
+ } = useDemoRoom(
1888
+ apiClient,
1889
+ demoRoomCode || "",
1890
+ locale,
1891
+ { enabled: !!apiClient && !!demoRoomCode }
1892
+ );
1893
+ const title = demoRoom?.name || titleProp || "Design District Demo Room";
1894
+ const descriptions = demoRoom?.description ? [demoRoom.description] : descriptionsProp || defaultDescriptions;
1895
+ const devices = demoRoom?.description || devicesProp || "eufyMake E1, eufyMake M5";
1896
+ const address = demoRoom?.address || addressProp || "1111 8th St, San Francisco, CA United States 94108";
1897
+ const images = demoRoom?.images && demoRoom.images.length > 0 ? demoRoom.images : imagesProp || defaultImages;
1898
+ const googleMapsLink = mapsLink || (demoRoom?.latitude && demoRoom?.longitude ? `https://www.google.com/maps/search/?api=1&query=${demoRoom.latitude},${demoRoom.longitude}` : "#");
1899
+ if (loading && apiClient && demoRoomCode) {
1900
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-8 items-start", children: [
1901
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1902
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-12 bg-gray-200 rounded animate-pulse" }),
1903
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-24 bg-gray-200 rounded animate-pulse" }),
1904
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-gray-200 rounded animate-pulse" })
1905
+ ] }),
1906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[400px] bg-gray-200 rounded-2xl animate-pulse" })
1907
+ ] }) });
1908
+ }
1909
+ if (error && apiClient && demoRoomCode) {
1910
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-red-600 py-8", children: [
1911
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-medium", children: "Failed to load demo room details" }),
1912
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm mt-2", children: error.message })
1913
+ ] }) });
1914
+ }
1915
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-8 items-start", children: [
1916
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1917
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-[40px] font-bold text-gray-900 leading-tight", children: title }),
1918
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: descriptions.map((desc, index) => /* @__PURE__ */ jsxRuntime.jsx(
1919
+ "p",
1920
+ {
1921
+ className: "text-base text-gray-600 leading-relaxed",
1922
+ children: desc
1923
+ },
1924
+ index
1925
+ )) }),
1926
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
1927
+ /* @__PURE__ */ jsxRuntime.jsxs(
1928
+ "svg",
1929
+ {
1930
+ width: "24",
1931
+ height: "24",
1932
+ viewBox: "0 0 24 24",
1933
+ fill: "none",
1934
+ xmlns: "http://www.w3.org/2000/svg",
1935
+ className: "flex-shrink-0 mt-0.5",
1936
+ children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsx(
1938
+ "rect",
1939
+ {
1940
+ x: "3",
1941
+ y: "3",
1942
+ width: "18",
1943
+ height: "18",
1944
+ rx: "2",
1945
+ stroke: "currentColor",
1946
+ strokeWidth: "2"
1947
+ }
1948
+ ),
1949
+ /* @__PURE__ */ jsxRuntime.jsx(
1950
+ "path",
1951
+ {
1952
+ d: "M8 10H16",
1953
+ stroke: "currentColor",
1954
+ strokeWidth: "2",
1955
+ strokeLinecap: "round"
1956
+ }
1957
+ ),
1958
+ /* @__PURE__ */ jsxRuntime.jsx(
1959
+ "path",
1960
+ {
1961
+ d: "M8 14H16",
1962
+ stroke: "currentColor",
1963
+ strokeWidth: "2",
1964
+ strokeLinecap: "round"
1965
+ }
1966
+ )
1967
+ ]
1968
+ }
1969
+ ),
1970
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900", children: devices })
1971
+ ] }),
1972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
1973
+ /* @__PURE__ */ jsxRuntime.jsxs(
1974
+ "svg",
1975
+ {
1976
+ width: "24",
1977
+ height: "24",
1978
+ viewBox: "0 0 24 24",
1979
+ fill: "none",
1980
+ xmlns: "http://www.w3.org/2000/svg",
1981
+ className: "flex-shrink-0 mt-0.5",
1982
+ children: [
1983
+ /* @__PURE__ */ jsxRuntime.jsx(
1984
+ "path",
1985
+ {
1986
+ d: "M12 2C8.13 2 5 5.13 5 9C5 14.25 12 22 12 22C12 22 19 14.25 19 9C19 5.13 15.87 2 12 2Z",
1987
+ stroke: "currentColor",
1988
+ strokeWidth: "2",
1989
+ strokeLinecap: "round",
1990
+ strokeLinejoin: "round"
1991
+ }
1992
+ ),
1993
+ /* @__PURE__ */ jsxRuntime.jsx(
1994
+ "circle",
1995
+ {
1996
+ cx: "12",
1997
+ cy: "9",
1998
+ r: "2.5",
1999
+ stroke: "currentColor",
2000
+ strokeWidth: "2"
2001
+ }
2002
+ )
2003
+ ]
2004
+ }
2005
+ ),
2006
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
2007
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-900", children: address }),
2008
+ /* @__PURE__ */ jsxRuntime.jsxs(
2009
+ "a",
2010
+ {
2011
+ href: googleMapsLink,
2012
+ target: "_blank",
2013
+ rel: "noopener noreferrer",
2014
+ className: "inline-flex items-center gap-1 text-sm text-blue-600 hover:text-blue-700 mt-1 underline",
2015
+ children: [
2016
+ "Open in Google Maps",
2017
+ /* @__PURE__ */ jsxRuntime.jsx(
2018
+ "svg",
2019
+ {
2020
+ width: "12",
2021
+ height: "12",
2022
+ viewBox: "0 0 12 12",
2023
+ fill: "none",
2024
+ xmlns: "http://www.w3.org/2000/svg",
2025
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2026
+ "path",
2027
+ {
2028
+ d: "M3 9L9 3M9 3H3M9 3V9",
2029
+ stroke: "currentColor",
2030
+ strokeWidth: "1.5",
2031
+ strokeLinecap: "round",
2032
+ strokeLinejoin: "round"
2033
+ }
2034
+ )
2035
+ }
2036
+ )
2037
+ ]
2038
+ }
2039
+ )
2040
+ ] })
2041
+ ] })
2042
+ ] }),
2043
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-[400px] rounded-2xl overflow-hidden", children: images.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2044
+ react.Swiper,
2045
+ {
2046
+ modules: [modules.Navigation, modules.Pagination, modules.Autoplay],
2047
+ spaceBetween: 0,
2048
+ slidesPerView: 1,
2049
+ navigation: true,
2050
+ pagination: { clickable: true },
2051
+ autoplay: {
2052
+ delay: 3e3,
2053
+ disableOnInteraction: false
2054
+ },
2055
+ loop: true,
2056
+ className: "h-full rounded-2xl",
2057
+ children: images.map((img, index) => /* @__PURE__ */ jsxRuntime.jsx(react.SwiperSlide, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(
2058
+ "img",
2059
+ {
2060
+ src: img,
2061
+ alt: `Demo room view ${index + 1}`,
2062
+ className: "w-full h-full object-cover"
2063
+ }
2064
+ ) }) }, index))
2065
+ }
2066
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full bg-gradient-to-br from-gray-100 to-gray-200 flex items-center justify-center rounded-2xl", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
2067
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 mx-auto mb-3 rounded-full bg-white flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
2068
+ "svg",
2069
+ {
2070
+ width: "32",
2071
+ height: "32",
2072
+ viewBox: "0 0 32 32",
2073
+ fill: "none",
2074
+ xmlns: "http://www.w3.org/2000/svg",
2075
+ children: [
2076
+ /* @__PURE__ */ jsxRuntime.jsx(
2077
+ "rect",
2078
+ {
2079
+ x: "4",
2080
+ y: "8",
2081
+ width: "24",
2082
+ height: "16",
2083
+ rx: "2",
2084
+ stroke: "currentColor",
2085
+ strokeWidth: "2"
2086
+ }
2087
+ ),
2088
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "14", r: "2", fill: "currentColor" }),
2089
+ /* @__PURE__ */ jsxRuntime.jsx(
2090
+ "path",
2091
+ {
2092
+ d: "M28 20L22 14L16 20",
2093
+ stroke: "currentColor",
2094
+ strokeWidth: "2",
2095
+ strokeLinecap: "round",
2096
+ strokeLinejoin: "round"
2097
+ }
2098
+ )
2099
+ ]
2100
+ }
2101
+ ) }),
2102
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-500 text-sm", children: "Demo Room Images" })
2103
+ ] }) }) })
2104
+ ] }) });
2105
+ };
2106
+ DemoRoomDetail.displayName = "DemoRoomDetail";
2107
+ var QuestionnaireForm = ({
2108
+ questions,
2109
+ onSubmit,
2110
+ loading = false,
2111
+ className
2112
+ }) => {
2113
+ const [responses, setResponses] = React2.useState({});
2114
+ const [errors, setErrors] = React2.useState({});
2115
+ const getQuestionId = (question) => {
2116
+ return question.id || question.key || "";
2117
+ };
2118
+ const handleChange = (questionId, value) => {
2119
+ setResponses((prev) => ({
2120
+ ...prev,
2121
+ [questionId]: value
2122
+ }));
2123
+ if (errors[questionId]) {
2124
+ setErrors((prev) => {
2125
+ const newErrors = { ...prev };
2126
+ delete newErrors[questionId];
2127
+ return newErrors;
2128
+ });
2129
+ }
2130
+ };
2131
+ const handleCheckboxChange = (questionId, optionValue, checked) => {
2132
+ const currentValues = responses[questionId] || [];
2133
+ const newValues = checked ? [...currentValues, optionValue] : currentValues.filter((v) => v !== optionValue);
2134
+ handleChange(questionId, newValues);
2135
+ };
2136
+ const validateForm = () => {
2137
+ const newErrors = {};
2138
+ questions.forEach((question) => {
2139
+ if (question.required) {
2140
+ const questionId = getQuestionId(question);
2141
+ const value = responses[questionId];
2142
+ if (!value || Array.isArray(value) && value.length === 0) {
2143
+ newErrors[questionId] = "This field is required";
2144
+ }
2145
+ }
2146
+ });
2147
+ setErrors(newErrors);
2148
+ return Object.keys(newErrors).length === 0;
2149
+ };
2150
+ const handleSubmit = (e) => {
2151
+ e.preventDefault();
2152
+ if (validateForm()) {
2153
+ onSubmit?.(responses);
2154
+ }
2155
+ };
2156
+ const renderQuestion = (question) => {
2157
+ const questionId = getQuestionId(question);
2158
+ const hasError = !!errors[questionId];
2159
+ switch (question.type) {
2160
+ case "text":
2161
+ case "email":
2162
+ case "tel":
2163
+ return /* @__PURE__ */ jsxRuntime.jsx(
2164
+ "input",
2165
+ {
2166
+ type: question.type,
2167
+ value: responses[questionId] || "",
2168
+ onChange: (e) => handleChange(questionId, e.target.value),
2169
+ placeholder: question.placeholder,
2170
+ className: cn(
2171
+ "w-full px-4 py-3 rounded-lg border text-base",
2172
+ "focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:border-transparent",
2173
+ hasError ? "border-red-500" : "border-[#E4E5E6]"
2174
+ )
2175
+ }
2176
+ );
2177
+ case "textarea":
2178
+ return /* @__PURE__ */ jsxRuntime.jsx(
2179
+ "textarea",
2180
+ {
2181
+ value: responses[questionId] || "",
2182
+ onChange: (e) => handleChange(questionId, e.target.value),
2183
+ placeholder: question.placeholder,
2184
+ rows: 4,
2185
+ className: cn(
2186
+ "w-full px-4 py-3 rounded-lg border text-base resize-none",
2187
+ "focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:border-transparent",
2188
+ hasError ? "border-red-500" : "border-[#E4E5E6]"
2189
+ )
2190
+ }
2191
+ );
2192
+ case "radio":
2193
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: question.options?.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
2194
+ "label",
2195
+ {
2196
+ className: "flex items-center gap-3 cursor-pointer group",
2197
+ children: [
2198
+ /* @__PURE__ */ jsxRuntime.jsx(
2199
+ "input",
2200
+ {
2201
+ type: "radio",
2202
+ name: questionId,
2203
+ value: option.value || option.label,
2204
+ checked: responses[questionId] === (option.value || option.label),
2205
+ onChange: (e) => handleChange(questionId, e.target.value),
2206
+ className: "w-5 h-5 text-[#3ADB67] focus:ring-[#3ADB67] focus:ring-2"
2207
+ }
2208
+ ),
2209
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 group-hover:text-[#3ADB67] transition-colors", children: option.label })
2210
+ ]
2211
+ },
2212
+ option.value || option.label
2213
+ )) });
2214
+ case "checkbox":
2215
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: question.options?.map((option) => {
2216
+ const optionValue = option.value || option.label;
2217
+ const isChecked = (responses[questionId] || []).includes(
2218
+ optionValue
2219
+ );
2220
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2221
+ "label",
2222
+ {
2223
+ className: "flex items-center gap-3 cursor-pointer group",
2224
+ children: [
2225
+ /* @__PURE__ */ jsxRuntime.jsx(
2226
+ "input",
2227
+ {
2228
+ type: "checkbox",
2229
+ checked: isChecked,
2230
+ onChange: (e) => handleCheckboxChange(
2231
+ questionId,
2232
+ optionValue,
2233
+ e.target.checked
2234
+ ),
2235
+ className: "w-5 h-5 text-[#3ADB67] focus:ring-[#3ADB67] focus:ring-2 rounded"
2236
+ }
2237
+ ),
2238
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 group-hover:text-[#3ADB67] transition-colors", children: option.label })
2239
+ ]
2240
+ },
2241
+ optionValue
2242
+ );
2243
+ }) });
2244
+ case "select":
2245
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2246
+ "select",
2247
+ {
2248
+ value: responses[questionId] || "",
2249
+ onChange: (e) => handleChange(questionId, e.target.value),
2250
+ className: cn(
2251
+ "w-full px-4 py-3 rounded-lg border text-base",
2252
+ "focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:border-transparent",
2253
+ "bg-white cursor-pointer",
2254
+ hasError ? "border-red-500" : "border-[#E4E5E6]"
2255
+ ),
2256
+ children: [
2257
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: question.placeholder || "Please select..." }),
2258
+ question.options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
2259
+ "option",
2260
+ {
2261
+ value: option.value || option.label,
2262
+ children: option.label
2263
+ },
2264
+ option.value || option.label
2265
+ ))
2266
+ ]
2267
+ }
2268
+ );
2269
+ default:
2270
+ return null;
2271
+ }
2272
+ };
2273
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: cn("space-y-6", className), children: [
2274
+ questions.map((question) => {
2275
+ const questionId = getQuestionId(question);
2276
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2277
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
2278
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-base font-medium text-gray-900", children: [
2279
+ question.label,
2280
+ question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", children: "*" })
2281
+ ] }),
2282
+ question.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm text-gray-600 mt-1", children: question.description })
2283
+ ] }),
2284
+ renderQuestion(question),
2285
+ question.hint && !errors[questionId] && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: question.hint }),
2286
+ errors[questionId] && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-500", children: errors[questionId] })
2287
+ ] }, questionId);
2288
+ }),
2289
+ /* @__PURE__ */ jsxRuntime.jsx(
2290
+ "button",
2291
+ {
2292
+ type: "submit",
2293
+ disabled: loading,
2294
+ className: cn(
2295
+ "w-full px-6 py-4 rounded-full",
2296
+ "bg-[#3ADB67] text-white font-medium text-base",
2297
+ "hover:bg-[#2FC257] transition-colors",
2298
+ "focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:ring-offset-2",
2299
+ "disabled:opacity-50 disabled:cursor-not-allowed"
2300
+ ),
2301
+ children: loading ? "Submitting..." : "Submit Booking"
2302
+ }
2303
+ )
2304
+ ] });
2305
+ };
2306
+ dayjs__default.default.extend(dayLocaleData__default.default);
2307
+ dayjs__default.default.extend(weekday__default.default);
2308
+ dayjs__default.default.extend(weekOfYear__default.default);
2309
+ var DateTimePicker = ({
2310
+ apiClient,
2311
+ demoRoomCode,
2312
+ timezone,
2313
+ locale,
2314
+ onBookingSuccess
2315
+ }) => {
2316
+ const { token } = antd.theme.useToken();
2317
+ const [selectMonth, setSelectMonth] = React2.useState("");
2318
+ const [selectedDate, setSelectedDate] = React2.useState(dayjs__default.default());
2319
+ const [selectedTimeslotId, setSelectedTimeslotId] = React2.useState(null);
2320
+ const [showQuestionnaire, setShowQuestionnaire] = React2.useState(false);
2321
+ const { createBooking, loading: bookingLoading, error: bookingError } = useCreateBooking(apiClient);
2322
+ const {
2323
+ data: demoRoom
2324
+ } = useDemoRoom(
2325
+ apiClient,
2326
+ demoRoomCode || "",
2327
+ locale,
2328
+ { enabled: !!demoRoomCode }
2329
+ );
2330
+ const {
2331
+ data: questionnaire,
2332
+ loading: questionnaireLoading
2333
+ } = useQuestionnaire(
2334
+ apiClient,
2335
+ demoRoomCode || "",
2336
+ demoRoom?.questionnaire_id,
2337
+ locale,
2338
+ { enabled: !!demoRoomCode && !!demoRoom?.questionnaire_id }
2339
+ );
2340
+ React2.useEffect(() => {
2341
+ if (questionnaire) {
2342
+ setShowQuestionnaire(true);
2343
+ }
2344
+ }, [questionnaire]);
2345
+ const startDate = selectedDate.startOf("month").format("YYYY-MM-DD");
2346
+ const endDate = selectedDate.endOf("month").format("YYYY-MM-DD");
2347
+ const {
2348
+ data: timeslotsData,
2349
+ loading: timeslotsLoading,
2350
+ error: timeslotsError
2351
+ } = useTimeslots(
2352
+ apiClient,
2353
+ demoRoomCode || "",
2354
+ {
2355
+ start_date: startDate,
2356
+ end_date: endDate,
2357
+ timezone
2358
+ },
2359
+ { enabled: !!demoRoomCode }
2360
+ );
2361
+ const dayTimeslots = React2.useMemo(() => {
2362
+ if (!timeslotsData?.timeslots) return [];
2363
+ const selectedDateStr = selectedDate.format("YYYY-MM-DD");
2364
+ return timeslotsData.timeslots.filter((slot) => {
2365
+ const slotDate = dayjs__default.default(slot.start_time).format("YYYY-MM-DD");
2366
+ return slotDate === selectedDateStr;
2367
+ });
2368
+ }, [timeslotsData, selectedDate]);
2369
+ const formatTimeslot = (slot) => {
2370
+ const start = dayjs__default.default(slot.start_time).format("h:mm A");
2371
+ const end = dayjs__default.default(slot.end_time).format("h:mm A");
2372
+ return `${start} - ${end}`;
2373
+ };
2374
+ const onPanelChange = (value, mode) => {
2375
+ console.log(value.format("YYYY-MM-DD"), mode);
2376
+ };
2377
+ const wrapperStyle = {
2378
+ width: 824,
2379
+ background: "#fff",
2380
+ border: `1px solid ${token.colorBorderSecondary}`,
2381
+ borderRadius: token.borderRadiusLG
2382
+ };
2383
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2384
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[48px] py-[64px] font-bold text-center", children: "Schedule Your Visit" }),
2385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
2386
+ /* @__PURE__ */ jsxRuntime.jsx(
2387
+ antd.ConfigProvider,
2388
+ {
2389
+ theme: {
2390
+ token: {
2391
+ colorPrimary: "#3ADB67"
2392
+ },
2393
+ components: {
2394
+ Calendar: {
2395
+ fullBg: "#fff",
2396
+ fullPanelBg: "#fff",
2397
+ itemActiveBg: "#3ADB67"
2398
+ }
2399
+ }
2400
+ },
2401
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2402
+ "div",
2403
+ {
2404
+ style: wrapperStyle,
2405
+ className: "calendar-custom-cell",
2406
+ children: [
2407
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
2408
+ .calendar-custom-cell .ant-picker-cell {
2409
+ padding: 6px !important;
2410
+ }
2411
+ .calendar-custom-cell .ant-picker-cell-inner {
2412
+ width: 100px !important;
2413
+ height: 100px !important;
2414
+ display: flex !important;
2415
+ align-items: center !important;
2416
+ justify-content: center !important;
2417
+ border-radius: 20px !important;
2418
+ border: 1px solid #E4E5E6 !important;
2419
+ }
2420
+ .calendar-custom-cell .ant-picker-cell-selected .ant-picker-cell-inner {
2421
+ background-color: #3ADB67 !important;
2422
+ color: white !important;
2423
+ border-color: #3ADB67 !important;
2424
+ }
2425
+ .calendar-custom-cell .ant-picker-cell-today .ant-picker-cell-inner {
2426
+ border-color: #3ADB67 !important;
2427
+ border-radius: 20px !important;
2428
+ }
2429
+ .calendar-custom-cell .ant-picker-cell-today .ant-picker-cell-inner::before {
2430
+ display: none !important;
2431
+ }
2432
+ .calendar-custom-cell .ant-picker-calendar-date-value {
2433
+ line-height: 100px !important;
2434
+ }
2435
+ .calendar-custom-cell .ant-picker-content {
2436
+ width: 100% !important;
2437
+ }
2438
+ .calendar-custom-cell .ant-picker-content thead tr th {
2439
+ line-height: 48px !important;
2440
+ }
2441
+ ` }),
2442
+ /* @__PURE__ */ jsxRuntime.jsx(
2443
+ antd.Calendar,
2444
+ {
2445
+ fullscreen: false,
2446
+ value: selectedDate,
2447
+ onChange: (date) => setSelectedDate(date),
2448
+ headerRender: ({ value, onChange }) => {
2449
+ const year = value.year();
2450
+ const month = value.month();
2451
+ const yearOptions = Array.from({ length: 20 }, (_, i) => {
2452
+ const label = year - 10 + i;
2453
+ return { label, value: label };
2454
+ });
2455
+ const monthOptions = value.localeData().months().map((label, index) => ({
2456
+ label,
2457
+ value: index
2458
+ }));
2459
+ const monthText = monthOptions?.find((item) => {
2460
+ return item?.value === month;
2461
+ });
2462
+ setSelectMonth(monthText?.label || "");
2463
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [
2464
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
2465
+ /* @__PURE__ */ jsxRuntime.jsx(
2466
+ antd.Select,
2467
+ {
2468
+ value: month,
2469
+ options: monthOptions,
2470
+ onChange: (newMonth) => {
2471
+ const now = value.clone().month(newMonth);
2472
+ onChange(now);
2473
+ },
2474
+ variant: "borderless",
2475
+ className: "text-2xl font-medium",
2476
+ popupMatchSelectWidth: false,
2477
+ style: {
2478
+ fontSize: "24px",
2479
+ fontWeight: 500
2480
+ }
2481
+ }
2482
+ ),
2483
+ /* @__PURE__ */ jsxRuntime.jsx(
2484
+ antd.Select,
2485
+ {
2486
+ value: year,
2487
+ options: yearOptions,
2488
+ onChange: (newYear) => {
2489
+ const now = value.clone().year(newYear);
2490
+ onChange(now);
2491
+ },
2492
+ variant: "borderless",
2493
+ className: "text-2xl font-medium",
2494
+ popupMatchSelectWidth: false,
2495
+ style: {
2496
+ fontSize: "24px",
2497
+ fontWeight: 500
2498
+ }
2499
+ }
2500
+ )
2501
+ ] }),
2502
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2503
+ /* @__PURE__ */ jsxRuntime.jsx(
2504
+ "button",
2505
+ {
2506
+ onClick: () => {
2507
+ const newDate = value.subtract(1, "month");
2508
+ onChange(newDate);
2509
+ },
2510
+ className: "w-10 h-10 flex items-center justify-center hover:bg-gray-100 rounded-lg transition-colors",
2511
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2512
+ "svg",
2513
+ {
2514
+ width: "20",
2515
+ height: "20",
2516
+ viewBox: "0 0 20 20",
2517
+ fill: "none",
2518
+ xmlns: "http://www.w3.org/2000/svg",
2519
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2520
+ "path",
2521
+ {
2522
+ d: "M12 16L6 10L12 4",
2523
+ stroke: "currentColor",
2524
+ strokeWidth: "2",
2525
+ strokeLinecap: "round",
2526
+ strokeLinejoin: "round"
2527
+ }
2528
+ )
2529
+ }
2530
+ )
2531
+ }
2532
+ ),
2533
+ /* @__PURE__ */ jsxRuntime.jsx(
2534
+ "button",
2535
+ {
2536
+ onClick: () => {
2537
+ const newDate = value.add(1, "month");
2538
+ onChange(newDate);
2539
+ },
2540
+ className: "w-10 h-10 flex items-center justify-center hover:bg-gray-100 rounded-lg transition-colors",
2541
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2542
+ "svg",
2543
+ {
2544
+ width: "20",
2545
+ height: "20",
2546
+ viewBox: "0 0 20 20",
2547
+ fill: "none",
2548
+ xmlns: "http://www.w3.org/2000/svg",
2549
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2550
+ "path",
2551
+ {
2552
+ d: "M8 4L14 10L8 16",
2553
+ stroke: "currentColor",
2554
+ strokeWidth: "2",
2555
+ strokeLinecap: "round",
2556
+ strokeLinejoin: "round"
2557
+ }
2558
+ )
2559
+ }
2560
+ )
2561
+ }
2562
+ )
2563
+ ] })
2564
+ ] });
2565
+ },
2566
+ onPanelChange
2567
+ }
2568
+ )
2569
+ ]
2570
+ }
2571
+ )
2572
+ }
2573
+ ),
2574
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white p-[24px] rounded-[12px] flex-1", children: [
2575
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2576
+ "Time Slot",
2577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
2578
+ /* @__PURE__ */ jsxRuntime.jsx(
2579
+ "button",
2580
+ {
2581
+ onClick: () => {
2582
+ const newDate = selectedDate.subtract(1, "day");
2583
+ setSelectedDate(newDate);
2584
+ },
2585
+ className: "w-10 h-10 flex items-center justify-center hover:bg-gray-100 rounded-lg transition-colors",
2586
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2587
+ "svg",
2588
+ {
2589
+ xmlns: "http://www.w3.org/2000/svg",
2590
+ width: "24",
2591
+ height: "24",
2592
+ viewBox: "0 0 24 24",
2593
+ fill: "none",
2594
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2595
+ "path",
2596
+ {
2597
+ d: "M14.2929 5.29289C14.6834 4.90237 15.3164 4.90237 15.707 5.29289C16.0975 5.68342 16.0975 6.31643 15.707 6.70696L10.414 11.9999L15.707 17.2929L15.7753 17.3691C16.0957 17.7618 16.0731 18.3408 15.707 18.707C15.3408 19.0731 14.7618 19.0957 14.3691 18.7753L14.2929 18.707L8.29289 12.707C7.90237 12.3164 7.90237 11.6834 8.29289 11.2929L14.2929 5.29289Z",
2598
+ fill: "#1D1D1F"
2599
+ }
2600
+ )
2601
+ }
2602
+ )
2603
+ }
2604
+ ),
2605
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: selectMonth }),
2606
+ /* @__PURE__ */ jsxRuntime.jsx(
2607
+ "button",
2608
+ {
2609
+ onClick: () => {
2610
+ const newDate = selectedDate.add(1, "day");
2611
+ setSelectedDate(newDate);
2612
+ },
2613
+ className: "w-10 h-10 flex items-center justify-center hover:bg-gray-100 rounded-lg transition-colors",
2614
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2615
+ "svg",
2616
+ {
2617
+ xmlns: "http://www.w3.org/2000/svg",
2618
+ width: "24",
2619
+ height: "24",
2620
+ viewBox: "0 0 24 24",
2621
+ fill: "none",
2622
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2623
+ "path",
2624
+ {
2625
+ d: "M8.29289 5.29289C8.68342 4.90237 9.31643 4.90237 9.70696 5.29289L15.707 11.2929C16.0975 11.6834 16.0975 12.3164 15.707 12.707L9.70696 18.707C9.31643 19.0975 8.68342 19.0975 8.29289 18.707C7.90237 18.3164 7.90237 17.6834 8.29289 17.2929L13.5859 11.9999L8.29289 6.70696C7.90237 6.31643 7.90237 5.68342 8.29289 5.29289Z",
2626
+ fill: "#1D1D1F"
2627
+ }
2628
+ )
2629
+ }
2630
+ )
2631
+ }
2632
+ )
2633
+ ] })
2634
+ ] }),
2635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 mt-[40px] gap-4", children: timeslotsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2 text-center text-[#767880] py-8", children: "Loading time slots..." }) : timeslotsError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2 text-center text-red-600 py-8", children: "Failed to load time slots" }) : dayTimeslots.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-2 text-center text-[#767880] py-8", children: "No available time slots for this date" }) : dayTimeslots.map((slot) => {
2636
+ const isAvailable = slot.status === "available";
2637
+ const isFull = slot.status === "full";
2638
+ const isSelected = selectedTimeslotId === slot.id;
2639
+ return /* @__PURE__ */ jsxRuntime.jsx(
2640
+ "button",
2641
+ {
2642
+ disabled: !isAvailable,
2643
+ onClick: () => {
2644
+ if (isAvailable) {
2645
+ setSelectedTimeslotId(slot.id);
2646
+ }
2647
+ },
2648
+ className: `
2649
+ rounded-[20px] w-full flex items-center justify-center gap-4 h-[76px]
2650
+ border text-center transition-colors
2651
+ ${isSelected ? "border-[#3ADB67] bg-[#3ADB67] text-white cursor-pointer" : isAvailable ? "border-[#E4E5E6] hover:border-[#3ADB67] hover:bg-[#3ADB67] hover:text-white cursor-pointer" : "border-[#E4E5E6] bg-[#F5F5F5] text-[#BDBDBD] cursor-not-allowed"}
2652
+ `,
2653
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
2654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: formatTimeslot(slot) }),
2655
+ isFull && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-[#BDBDBD] mt-1", children: "Full" }),
2656
+ isAvailable && !isSelected && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-[#767880] mt-1", children: [
2657
+ slot.capacity - slot.booked_count,
2658
+ " spots left"
2659
+ ] }),
2660
+ isAvailable && isSelected && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-white mt-1", children: [
2661
+ slot.capacity - slot.booked_count,
2662
+ " spots left"
2663
+ ] })
2664
+ ] })
2665
+ },
2666
+ slot.id
2667
+ );
2668
+ }) })
2669
+ ] })
2670
+ ] }),
2671
+ showQuestionnaire && questionnaire && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-12", children: [
2672
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[48px] font-bold text-center mb-8", children: "Fill out Form" }),
2673
+ questionnaireLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-[#767880] py-8", children: "Loading questionnaire..." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white rounded-[12px] border border-[#E4E5E6] p-8", children: /* @__PURE__ */ jsxRuntime.jsx(
2674
+ QuestionnaireForm,
2675
+ {
2676
+ questions: questionnaire.questions,
2677
+ loading: bookingLoading,
2678
+ onSubmit: async (responses) => {
2679
+ try {
2680
+ const customerName = responses.name || responses.customer_name || "";
2681
+ const customerEmail = responses.email || responses.customer_email || "";
2682
+ const customerPhone = responses.phone || responses.customer_phone_number || "";
2683
+ const customerPhoneCode = responses.phone_code || responses.customer_phone_code || "+1";
2684
+ const result = await createBooking({
2685
+ demoroom_code: demoRoomCode,
2686
+ timeslot_id: selectedTimeslotId,
2687
+ questionnaire_id: questionnaire.id,
2688
+ questionnaire_response: responses,
2689
+ customer_name: customerName,
2690
+ customer_email: customerEmail,
2691
+ customer_phone_code: customerPhoneCode,
2692
+ customer_phone_number: customerPhone
2693
+ });
2694
+ if (result && onBookingSuccess) {
2695
+ onBookingSuccess(result?.cancel_token);
2696
+ }
2697
+ } catch (error) {
2698
+ console.error("Booking creation failed:", error);
2699
+ }
2700
+ }
2701
+ }
2702
+ ) })
2703
+ ] }),
2704
+ bookingError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8 p-4 bg-red-50 border border-red-200 rounded-lg text-red-600 max-w-2xl mx-auto", children: [
2705
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "Booking failed" }),
2706
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm mt-1", children: bookingError.message })
2707
+ ] })
2708
+ ] });
2709
+ };
2710
+ var DateTimePicker_default = DateTimePicker;
2711
+ var BookingForm = ({
2712
+ layoutClassName,
2713
+ className,
2714
+ apiConfig,
2715
+ demoRoomCode,
2716
+ timezone,
2717
+ handleBookingSuccess,
2718
+ ...props
2719
+ }) => {
2720
+ const apiClient = React2.useMemo(
2721
+ () => createDemoRoomApi(apiConfig),
2722
+ [apiConfig]
2723
+ );
2724
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2725
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full", className), ...props, children: [
2726
+ /* @__PURE__ */ jsxRuntime.jsx(
2727
+ BreadCrumbs,
2728
+ {
2729
+ className: layoutClassName,
2730
+ items: [{ label: "Home", link: "/" }, { label: "Demo Room" }]
2731
+ }
2732
+ ),
2733
+ /* @__PURE__ */ jsxRuntime.jsx(
2734
+ DemoRoomDetail,
2735
+ {
2736
+ className: cn("mt-8", layoutClassName),
2737
+ apiClient,
2738
+ demoRoomCode,
2739
+ locale: apiConfig.locale
2740
+ }
2741
+ )
2742
+ ] }),
2743
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-[#f5f5f5]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(
2744
+ DateTimePicker_default,
2745
+ {
2746
+ apiClient,
2747
+ demoRoomCode,
2748
+ timezone,
2749
+ locale: apiConfig.locale,
2750
+ onBookingSuccess: handleBookingSuccess
2751
+ }
2752
+ ) }) })
2753
+ ] });
2754
+ };
2755
+ BookingForm.displayName = "BookingForm";
2756
+ var BookingSuccess = ({
2757
+ bookingData: initialBookingData,
2758
+ token,
2759
+ apiConfig,
2760
+ onBackToHome,
2761
+ className
2762
+ }) => {
2763
+ const [bookingData, setBookingData] = React2.useState(initialBookingData || null);
2764
+ const [loading, setLoading] = React2.useState(false);
2765
+ const [error, setError] = React2.useState(null);
2766
+ React2.useEffect(() => {
2767
+ if (token && apiConfig && !initialBookingData) {
2768
+ const fetchBookingData = async () => {
2769
+ setLoading(true);
2770
+ setError(null);
2771
+ try {
2772
+ const apiClient = createDemoRoomApi(apiConfig);
2773
+ const booking = await apiClient.getBooking(token);
2774
+ setBookingData(booking);
2775
+ } catch (err) {
2776
+ console.error("Failed to fetch booking data:", err);
2777
+ setError("Failed to load booking information");
2778
+ } finally {
2779
+ setLoading(false);
2780
+ }
2781
+ };
2782
+ fetchBookingData();
2783
+ }
2784
+ }, [token, apiConfig, initialBookingData]);
2785
+ if (loading) {
2786
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `min-h-screen bg-[#F5F5F5] py-12 px-6 ${className || ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-2xl mx-auto text-center", children: [
2787
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin w-16 h-16 mx-auto mb-4 border-4 border-[#3ADB67] border-t-transparent rounded-full" }),
2788
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl text-gray-600", children: "Loading booking information..." })
2789
+ ] }) });
2790
+ }
2791
+ if (error || !bookingData) {
2792
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `min-h-screen bg-[#F5F5F5] py-12 px-6 ${className || ""}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-2xl mx-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-[12px] border border-red-200 p-8 text-center", children: [
2793
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 mx-auto mb-4 rounded-full bg-red-100 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
2794
+ "svg",
2795
+ {
2796
+ width: "32",
2797
+ height: "32",
2798
+ viewBox: "0 0 24 24",
2799
+ fill: "none",
2800
+ xmlns: "http://www.w3.org/2000/svg",
2801
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2802
+ "path",
2803
+ {
2804
+ d: "M12 8V12M12 16H12.01M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z",
2805
+ stroke: "#EF4444",
2806
+ strokeWidth: "2",
2807
+ strokeLinecap: "round",
2808
+ strokeLinejoin: "round"
2809
+ }
2810
+ )
2811
+ }
2812
+ ) }),
2813
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-2", children: error || "Booking Not Found" }),
2814
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base text-gray-600 mb-6", children: "We couldn't find your booking information. Please check your booking confirmation email or contact support." }),
2815
+ onBackToHome && /* @__PURE__ */ jsxRuntime.jsx(
2816
+ "button",
2817
+ {
2818
+ onClick: onBackToHome,
2819
+ className: "px-6 py-3 rounded-full bg-[#3ADB67] text-white font-medium text-base hover:bg-[#2FC257] transition-colors focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:ring-offset-2",
2820
+ children: "Back to Home"
2821
+ }
2822
+ )
2823
+ ] }) }) });
2824
+ }
2825
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `min-h-screen bg-[#F5F5F5] py-12 px-6 ${className || ""}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-2xl mx-auto", children: [
2826
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-8", children: [
2827
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 h-20 mx-auto mb-6 rounded-full bg-[#3ADB67] flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
2828
+ "svg",
2829
+ {
2830
+ width: "48",
2831
+ height: "48",
2832
+ viewBox: "0 0 32 32",
2833
+ fill: "none",
2834
+ xmlns: "http://www.w3.org/2000/svg",
2835
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2836
+ "path",
2837
+ {
2838
+ d: "M26.6667 8L12 22.6667L5.33334 16",
2839
+ stroke: "white",
2840
+ strokeWidth: "3",
2841
+ strokeLinecap: "round",
2842
+ strokeLinejoin: "round"
2843
+ }
2844
+ )
2845
+ }
2846
+ ) }),
2847
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-[48px] font-bold text-gray-900 mb-4", children: "Booking Confirmed!" }),
2848
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl text-gray-600", children: "Your demo room booking has been successfully confirmed." })
2849
+ ] }),
2850
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-[12px] border border-[#E4E5E6] p-8 mb-6", children: [
2851
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-gray-900 mb-6", children: "Booking Details" }),
2852
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2853
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start py-3 border-b border-gray-100", children: [
2854
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-600 font-medium", children: "Booking ID" }),
2855
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 font-semibold", children: bookingData.booking_id })
2856
+ ] }),
2857
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start py-3 border-b border-gray-100", children: [
2858
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-600 font-medium", children: "Date" }),
2859
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 font-semibold", children: bookingData.booking_date })
2860
+ ] }),
2861
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start py-3 border-b border-gray-100", children: [
2862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-600 font-medium", children: "Time" }),
2863
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 font-semibold", children: bookingData.booking_time })
2864
+ ] }),
2865
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start py-3 border-b border-gray-100", children: [
2866
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-600 font-medium", children: "Status" }),
2867
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-[#3ADB67] bg-opacity-10 text-[#3ADB67]", children: bookingData.status })
2868
+ ] }),
2869
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-start py-3", children: [
2870
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-600 font-medium", children: "Email" }),
2871
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base text-gray-900 font-semibold", children: bookingData.customer_email })
2872
+ ] })
2873
+ ] })
2874
+ ] }),
2875
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-[12px] p-6 mb-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
2876
+ /* @__PURE__ */ jsxRuntime.jsx(
2877
+ "svg",
2878
+ {
2879
+ className: "w-6 h-6 text-blue-600 flex-shrink-0 mt-0.5",
2880
+ fill: "none",
2881
+ viewBox: "0 0 24 24",
2882
+ stroke: "currentColor",
2883
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2884
+ "path",
2885
+ {
2886
+ strokeLinecap: "round",
2887
+ strokeLinejoin: "round",
2888
+ strokeWidth: 2,
2889
+ d: "M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
2890
+ }
2891
+ )
2892
+ }
2893
+ ),
2894
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2895
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold text-blue-900 mb-1", children: "Confirmation Email Sent" }),
2896
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-blue-800", children: [
2897
+ "A confirmation email has been sent to ",
2898
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: bookingData.customer_email }),
2899
+ " with all the booking details and instructions."
2900
+ ] })
2901
+ ] })
2902
+ ] }) }),
2903
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row gap-4", children: [
2904
+ onBackToHome && /* @__PURE__ */ jsxRuntime.jsx(
2905
+ "button",
2906
+ {
2907
+ onClick: onBackToHome,
2908
+ className: "flex-1 px-6 py-4 rounded-full bg-[#3ADB67] text-white font-medium text-base hover:bg-[#2FC257] transition-colors focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:ring-offset-2",
2909
+ children: "Back to Home"
2910
+ }
2911
+ ),
2912
+ /* @__PURE__ */ jsxRuntime.jsx(
2913
+ "button",
2914
+ {
2915
+ onClick: () => window.print(),
2916
+ className: "flex-1 px-6 py-4 rounded-full border-2 border-[#3ADB67] text-[#3ADB67] font-medium text-base hover:bg-[#3ADB67] hover:bg-opacity-5 transition-colors focus:outline-none focus:ring-2 focus:ring-[#3ADB67] focus:ring-offset-2",
2917
+ children: "Print Confirmation"
2918
+ }
2919
+ )
2920
+ ] })
2921
+ ] }) });
2922
+ };
2923
+
2924
+ // src/theme-tokens/tokens.ts
2925
+ var defaultTheme = {
2926
+ colors: {
2927
+ primary: {
2928
+ 50: "#eff6ff",
2929
+ 100: "#dbeafe",
2930
+ 200: "#bfdbfe",
2931
+ 300: "#93c5fd",
2932
+ 400: "#60a5fa",
2933
+ 500: "#3b82f6",
2934
+ 600: "#2563eb",
2935
+ 700: "#1d4ed8",
2936
+ 800: "#1e40af",
2937
+ 900: "#1e3a8a",
2938
+ 950: "#172554"
2939
+ },
2940
+ secondary: {
2941
+ 50: "#f8fafc",
2942
+ 100: "#f1f5f9",
2943
+ 200: "#e2e8f0",
2944
+ 300: "#cbd5e1",
2945
+ 400: "#94a3b8",
2946
+ 500: "#64748b",
2947
+ 600: "#475569",
2948
+ 700: "#334155",
2949
+ 800: "#1e293b",
2950
+ 900: "#0f172a",
2951
+ 950: "#020617"
2952
+ },
2953
+ success: {
2954
+ 50: "#f0fdf4",
2955
+ 500: "#22c55e",
2956
+ 900: "#14532d"
2957
+ },
2958
+ warning: {
2959
+ 50: "#fffbeb",
2960
+ 500: "#f59e0b",
2961
+ 900: "#78350f"
2962
+ },
2963
+ error: {
2964
+ 50: "#fef2f2",
2965
+ 500: "#ef4444",
2966
+ 900: "#7f1d1d"
2967
+ }
2968
+ },
2969
+ fontFamily: {
2970
+ sans: ["Inter", "system-ui", "sans-serif"],
2971
+ mono: ["Fira Code", "monospace"]
2972
+ },
2973
+ fontSize: {
2974
+ xs: ["0.75rem", { lineHeight: "1rem" }],
2975
+ sm: ["0.875rem", { lineHeight: "1.25rem" }],
2976
+ base: ["1rem", { lineHeight: "1.5rem" }],
2977
+ lg: ["1.125rem", { lineHeight: "1.75rem" }],
2978
+ xl: ["1.25rem", { lineHeight: "1.75rem" }],
2979
+ "2xl": ["1.5rem", { lineHeight: "2rem" }],
2980
+ "3xl": ["1.875rem", { lineHeight: "2.25rem" }],
2981
+ "4xl": ["2.25rem", { lineHeight: "2.5rem" }]
2982
+ },
2983
+ spacing: {
2984
+ 0: "0",
2985
+ 1: "0.25rem",
2986
+ 2: "0.5rem",
2987
+ 3: "0.75rem",
2988
+ 4: "1rem",
2989
+ 5: "1.25rem",
2990
+ 6: "1.5rem",
2991
+ 8: "2rem",
2992
+ 10: "2.5rem",
2993
+ 12: "3rem",
2994
+ 16: "4rem",
2995
+ 20: "5rem",
2996
+ 24: "6rem"
2997
+ },
2998
+ borderRadius: {
2999
+ none: "0",
3000
+ sm: "0.125rem",
3001
+ base: "0.25rem",
3002
+ md: "0.375rem",
3003
+ lg: "0.5rem",
3004
+ xl: "0.75rem",
3005
+ "2xl": "1rem",
3006
+ full: "9999px"
3007
+ },
3008
+ boxShadow: {
3009
+ sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
3010
+ base: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
3011
+ md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
3012
+ lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
3013
+ xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
3014
+ }
3015
+ };
3016
+ var ThemeContext = React2.createContext({ theme: defaultTheme });
3017
+ var useTheme = () => React2.useContext(ThemeContext);
3018
+ function deepMerge(target, source) {
3019
+ const result = { ...target };
3020
+ for (const key in source) {
3021
+ if (source[key] instanceof Object && !Array.isArray(source[key]) && key in target) {
3022
+ result[key] = deepMerge(target[key], source[key]);
3023
+ } else if (source[key] !== void 0) {
3024
+ result[key] = source[key];
3025
+ }
3026
+ }
3027
+ return result;
3028
+ }
3029
+ var ThemeProvider = ({
3030
+ theme: customTheme = {},
3031
+ children
3032
+ }) => {
3033
+ const theme2 = React2.useMemo(
3034
+ () => deepMerge(defaultTheme, customTheme),
3035
+ [customTheme]
3036
+ );
3037
+ React2.useEffect(() => {
3038
+ const root = document.documentElement;
3039
+ Object.entries(theme2.colors).forEach(([colorName, colorValues]) => {
3040
+ if (typeof colorValues === "object") {
3041
+ Object.entries(colorValues).forEach(([shade, value]) => {
3042
+ root.style.setProperty(`--color-${colorName}-${shade}`, value);
3043
+ });
3044
+ } else {
3045
+ root.style.setProperty(`--color-${colorName}`, colorValues);
3046
+ }
3047
+ });
3048
+ Object.entries(theme2.fontFamily).forEach(([name, value]) => {
3049
+ const fontValue = Array.isArray(value) ? value.join(", ") : String(value);
3050
+ root.style.setProperty(`--font-${name}`, fontValue);
3051
+ });
3052
+ Object.entries(theme2.spacing).forEach(([key, value]) => {
3053
+ root.style.setProperty(`--spacing-${key}`, value);
3054
+ });
3055
+ Object.entries(theme2.borderRadius).forEach(([key, value]) => {
3056
+ root.style.setProperty(`--radius-${key}`, value);
3057
+ });
3058
+ }, [theme2]);
3059
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: { theme: theme2 }, children });
3060
+ };
3061
+
3062
+ exports.BookingForm = BookingForm;
3063
+ exports.BookingSuccess = BookingSuccess;
3064
+ exports.DemoRoom = DemoRoom;
3065
+ exports.DemoRoomApiClient = DemoRoomApiClient;
3066
+ exports.DemoRoomDetail = DemoRoomDetail;
3067
+ exports.ThemeProvider = ThemeProvider;
3068
+ exports.cn = cn;
3069
+ exports.createDemoRoomApi = createDemoRoomApi;
3070
+ exports.useCreateBooking = useCreateBooking;
3071
+ exports.useDemoRoom = useDemoRoom;
3072
+ exports.useDemoRooms = useDemoRooms;
3073
+ exports.useQuestionnaire = useQuestionnaire;
3074
+ exports.useTheme = useTheme;
3075
+ exports.useTimeslots = useTimeslots;
3076
+ //# sourceMappingURL=index.js.map
3077
+ //# sourceMappingURL=index.js.map