@idkwebsites/components 0.1.8 → 0.1.15
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.cjs +566 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +519 -137
- package/dist/index.js.map +1 -1
- package/dist/styles.css +161 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -383,8 +383,62 @@ function ServicesList({
|
|
|
383
383
|
);
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
-
// src/
|
|
386
|
+
// src/lib/linkify.tsx
|
|
387
387
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
388
|
+
var LINK_REGEX = /((https?:\/\/|www\.)[^\s]+|[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}|(?:[a-z0-9-]+\.)+[a-z]{2,}(?:\/[^\s]*)?)/gi;
|
|
389
|
+
function buildHref(raw) {
|
|
390
|
+
if (raw.includes("@") && !raw.startsWith("http")) {
|
|
391
|
+
return `mailto:${raw}`;
|
|
392
|
+
}
|
|
393
|
+
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
394
|
+
return raw;
|
|
395
|
+
}
|
|
396
|
+
if (raw.startsWith("www.")) {
|
|
397
|
+
return `https://${raw}`;
|
|
398
|
+
}
|
|
399
|
+
return `https://${raw}`;
|
|
400
|
+
}
|
|
401
|
+
function trimTrailingPunctuation(value) {
|
|
402
|
+
let text = value;
|
|
403
|
+
let trailing = "";
|
|
404
|
+
while (text && /[),.!?:;]+$/.test(text)) {
|
|
405
|
+
trailing = text.slice(-1) + trailing;
|
|
406
|
+
text = text.slice(0, -1);
|
|
407
|
+
}
|
|
408
|
+
return { text, trailing };
|
|
409
|
+
}
|
|
410
|
+
function renderLinkedText(text) {
|
|
411
|
+
if (!text) return null;
|
|
412
|
+
const matches = Array.from(text.matchAll(LINK_REGEX));
|
|
413
|
+
if (matches.length === 0) return text;
|
|
414
|
+
const nodes = [];
|
|
415
|
+
let lastIndex = 0;
|
|
416
|
+
matches.forEach((match, index) => {
|
|
417
|
+
const matchText = match[0];
|
|
418
|
+
const start = match.index ?? 0;
|
|
419
|
+
if (start > lastIndex) {
|
|
420
|
+
nodes.push(text.slice(lastIndex, start));
|
|
421
|
+
}
|
|
422
|
+
const { text: cleanText, trailing } = trimTrailingPunctuation(matchText);
|
|
423
|
+
if (cleanText) {
|
|
424
|
+
const href = buildHref(cleanText);
|
|
425
|
+
nodes.push(
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", children: cleanText }, `link-${start}-${index}`)
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
if (trailing) {
|
|
430
|
+
nodes.push(trailing);
|
|
431
|
+
}
|
|
432
|
+
lastIndex = start + matchText.length;
|
|
433
|
+
});
|
|
434
|
+
if (lastIndex < text.length) {
|
|
435
|
+
nodes.push(text.slice(lastIndex));
|
|
436
|
+
}
|
|
437
|
+
return nodes;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/components/TeamMember.tsx
|
|
441
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
388
442
|
function TeamMember({
|
|
389
443
|
member,
|
|
390
444
|
className,
|
|
@@ -395,32 +449,32 @@ function TeamMember({
|
|
|
395
449
|
imagePosition = "left"
|
|
396
450
|
}) {
|
|
397
451
|
const initials = member.name?.split(" ").map((part) => part[0]).slice(0, 2).join("").toUpperCase();
|
|
398
|
-
const avatar = /* @__PURE__ */ (0,
|
|
452
|
+
const avatar = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "idk-team__avatar", children: member.photo?.url ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: member.photo.url, alt: member.name }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: initials }) });
|
|
399
453
|
if (layout === "profile") {
|
|
400
|
-
return /* @__PURE__ */ (0,
|
|
454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: ["idk-team__profile", className].filter(Boolean).join(" "), children: [
|
|
401
455
|
imagePosition === "left" ? avatar : null,
|
|
402
|
-
/* @__PURE__ */ (0,
|
|
403
|
-
/* @__PURE__ */ (0,
|
|
404
|
-
showRole ? /* @__PURE__ */ (0,
|
|
405
|
-
showBio && member.bio ? /* @__PURE__ */ (0,
|
|
406
|
-
showEmail ? /* @__PURE__ */ (0,
|
|
456
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "idk-team__info", children: [
|
|
457
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "idk-card__title", children: member.name }),
|
|
458
|
+
showRole ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-card__description", children: member.role || "Staff" }) : null,
|
|
459
|
+
showBio && member.bio ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-team__bio", children: renderLinkedText(member.bio) }) : null,
|
|
460
|
+
showEmail ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-card__meta", children: member.email }) : null
|
|
407
461
|
] }),
|
|
408
462
|
imagePosition === "right" ? avatar : null
|
|
409
463
|
] });
|
|
410
464
|
}
|
|
411
|
-
return /* @__PURE__ */ (0,
|
|
412
|
-
/* @__PURE__ */ (0,
|
|
413
|
-
/* @__PURE__ */ (0,
|
|
414
|
-
/* @__PURE__ */ (0,
|
|
415
|
-
showRole ? /* @__PURE__ */ (0,
|
|
416
|
-
showBio && member.bio ? /* @__PURE__ */ (0,
|
|
417
|
-
showEmail ? /* @__PURE__ */ (0,
|
|
465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: ["idk-card", className].filter(Boolean).join(" "), children: [
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "idk-team__avatar", children: member.photo?.url ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: member.photo.url, alt: member.name }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: initials }) }),
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "idk-team__info", children: [
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "idk-card__title", children: member.name }),
|
|
469
|
+
showRole ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-card__description", children: member.role || "Staff" }) : null,
|
|
470
|
+
showBio && member.bio ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-team__bio", children: renderLinkedText(member.bio) }) : null,
|
|
471
|
+
showEmail ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "idk-card__meta", children: member.email }) : null
|
|
418
472
|
] })
|
|
419
473
|
] });
|
|
420
474
|
}
|
|
421
475
|
|
|
422
476
|
// src/components/TeamGrid.tsx
|
|
423
|
-
var
|
|
477
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
424
478
|
function TeamGrid({
|
|
425
479
|
columns = 3,
|
|
426
480
|
className,
|
|
@@ -438,7 +492,7 @@ function TeamGrid({
|
|
|
438
492
|
}) {
|
|
439
493
|
const { data, isLoading, error } = useTeam(query);
|
|
440
494
|
if (isLoading) {
|
|
441
|
-
return /* @__PURE__ */ (0,
|
|
495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "idk-state", children: loadingMessage });
|
|
442
496
|
}
|
|
443
497
|
let members = data?.team ? [...data.team] : [];
|
|
444
498
|
if (filter) {
|
|
@@ -451,15 +505,15 @@ function TeamGrid({
|
|
|
451
505
|
members = members.slice(0, Math.max(0, limit));
|
|
452
506
|
}
|
|
453
507
|
if (error || members.length === 0) {
|
|
454
|
-
return /* @__PURE__ */ (0,
|
|
508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "idk-state", children: emptyMessage });
|
|
455
509
|
}
|
|
456
510
|
const gridStyle = { gridTemplateColumns: `repeat(${Math.max(1, columns)}, minmax(0, 1fr))` };
|
|
457
|
-
return /* @__PURE__ */ (0,
|
|
511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
458
512
|
"div",
|
|
459
513
|
{
|
|
460
514
|
className: ["idk-team", className].filter(Boolean).join(" "),
|
|
461
515
|
style: gridStyle,
|
|
462
|
-
children: members.map((member) => /* @__PURE__ */ (0,
|
|
516
|
+
children: members.map((member) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
463
517
|
TeamMember,
|
|
464
518
|
{
|
|
465
519
|
member,
|
|
@@ -478,7 +532,7 @@ function TeamGrid({
|
|
|
478
532
|
// src/components/ContactForm.tsx
|
|
479
533
|
var import_react6 = require("react");
|
|
480
534
|
var import_react_query7 = require("@tanstack/react-query");
|
|
481
|
-
var
|
|
535
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
482
536
|
var DEFAULT_FIELDS = ["name", "email", "phone", "message"];
|
|
483
537
|
function ContactForm({
|
|
484
538
|
fields = DEFAULT_FIELDS,
|
|
@@ -524,10 +578,10 @@ function ContactForm({
|
|
|
524
578
|
formType
|
|
525
579
|
});
|
|
526
580
|
};
|
|
527
|
-
return /* @__PURE__ */ (0,
|
|
528
|
-
fields.includes("name") && /* @__PURE__ */ (0,
|
|
529
|
-
/* @__PURE__ */ (0,
|
|
530
|
-
/* @__PURE__ */ (0,
|
|
581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { className: ["idk-form", className].filter(Boolean).join(" "), onSubmit: handleSubmit, children: [
|
|
582
|
+
fields.includes("name") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "idk-form__field", children: [
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Name" }),
|
|
584
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
531
585
|
"input",
|
|
532
586
|
{
|
|
533
587
|
value: formState.name,
|
|
@@ -536,9 +590,9 @@ function ContactForm({
|
|
|
536
590
|
}
|
|
537
591
|
)
|
|
538
592
|
] }),
|
|
539
|
-
fields.includes("email") && /* @__PURE__ */ (0,
|
|
540
|
-
/* @__PURE__ */ (0,
|
|
541
|
-
/* @__PURE__ */ (0,
|
|
593
|
+
fields.includes("email") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "idk-form__field", children: [
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Email" }),
|
|
595
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
542
596
|
"input",
|
|
543
597
|
{
|
|
544
598
|
type: "email",
|
|
@@ -548,9 +602,9 @@ function ContactForm({
|
|
|
548
602
|
}
|
|
549
603
|
)
|
|
550
604
|
] }),
|
|
551
|
-
fields.includes("phone") && /* @__PURE__ */ (0,
|
|
552
|
-
/* @__PURE__ */ (0,
|
|
553
|
-
/* @__PURE__ */ (0,
|
|
605
|
+
fields.includes("phone") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "idk-form__field", children: [
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Phone" }),
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
554
608
|
"input",
|
|
555
609
|
{
|
|
556
610
|
value: formState.phone,
|
|
@@ -558,9 +612,9 @@ function ContactForm({
|
|
|
558
612
|
}
|
|
559
613
|
)
|
|
560
614
|
] }),
|
|
561
|
-
fields.includes("subject") && /* @__PURE__ */ (0,
|
|
562
|
-
/* @__PURE__ */ (0,
|
|
563
|
-
/* @__PURE__ */ (0,
|
|
615
|
+
fields.includes("subject") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "idk-form__field", children: [
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Subject" }),
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
564
618
|
"input",
|
|
565
619
|
{
|
|
566
620
|
value: formState.subject,
|
|
@@ -568,9 +622,9 @@ function ContactForm({
|
|
|
568
622
|
}
|
|
569
623
|
)
|
|
570
624
|
] }),
|
|
571
|
-
fields.includes("message") && /* @__PURE__ */ (0,
|
|
572
|
-
/* @__PURE__ */ (0,
|
|
573
|
-
/* @__PURE__ */ (0,
|
|
625
|
+
fields.includes("message") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "idk-form__field", children: [
|
|
626
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Message" }),
|
|
627
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
574
628
|
"textarea",
|
|
575
629
|
{
|
|
576
630
|
value: formState.message,
|
|
@@ -580,15 +634,27 @@ function ContactForm({
|
|
|
580
634
|
}
|
|
581
635
|
)
|
|
582
636
|
] }),
|
|
583
|
-
/* @__PURE__ */ (0,
|
|
584
|
-
mutation.isError ? /* @__PURE__ */ (0,
|
|
585
|
-
mutation.isSuccess ? /* @__PURE__ */ (0,
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "submit", className: "idk-button", disabled: mutation.isPending, children: mutation.isPending ? "Sending..." : submitLabel }),
|
|
638
|
+
mutation.isError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "idk-form__error", children: "Something went wrong. Please try again." }) : null,
|
|
639
|
+
mutation.isSuccess ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "idk-form__success", children: "Thanks! We'll be in touch soon." }) : null
|
|
586
640
|
] });
|
|
587
641
|
}
|
|
588
642
|
|
|
589
643
|
// src/components/BookingWidget.tsx
|
|
590
644
|
var import_react7 = require("react");
|
|
591
|
-
var
|
|
645
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
646
|
+
var parseDateOnly = (value) => {
|
|
647
|
+
if (!value) return null;
|
|
648
|
+
const normalized = value.includes("T") ? value.split("T")[0] : value;
|
|
649
|
+
const parsed = /* @__PURE__ */ new Date(`${normalized}T00:00:00`);
|
|
650
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
651
|
+
};
|
|
652
|
+
var addDays = (dateStr, days) => {
|
|
653
|
+
const parsed = parseDateOnly(dateStr);
|
|
654
|
+
if (!parsed) return dateStr;
|
|
655
|
+
parsed.setDate(parsed.getDate() + days);
|
|
656
|
+
return parsed.toISOString().slice(0, 10);
|
|
657
|
+
};
|
|
592
658
|
function BookingWidget({
|
|
593
659
|
className,
|
|
594
660
|
showStaffSelection = true,
|
|
@@ -615,7 +681,16 @@ function BookingWidget({
|
|
|
615
681
|
staffLayout = "grid",
|
|
616
682
|
staffColumns = 2,
|
|
617
683
|
showAnyStaffOption = true,
|
|
618
|
-
|
|
684
|
+
staffPageSize = 8,
|
|
685
|
+
showStaffPagination,
|
|
686
|
+
timeLayout = "split",
|
|
687
|
+
availabilityDays: availabilityDaysProp = 7,
|
|
688
|
+
enableDatePaging = true,
|
|
689
|
+
datePickerMode = "list",
|
|
690
|
+
calendarVariant = "default",
|
|
691
|
+
maxAdvanceMonths = 3,
|
|
692
|
+
disabledWeekdays = [],
|
|
693
|
+
showFullyBookedLabel = true
|
|
619
694
|
}) {
|
|
620
695
|
const resolvedServicesQuery = (0, import_react7.useMemo)(
|
|
621
696
|
() => services ? { ...servicesQuery, enabled: false } : servicesQuery,
|
|
@@ -634,6 +709,17 @@ function BookingWidget({
|
|
|
634
709
|
const [serviceSearch, setServiceSearch] = (0, import_react7.useState)("");
|
|
635
710
|
const [categoryFilter, setCategoryFilter] = (0, import_react7.useState)("all");
|
|
636
711
|
const [servicePage, setServicePage] = (0, import_react7.useState)(1);
|
|
712
|
+
const [staffPage, setStaffPage] = (0, import_react7.useState)(1);
|
|
713
|
+
const [availabilityDays, setAvailabilityDays] = (0, import_react7.useState)(
|
|
714
|
+
Math.max(1, availabilityDaysProp)
|
|
715
|
+
);
|
|
716
|
+
const [availabilityStartDate, setAvailabilityStartDate] = (0, import_react7.useState)(
|
|
717
|
+
() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
|
|
718
|
+
);
|
|
719
|
+
const [calendarMonth, setCalendarMonth] = (0, import_react7.useState)(() => {
|
|
720
|
+
const now = /* @__PURE__ */ new Date();
|
|
721
|
+
return new Date(now.getFullYear(), now.getMonth(), 1);
|
|
722
|
+
});
|
|
637
723
|
const [bookingError, setBookingError] = (0, import_react7.useState)(null);
|
|
638
724
|
const [details, setDetails] = (0, import_react7.useState)({
|
|
639
725
|
name: "",
|
|
@@ -665,6 +751,9 @@ function BookingWidget({
|
|
|
665
751
|
(0, import_react7.useEffect)(() => {
|
|
666
752
|
setServicePage(1);
|
|
667
753
|
}, [serviceSearch, categoryFilter]);
|
|
754
|
+
(0, import_react7.useEffect)(() => {
|
|
755
|
+
setStaffPage(1);
|
|
756
|
+
}, [selectedService?.id, teamData, teamFilter]);
|
|
668
757
|
const pagedServices = (0, import_react7.useMemo)(() => {
|
|
669
758
|
const pageSize = Math.max(1, servicePageSize);
|
|
670
759
|
return filteredServices.slice(0, pageSize * servicePage);
|
|
@@ -680,10 +769,21 @@ function BookingWidget({
|
|
|
680
769
|
const teamList = teamData?.team || [];
|
|
681
770
|
return teamFilter ? teamList.filter(teamFilter) : teamList;
|
|
682
771
|
}, [selectedService, teamData, teamFilter]);
|
|
772
|
+
const pagedStaff = (0, import_react7.useMemo)(() => {
|
|
773
|
+
const pageSize = Math.max(1, staffPageSize);
|
|
774
|
+
return staffOptions.slice(0, pageSize * staffPage);
|
|
775
|
+
}, [staffOptions, staffPage, staffPageSize]);
|
|
776
|
+
const hasMoreStaff = staffOptions.length > pagedStaff.length;
|
|
777
|
+
const shouldPaginateStaff = showStaffPagination ?? hasMoreStaff;
|
|
778
|
+
const availabilityEndDate = (0, import_react7.useMemo)(
|
|
779
|
+
() => addDays(availabilityStartDate, Math.max(1, availabilityDays) - 1),
|
|
780
|
+
[availabilityStartDate, availabilityDays]
|
|
781
|
+
);
|
|
683
782
|
const availability = useAvailability({
|
|
684
783
|
serviceId: selectedService?.id || "",
|
|
685
784
|
staffId: selectedStaff?.id,
|
|
686
|
-
|
|
785
|
+
startDate: availabilityStartDate,
|
|
786
|
+
endDate: availabilityEndDate,
|
|
687
787
|
enabled: Boolean(selectedService)
|
|
688
788
|
});
|
|
689
789
|
const timeZone = availability.data?.timeZone || "America/Chicago";
|
|
@@ -753,18 +853,6 @@ function BookingWidget({
|
|
|
753
853
|
setSelectedEndTime(null);
|
|
754
854
|
setBookingError(null);
|
|
755
855
|
};
|
|
756
|
-
(0, import_react7.useEffect)(() => {
|
|
757
|
-
if (step !== "time") return;
|
|
758
|
-
if (!availability.data?.dates?.length) return;
|
|
759
|
-
if (selectedDate) return;
|
|
760
|
-
setSelectedDate(availability.data.dates[0].date);
|
|
761
|
-
}, [step, availability.data, selectedDate]);
|
|
762
|
-
const parseDateOnly = (value) => {
|
|
763
|
-
if (!value) return null;
|
|
764
|
-
const normalized = value.includes("T") ? value.split("T")[0] : value;
|
|
765
|
-
const parsed = /* @__PURE__ */ new Date(`${normalized}T00:00:00`);
|
|
766
|
-
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
767
|
-
};
|
|
768
856
|
const parseDateTime = (value, fallbackDate) => {
|
|
769
857
|
if (!value) return null;
|
|
770
858
|
const direct = new Date(value);
|
|
@@ -810,6 +898,156 @@ function BookingWidget({
|
|
|
810
898
|
const remaining = minutes % 60;
|
|
811
899
|
return remaining === 0 ? `${hours} hr${hours > 1 ? "s" : ""}` : `${hours} hr ${remaining} min`;
|
|
812
900
|
};
|
|
901
|
+
const todayString = (0, import_react7.useMemo)(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), []);
|
|
902
|
+
const todayDate = (0, import_react7.useMemo)(() => {
|
|
903
|
+
const now = /* @__PURE__ */ new Date();
|
|
904
|
+
now.setHours(0, 0, 0, 0);
|
|
905
|
+
return now;
|
|
906
|
+
}, []);
|
|
907
|
+
const disabledWeekdaysSet = (0, import_react7.useMemo)(() => new Set(disabledWeekdays), [disabledWeekdays]);
|
|
908
|
+
const getMonthStart = (0, import_react7.useCallback)((date) => {
|
|
909
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
910
|
+
}, []);
|
|
911
|
+
const getMonthEnd = (0, import_react7.useCallback)((date) => {
|
|
912
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
913
|
+
}, []);
|
|
914
|
+
const getMonthDays = (0, import_react7.useCallback)(
|
|
915
|
+
(date) => {
|
|
916
|
+
const start = getMonthStart(date);
|
|
917
|
+
const end = getMonthEnd(date);
|
|
918
|
+
const days = [];
|
|
919
|
+
const startDay = start.getDay();
|
|
920
|
+
for (let i = startDay; i > 0; i -= 1) {
|
|
921
|
+
const d = new Date(start);
|
|
922
|
+
d.setDate(start.getDate() - i);
|
|
923
|
+
days.push({ date: d.toISOString().slice(0, 10), isCurrentMonth: false });
|
|
924
|
+
}
|
|
925
|
+
for (let day = 1; day <= end.getDate(); day += 1) {
|
|
926
|
+
const d = new Date(date.getFullYear(), date.getMonth(), day);
|
|
927
|
+
days.push({ date: d.toISOString().slice(0, 10), isCurrentMonth: true });
|
|
928
|
+
}
|
|
929
|
+
const remainder = 7 - (days.length % 7 || 7);
|
|
930
|
+
for (let i = 1; i <= remainder; i += 1) {
|
|
931
|
+
const d = new Date(end);
|
|
932
|
+
d.setDate(end.getDate() + i);
|
|
933
|
+
days.push({ date: d.toISOString().slice(0, 10), isCurrentMonth: false });
|
|
934
|
+
}
|
|
935
|
+
return days;
|
|
936
|
+
},
|
|
937
|
+
[getMonthEnd, getMonthStart]
|
|
938
|
+
);
|
|
939
|
+
const maxAdvanceDate = (0, import_react7.useMemo)(() => {
|
|
940
|
+
if (!maxAdvanceMonths || maxAdvanceMonths <= 0) return null;
|
|
941
|
+
const maxMonth = new Date(todayDate.getFullYear(), todayDate.getMonth() + maxAdvanceMonths - 1, 1);
|
|
942
|
+
return getMonthEnd(maxMonth);
|
|
943
|
+
}, [getMonthEnd, maxAdvanceMonths, todayDate]);
|
|
944
|
+
const maxAdvanceMonthStart = (0, import_react7.useMemo)(() => {
|
|
945
|
+
if (!maxAdvanceMonths || maxAdvanceMonths <= 0) return null;
|
|
946
|
+
return new Date(todayDate.getFullYear(), todayDate.getMonth() + maxAdvanceMonths - 1, 1);
|
|
947
|
+
}, [maxAdvanceMonths, todayDate]);
|
|
948
|
+
const monthOptionCount = (0, import_react7.useMemo)(() => {
|
|
949
|
+
if (!maxAdvanceMonths || maxAdvanceMonths <= 0) return 12;
|
|
950
|
+
return maxAdvanceMonths;
|
|
951
|
+
}, [maxAdvanceMonths]);
|
|
952
|
+
const monthOptions = (0, import_react7.useMemo)(() => {
|
|
953
|
+
return Array.from({ length: monthOptionCount }, (_, index) => {
|
|
954
|
+
const date = new Date(todayDate.getFullYear(), todayDate.getMonth() + index, 1);
|
|
955
|
+
return {
|
|
956
|
+
value: `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`,
|
|
957
|
+
label: new Intl.DateTimeFormat("en-US", { month: "long", year: "numeric" }).format(date),
|
|
958
|
+
date
|
|
959
|
+
};
|
|
960
|
+
});
|
|
961
|
+
}, [monthOptionCount, todayDate]);
|
|
962
|
+
const calendarDays = (0, import_react7.useMemo)(() => getMonthDays(calendarMonth), [getMonthDays, calendarMonth]);
|
|
963
|
+
const availabilityByDate = (0, import_react7.useMemo)(() => {
|
|
964
|
+
const map = /* @__PURE__ */ new Map();
|
|
965
|
+
(availability.data?.dates || []).forEach((entry) => {
|
|
966
|
+
map.set(entry.date, entry);
|
|
967
|
+
});
|
|
968
|
+
return map;
|
|
969
|
+
}, [availability.data]);
|
|
970
|
+
const hasBlockedInCalendarView = (0, import_react7.useMemo)(() => {
|
|
971
|
+
return calendarDays.some((day) => {
|
|
972
|
+
const entry = availabilityByDate.get(day.date);
|
|
973
|
+
if (!entry) return false;
|
|
974
|
+
return !entry.slots.some((slot) => slot.available);
|
|
975
|
+
});
|
|
976
|
+
}, [calendarDays, availabilityByDate]);
|
|
977
|
+
const handlePrevDates = () => {
|
|
978
|
+
if (availabilityStartDate <= todayString) return;
|
|
979
|
+
setAvailabilityStartDate((prev) => addDays(prev, -availabilityDays));
|
|
980
|
+
setSelectedDate(null);
|
|
981
|
+
setSelectedTime(null);
|
|
982
|
+
setSelectedEndTime(null);
|
|
983
|
+
setBookingError(null);
|
|
984
|
+
};
|
|
985
|
+
const handleNextDates = () => {
|
|
986
|
+
if (maxAdvanceDate) {
|
|
987
|
+
const nextStart = parseDateOnly(addDays(availabilityStartDate, availabilityDays));
|
|
988
|
+
if (nextStart && nextStart > maxAdvanceDate) {
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
setAvailabilityStartDate((prev) => addDays(prev, availabilityDays));
|
|
993
|
+
setSelectedDate(null);
|
|
994
|
+
setSelectedTime(null);
|
|
995
|
+
setSelectedEndTime(null);
|
|
996
|
+
setBookingError(null);
|
|
997
|
+
};
|
|
998
|
+
const handlePrevMonth = () => {
|
|
999
|
+
setCalendarMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1));
|
|
1000
|
+
setSelectedDate(null);
|
|
1001
|
+
setSelectedTime(null);
|
|
1002
|
+
setSelectedEndTime(null);
|
|
1003
|
+
setBookingError(null);
|
|
1004
|
+
};
|
|
1005
|
+
const handleNextMonth = () => {
|
|
1006
|
+
if (maxAdvanceMonthStart) {
|
|
1007
|
+
const nextMonth = new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() + 1, 1);
|
|
1008
|
+
if (nextMonth > maxAdvanceMonthStart) return;
|
|
1009
|
+
}
|
|
1010
|
+
setCalendarMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1));
|
|
1011
|
+
setSelectedDate(null);
|
|
1012
|
+
setSelectedTime(null);
|
|
1013
|
+
setSelectedEndTime(null);
|
|
1014
|
+
setBookingError(null);
|
|
1015
|
+
};
|
|
1016
|
+
const handleMonthSelect = (value) => {
|
|
1017
|
+
const [year, month] = value.split("-").map(Number);
|
|
1018
|
+
if (!year || !month) return;
|
|
1019
|
+
setCalendarMonth(new Date(year, month - 1, 1));
|
|
1020
|
+
setSelectedDate(null);
|
|
1021
|
+
setSelectedTime(null);
|
|
1022
|
+
setSelectedEndTime(null);
|
|
1023
|
+
setBookingError(null);
|
|
1024
|
+
};
|
|
1025
|
+
(0, import_react7.useEffect)(() => {
|
|
1026
|
+
if (step !== "time") return;
|
|
1027
|
+
if (!availability.data?.dates?.length) return;
|
|
1028
|
+
const matches = selectedDate ? availability.data.dates.some((entry) => entry.date === selectedDate) : false;
|
|
1029
|
+
if (matches) return;
|
|
1030
|
+
setSelectedDate(availability.data.dates[0].date);
|
|
1031
|
+
}, [step, availability.data, selectedDate]);
|
|
1032
|
+
(0, import_react7.useEffect)(() => {
|
|
1033
|
+
if (!selectedService) return;
|
|
1034
|
+
if (datePickerMode === "calendar") {
|
|
1035
|
+
const now = /* @__PURE__ */ new Date();
|
|
1036
|
+
setCalendarMonth(new Date(now.getFullYear(), now.getMonth(), 1));
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
setAvailabilityStartDate((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
1040
|
+
setAvailabilityDays(Math.max(1, availabilityDaysProp));
|
|
1041
|
+
}, [selectedService?.id, selectedStaff?.id, availabilityDaysProp, datePickerMode]);
|
|
1042
|
+
(0, import_react7.useEffect)(() => {
|
|
1043
|
+
if (datePickerMode !== "calendar") return;
|
|
1044
|
+
const start = getMonthStart(calendarMonth);
|
|
1045
|
+
const end = getMonthEnd(calendarMonth);
|
|
1046
|
+
const startString = start.toISOString().slice(0, 10);
|
|
1047
|
+
const daysInMonth = end.getDate();
|
|
1048
|
+
setAvailabilityStartDate(startString);
|
|
1049
|
+
setAvailabilityDays(daysInMonth);
|
|
1050
|
+
}, [calendarMonth, datePickerMode, getMonthEnd, getMonthStart]);
|
|
813
1051
|
const handleBack = () => {
|
|
814
1052
|
if (step === "service") return;
|
|
815
1053
|
if (step === "staff") {
|
|
@@ -879,32 +1117,32 @@ function BookingWidget({
|
|
|
879
1117
|
};
|
|
880
1118
|
const isServicesLoading = services ? false : servicesLoading;
|
|
881
1119
|
if (isServicesLoading) {
|
|
882
|
-
return /* @__PURE__ */ (0,
|
|
1120
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "Loading booking options..." });
|
|
883
1121
|
}
|
|
884
1122
|
if (!servicesList.length) {
|
|
885
|
-
return /* @__PURE__ */ (0,
|
|
1123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No services available." });
|
|
886
1124
|
}
|
|
887
|
-
return /* @__PURE__ */ (0,
|
|
1125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
888
1126
|
"div",
|
|
889
1127
|
{
|
|
890
1128
|
ref: widgetRef,
|
|
891
1129
|
className: ["idk-booking", className].filter(Boolean).join(" "),
|
|
892
1130
|
children: [
|
|
893
|
-
/* @__PURE__ */ (0,
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
/* @__PURE__ */ (0,
|
|
896
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
1131
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__header", children: [
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__title-wrap", children: [
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "idk-booking__title", children: title }),
|
|
1134
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-booking__subtitle", children: subtitle }) : null
|
|
897
1135
|
] }),
|
|
898
|
-
step !== "service" && step !== "done" ? /* @__PURE__ */ (0,
|
|
1136
|
+
step !== "service" && step !== "done" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "idk-link", onClick: handleBack, children: "Back" }) : null
|
|
899
1137
|
] }),
|
|
900
|
-
step !== "done" ? /* @__PURE__ */ (0,
|
|
901
|
-
/* @__PURE__ */ (0,
|
|
1138
|
+
step !== "done" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__progress", children: [
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
|
|
902
1140
|
"Step ",
|
|
903
1141
|
stepNumber,
|
|
904
1142
|
" of ",
|
|
905
1143
|
totalSteps
|
|
906
1144
|
] }),
|
|
907
|
-
/* @__PURE__ */ (0,
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__bar", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
908
1146
|
"div",
|
|
909
1147
|
{
|
|
910
1148
|
className: "idk-booking__bar-fill",
|
|
@@ -912,10 +1150,10 @@ function BookingWidget({
|
|
|
912
1150
|
}
|
|
913
1151
|
) })
|
|
914
1152
|
] }) : null,
|
|
915
|
-
step === "service" && /* @__PURE__ */ (0,
|
|
916
|
-
/* @__PURE__ */ (0,
|
|
917
|
-
enableServiceSearch || enableCategoryFilter ? /* @__PURE__ */ (0,
|
|
918
|
-
enableServiceSearch ? /* @__PURE__ */ (0,
|
|
1153
|
+
step === "service" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a service" }),
|
|
1155
|
+
enableServiceSearch || enableCategoryFilter ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__filters", children: [
|
|
1156
|
+
enableServiceSearch ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
919
1157
|
"input",
|
|
920
1158
|
{
|
|
921
1159
|
type: "search",
|
|
@@ -924,19 +1162,19 @@ function BookingWidget({
|
|
|
924
1162
|
placeholder: serviceSearchPlaceholder
|
|
925
1163
|
}
|
|
926
1164
|
) : null,
|
|
927
|
-
enableCategoryFilter && categories.length > 0 ? /* @__PURE__ */ (0,
|
|
1165
|
+
enableCategoryFilter && categories.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
928
1166
|
"select",
|
|
929
1167
|
{
|
|
930
1168
|
value: categoryFilter,
|
|
931
1169
|
onChange: (event) => setCategoryFilter(event.target.value),
|
|
932
1170
|
children: [
|
|
933
|
-
/* @__PURE__ */ (0,
|
|
934
|
-
categories.map((category) => /* @__PURE__ */ (0,
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "all", children: categoryLabel }),
|
|
1172
|
+
categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: category, children: category }, category))
|
|
935
1173
|
]
|
|
936
1174
|
}
|
|
937
1175
|
) : null
|
|
938
1176
|
] }) : null,
|
|
939
|
-
filteredServices.length === 0 ? /* @__PURE__ */ (0,
|
|
1177
|
+
filteredServices.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No services match your filters." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
940
1178
|
"div",
|
|
941
1179
|
{
|
|
942
1180
|
className: [
|
|
@@ -949,7 +1187,7 @@ function BookingWidget({
|
|
|
949
1187
|
},
|
|
950
1188
|
children: pagedServices.map((service) => {
|
|
951
1189
|
const isSelected = selectedService?.id === service.id;
|
|
952
|
-
return /* @__PURE__ */ (0,
|
|
1190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
953
1191
|
"button",
|
|
954
1192
|
{
|
|
955
1193
|
type: "button",
|
|
@@ -967,20 +1205,20 @@ function BookingWidget({
|
|
|
967
1205
|
}
|
|
968
1206
|
},
|
|
969
1207
|
children: [
|
|
970
|
-
/* @__PURE__ */ (0,
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
972
|
-
/* @__PURE__ */ (0,
|
|
973
|
-
isSelected ? /* @__PURE__ */ (0,
|
|
974
|
-
typeof service.price === "number" && service.price > 0 ? /* @__PURE__ */ (0,
|
|
1208
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__header", children: [
|
|
1209
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: service.name }),
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "idk-card__aside", children: [
|
|
1211
|
+
isSelected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__check", children: "\u2713" }) : null,
|
|
1212
|
+
typeof service.price === "number" && service.price > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "idk-card__price", children: [
|
|
975
1213
|
"$",
|
|
976
1214
|
(service.price / 100).toFixed(2)
|
|
977
1215
|
] }) : null
|
|
978
1216
|
] })
|
|
979
1217
|
] }),
|
|
980
|
-
service.description ? /* @__PURE__ */ (0,
|
|
981
|
-
/* @__PURE__ */ (0,
|
|
982
|
-
/* @__PURE__ */ (0,
|
|
983
|
-
service.category ? /* @__PURE__ */ (0,
|
|
1218
|
+
service.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-card__description", children: service.description }) : null,
|
|
1219
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__meta", children: [
|
|
1220
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: formatDuration(service.duration) }),
|
|
1221
|
+
service.category ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-pill", children: service.category }) : null
|
|
984
1222
|
] })
|
|
985
1223
|
]
|
|
986
1224
|
},
|
|
@@ -989,8 +1227,8 @@ function BookingWidget({
|
|
|
989
1227
|
})
|
|
990
1228
|
}
|
|
991
1229
|
),
|
|
992
|
-
/* @__PURE__ */ (0,
|
|
993
|
-
shouldPaginate ? /* @__PURE__ */ (0,
|
|
1230
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__actions", children: [
|
|
1231
|
+
shouldPaginate ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
994
1232
|
"button",
|
|
995
1233
|
{
|
|
996
1234
|
type: "button",
|
|
@@ -1000,12 +1238,12 @@ function BookingWidget({
|
|
|
1000
1238
|
children: hasMoreServices ? "Show more services" : "All services shown"
|
|
1001
1239
|
}
|
|
1002
1240
|
) : null,
|
|
1003
|
-
selectedService && !autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1241
|
+
selectedService && !autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "idk-button", onClick: handleServiceContinue, children: "Continue" }) : null
|
|
1004
1242
|
] })
|
|
1005
1243
|
] }),
|
|
1006
|
-
step === "staff" && /* @__PURE__ */ (0,
|
|
1007
|
-
/* @__PURE__ */ (0,
|
|
1008
|
-
staffOptions.length === 0 ? /* @__PURE__ */ (0,
|
|
1244
|
+
step === "staff" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1245
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a team member" }),
|
|
1246
|
+
staffOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No team members available." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1009
1247
|
"div",
|
|
1010
1248
|
{
|
|
1011
1249
|
className: [
|
|
@@ -1014,7 +1252,7 @@ function BookingWidget({
|
|
|
1014
1252
|
].join(" "),
|
|
1015
1253
|
style: staffLayout === "grid" ? { gridTemplateColumns: `repeat(${Math.max(1, staffColumns)}, minmax(0, 1fr))` } : void 0,
|
|
1016
1254
|
children: [
|
|
1017
|
-
showAnyStaffOption && canSkipStaff ? /* @__PURE__ */ (0,
|
|
1255
|
+
showAnyStaffOption && canSkipStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1018
1256
|
"button",
|
|
1019
1257
|
{
|
|
1020
1258
|
type: "button",
|
|
@@ -1030,16 +1268,16 @@ function BookingWidget({
|
|
|
1030
1268
|
}
|
|
1031
1269
|
},
|
|
1032
1270
|
children: [
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1034
|
-
/* @__PURE__ */ (0,
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__header", children: [
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: "Any Available" }),
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__badge", children: "Recommended" })
|
|
1036
1274
|
] }),
|
|
1037
|
-
/* @__PURE__ */ (0,
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-card__description", children: "We'll match you with the first available stylist." })
|
|
1038
1276
|
]
|
|
1039
1277
|
},
|
|
1040
1278
|
"any-staff"
|
|
1041
1279
|
) : null,
|
|
1042
|
-
|
|
1280
|
+
pagedStaff.map((staff) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1043
1281
|
"button",
|
|
1044
1282
|
{
|
|
1045
1283
|
type: "button",
|
|
@@ -1055,12 +1293,12 @@ function BookingWidget({
|
|
|
1055
1293
|
scrollToTop();
|
|
1056
1294
|
}
|
|
1057
1295
|
},
|
|
1058
|
-
children: /* @__PURE__ */ (0,
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1061
|
-
/* @__PURE__ */ (0,
|
|
1062
|
-
/* @__PURE__ */ (0,
|
|
1063
|
-
staff.bio ? /* @__PURE__ */ (0,
|
|
1296
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-team__card", children: [
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-team__avatar", children: staff.photo?.url ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: staff.photo.url, alt: staff.name }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: staff.name.split(" ").map((part) => part[0]).slice(0, 2).join("").toUpperCase() }) }),
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: staff.name }),
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__meta", children: staff.role || "Staff" }),
|
|
1301
|
+
staff.bio ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-card__description", children: renderLinkedText(staff.bio) }) : null
|
|
1064
1302
|
] })
|
|
1065
1303
|
] })
|
|
1066
1304
|
},
|
|
@@ -1069,8 +1307,18 @@ function BookingWidget({
|
|
|
1069
1307
|
]
|
|
1070
1308
|
}
|
|
1071
1309
|
),
|
|
1072
|
-
/* @__PURE__ */ (0,
|
|
1073
|
-
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__actions", children: [
|
|
1311
|
+
shouldPaginateStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1312
|
+
"button",
|
|
1313
|
+
{
|
|
1314
|
+
type: "button",
|
|
1315
|
+
className: "idk-button idk-button--ghost",
|
|
1316
|
+
onClick: () => setStaffPage((prev) => hasMoreStaff ? prev + 1 : 1),
|
|
1317
|
+
disabled: !hasMoreStaff && staffPage === 1,
|
|
1318
|
+
children: hasMoreStaff ? "Show more staff" : staffPage > 1 ? "Show fewer staff" : "All staff shown"
|
|
1319
|
+
}
|
|
1320
|
+
) : null,
|
|
1321
|
+
canSkipStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1074
1322
|
"button",
|
|
1075
1323
|
{
|
|
1076
1324
|
type: "button",
|
|
@@ -1083,7 +1331,7 @@ function BookingWidget({
|
|
|
1083
1331
|
children: "Continue without selecting"
|
|
1084
1332
|
}
|
|
1085
1333
|
) : null,
|
|
1086
|
-
!autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1334
|
+
!autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1087
1335
|
"button",
|
|
1088
1336
|
{
|
|
1089
1337
|
type: "button",
|
|
@@ -1095,37 +1343,171 @@ function BookingWidget({
|
|
|
1095
1343
|
) : null
|
|
1096
1344
|
] })
|
|
1097
1345
|
] }),
|
|
1098
|
-
step === "time" && /* @__PURE__ */ (0,
|
|
1099
|
-
/* @__PURE__ */ (0,
|
|
1100
|
-
availability.isLoading ? /* @__PURE__ */ (0,
|
|
1101
|
-
/* @__PURE__ */ (0,
|
|
1102
|
-
"
|
|
1346
|
+
step === "time" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a time" }),
|
|
1348
|
+
availability.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "Loading availability..." }) : availability.data ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: ["idk-availability", timeLayout === "split" ? "idk-availability--split" : ""].join(" "), children: [
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__dates", children: datePickerMode === "calendar" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1350
|
+
"div",
|
|
1103
1351
|
{
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1352
|
+
className: [
|
|
1353
|
+
"idk-calendar",
|
|
1354
|
+
calendarVariant === "compact" ? "idk-calendar--compact" : ""
|
|
1355
|
+
].filter(Boolean).join(" "),
|
|
1356
|
+
children: [
|
|
1357
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__header", children: calendarVariant === "compact" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-calendar__header idk-calendar__header--compact", children: [
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1359
|
+
"button",
|
|
1360
|
+
{
|
|
1361
|
+
type: "button",
|
|
1362
|
+
className: "idk-calendar__nav-btn",
|
|
1363
|
+
onClick: handlePrevMonth,
|
|
1364
|
+
disabled: calendarMonth <= getMonthStart(todayDate),
|
|
1365
|
+
"aria-label": "Previous month",
|
|
1366
|
+
children: "<"
|
|
1367
|
+
}
|
|
1368
|
+
),
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1370
|
+
"select",
|
|
1371
|
+
{
|
|
1372
|
+
className: "idk-calendar__month-select",
|
|
1373
|
+
value: `${calendarMonth.getFullYear()}-${String(calendarMonth.getMonth() + 1).padStart(2, "0")}`,
|
|
1374
|
+
onChange: (event) => handleMonthSelect(event.target.value),
|
|
1375
|
+
children: monthOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: option.value, children: option.label }, option.value))
|
|
1376
|
+
}
|
|
1377
|
+
),
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1379
|
+
"button",
|
|
1380
|
+
{
|
|
1381
|
+
type: "button",
|
|
1382
|
+
className: "idk-calendar__nav-btn",
|
|
1383
|
+
onClick: handleNextMonth,
|
|
1384
|
+
disabled: Boolean(maxAdvanceMonthStart && calendarMonth >= maxAdvanceMonthStart),
|
|
1385
|
+
"aria-label": "Next month",
|
|
1386
|
+
children: ">"
|
|
1387
|
+
}
|
|
1388
|
+
)
|
|
1389
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1391
|
+
"button",
|
|
1392
|
+
{
|
|
1393
|
+
type: "button",
|
|
1394
|
+
className: "idk-button idk-button--ghost",
|
|
1395
|
+
onClick: handlePrevMonth,
|
|
1396
|
+
disabled: calendarMonth <= getMonthStart(todayDate),
|
|
1397
|
+
children: "Prev"
|
|
1398
|
+
}
|
|
1399
|
+
),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__title", children: new Intl.DateTimeFormat("en-US", {
|
|
1401
|
+
month: "long",
|
|
1402
|
+
year: "numeric"
|
|
1403
|
+
}).format(calendarMonth) }),
|
|
1404
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1405
|
+
"button",
|
|
1406
|
+
{
|
|
1407
|
+
type: "button",
|
|
1408
|
+
className: "idk-button idk-button--ghost",
|
|
1409
|
+
onClick: handleNextMonth,
|
|
1410
|
+
disabled: Boolean(maxAdvanceMonthStart && calendarMonth >= maxAdvanceMonthStart),
|
|
1411
|
+
children: "Next"
|
|
1412
|
+
}
|
|
1413
|
+
)
|
|
1414
|
+
] }) }),
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__weekdays", children: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((label) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: label }, label)) }),
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__grid", children: calendarDays.map((day) => {
|
|
1417
|
+
const entry = availabilityByDate.get(day.date);
|
|
1418
|
+
const hasAvailable = entry?.slots?.some((slot) => slot.available) ?? false;
|
|
1419
|
+
const dateValue = parseDateOnly(day.date);
|
|
1420
|
+
const isPast = dateValue ? dateValue < todayDate : false;
|
|
1421
|
+
const isBeyondMax = maxAdvanceDate ? dateValue ? dateValue > maxAdvanceDate : false : false;
|
|
1422
|
+
const weekday = dateValue ? dateValue.getDay() : null;
|
|
1423
|
+
const isDisabledWeekday = weekday !== null ? disabledWeekdaysSet.has(weekday) : false;
|
|
1424
|
+
const isBlocked = Boolean(entry) && !hasAvailable;
|
|
1425
|
+
const isDisabled = !entry || isPast || isBeyondMax || isBlocked || isDisabledWeekday;
|
|
1426
|
+
const isActive = selectedDate === day.date;
|
|
1427
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1428
|
+
"button",
|
|
1429
|
+
{
|
|
1430
|
+
type: "button",
|
|
1431
|
+
className: [
|
|
1432
|
+
"idk-calendar__day",
|
|
1433
|
+
day.isCurrentMonth ? "" : "is-muted",
|
|
1434
|
+
hasAvailable ? "is-available" : "",
|
|
1435
|
+
isBlocked ? "is-blocked" : "",
|
|
1436
|
+
isDisabledWeekday ? "is-disabled" : "",
|
|
1437
|
+
isActive ? "is-active" : ""
|
|
1438
|
+
].filter(Boolean).join(" "),
|
|
1439
|
+
disabled: isDisabled,
|
|
1440
|
+
onClick: () => {
|
|
1441
|
+
setSelectedDate(day.date);
|
|
1442
|
+
setSelectedTime(null);
|
|
1443
|
+
setSelectedEndTime(null);
|
|
1444
|
+
setBookingError(null);
|
|
1445
|
+
},
|
|
1446
|
+
children: [
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: day.date.split("-")[2] }),
|
|
1448
|
+
showFullyBookedLabel && isBlocked && day.isCurrentMonth ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-calendar__label", children: calendarVariant === "compact" ? "\u2022" : "Fully booked" }) : null
|
|
1449
|
+
]
|
|
1450
|
+
},
|
|
1451
|
+
day.date
|
|
1452
|
+
);
|
|
1453
|
+
}) }),
|
|
1454
|
+
showFullyBookedLabel && calendarVariant === "compact" && hasBlockedInCalendarView ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-calendar__legend", children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-calendar__legend-dot", children: "\u2022" }),
|
|
1456
|
+
" Fully booked"
|
|
1457
|
+
] }) : null
|
|
1458
|
+
]
|
|
1459
|
+
}
|
|
1460
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1461
|
+
enableDatePaging ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-availability__nav", children: [
|
|
1462
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1463
|
+
"button",
|
|
1464
|
+
{
|
|
1465
|
+
type: "button",
|
|
1466
|
+
className: "idk-button idk-button--ghost",
|
|
1467
|
+
onClick: handlePrevDates,
|
|
1468
|
+
disabled: availabilityStartDate <= todayString,
|
|
1469
|
+
children: "Previous"
|
|
1470
|
+
}
|
|
1471
|
+
),
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1473
|
+
"button",
|
|
1474
|
+
{
|
|
1475
|
+
type: "button",
|
|
1476
|
+
className: "idk-button idk-button--ghost",
|
|
1477
|
+
onClick: handleNextDates,
|
|
1478
|
+
children: "Next"
|
|
1479
|
+
}
|
|
1480
|
+
)
|
|
1481
|
+
] }) : null,
|
|
1482
|
+
availability.data.dates.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1483
|
+
"button",
|
|
1484
|
+
{
|
|
1485
|
+
type: "button",
|
|
1486
|
+
className: entry.date === selectedDate ? "is-active" : void 0,
|
|
1487
|
+
onClick: () => {
|
|
1488
|
+
setSelectedDate(entry.date);
|
|
1489
|
+
setSelectedTime(null);
|
|
1490
|
+
setSelectedEndTime(null);
|
|
1491
|
+
setBookingError(null);
|
|
1492
|
+
},
|
|
1493
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-date-chip__day", children: formatDateLabel(entry.date) })
|
|
1111
1494
|
},
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1119
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "idk-availability__panel-subtitle", children: timeZoneLabel })
|
|
1495
|
+
entry.date
|
|
1496
|
+
))
|
|
1497
|
+
] }) }),
|
|
1498
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-availability__panel", children: [
|
|
1499
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__panel-header", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__panel-title", children: selectedDate ? formatDateHeading(selectedDate) : availability.data.dates[0]?.date ? formatDateHeading(availability.data.dates[0].date) : "Select a date" }),
|
|
1501
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__panel-subtitle", children: timeZoneLabel })
|
|
1120
1502
|
] }) }),
|
|
1121
|
-
/* @__PURE__ */ (0,
|
|
1122
|
-
const activeEntry = availability.data.dates.find((entry) => entry.date === selectedDate)
|
|
1123
|
-
if (!activeEntry) return /* @__PURE__ */ (0,
|
|
1503
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__slots", children: (() => {
|
|
1504
|
+
const activeEntry = selectedDate ? availability.data.dates.find((entry) => entry.date === selectedDate) : availability.data.dates[0];
|
|
1505
|
+
if (!activeEntry) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "Select a date to see times." });
|
|
1124
1506
|
const slots = (activeEntry.slots || []).filter((slot) => slot.available);
|
|
1125
1507
|
if (slots.length === 0) {
|
|
1126
|
-
return /* @__PURE__ */ (0,
|
|
1508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No available times for this date." });
|
|
1127
1509
|
}
|
|
1128
|
-
return slots.map((slot) => /* @__PURE__ */ (0,
|
|
1510
|
+
return slots.map((slot, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1129
1511
|
"button",
|
|
1130
1512
|
{
|
|
1131
1513
|
type: "button",
|
|
@@ -1143,12 +1525,12 @@ function BookingWidget({
|
|
|
1143
1525
|
},
|
|
1144
1526
|
children: formatTimeLabel(slot.time)
|
|
1145
1527
|
},
|
|
1146
|
-
`${slot.time}-${slot.endTime}`
|
|
1528
|
+
`${activeEntry.date}-${slot.time}-${slot.endTime}-${index}`
|
|
1147
1529
|
));
|
|
1148
1530
|
})() })
|
|
1149
1531
|
] })
|
|
1150
|
-
] }) : /* @__PURE__ */ (0,
|
|
1151
|
-
!autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1532
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No availability found." }),
|
|
1533
|
+
!autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__actions", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1152
1534
|
"button",
|
|
1153
1535
|
{
|
|
1154
1536
|
type: "button",
|
|
@@ -1159,37 +1541,37 @@ function BookingWidget({
|
|
|
1159
1541
|
}
|
|
1160
1542
|
) }) : null
|
|
1161
1543
|
] }),
|
|
1162
|
-
step === "details" && /* @__PURE__ */ (0,
|
|
1163
|
-
/* @__PURE__ */ (0,
|
|
1164
|
-
bookingError ? /* @__PURE__ */ (0,
|
|
1165
|
-
selectedService && selectedTime ? /* @__PURE__ */ (0,
|
|
1166
|
-
/* @__PURE__ */ (0,
|
|
1167
|
-
/* @__PURE__ */ (0,
|
|
1168
|
-
/* @__PURE__ */ (0,
|
|
1544
|
+
step === "details" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { className: "idk-form", onSubmit: handleSubmit, children: [
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Your details" }),
|
|
1546
|
+
bookingError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__error", children: bookingError }) : null,
|
|
1547
|
+
selectedService && selectedTime ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__summary", children: [
|
|
1548
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Service" }),
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: selectedService.name })
|
|
1169
1551
|
] }),
|
|
1170
|
-
selectedStaff ? /* @__PURE__ */ (0,
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1172
|
-
/* @__PURE__ */ (0,
|
|
1552
|
+
selectedStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1553
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Staff" }),
|
|
1554
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: selectedStaff.name })
|
|
1173
1555
|
] }) : null,
|
|
1174
|
-
/* @__PURE__ */ (0,
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1557
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "When" }),
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
|
|
1177
1559
|
formatDateHeading(selectedDate || ""),
|
|
1178
1560
|
" \xB7 ",
|
|
1179
1561
|
formatTimeLabel(selectedTime)
|
|
1180
1562
|
] })
|
|
1181
1563
|
] }),
|
|
1182
|
-
selectedService.price ? /* @__PURE__ */ (0,
|
|
1183
|
-
/* @__PURE__ */ (0,
|
|
1184
|
-
/* @__PURE__ */ (0,
|
|
1564
|
+
selectedService.price ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Price" }),
|
|
1566
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
|
|
1185
1567
|
"$",
|
|
1186
1568
|
(selectedService.price / 100).toFixed(2)
|
|
1187
1569
|
] })
|
|
1188
1570
|
] }) : null
|
|
1189
1571
|
] }) : null,
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1191
|
-
/* @__PURE__ */ (0,
|
|
1192
|
-
/* @__PURE__ */ (0,
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Name" }),
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1193
1575
|
"input",
|
|
1194
1576
|
{
|
|
1195
1577
|
value: details.name,
|
|
@@ -1198,9 +1580,9 @@ function BookingWidget({
|
|
|
1198
1580
|
}
|
|
1199
1581
|
)
|
|
1200
1582
|
] }),
|
|
1201
|
-
/* @__PURE__ */ (0,
|
|
1202
|
-
/* @__PURE__ */ (0,
|
|
1203
|
-
/* @__PURE__ */ (0,
|
|
1583
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1584
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Email" }),
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1204
1586
|
"input",
|
|
1205
1587
|
{
|
|
1206
1588
|
type: "email",
|
|
@@ -1210,9 +1592,9 @@ function BookingWidget({
|
|
|
1210
1592
|
}
|
|
1211
1593
|
)
|
|
1212
1594
|
] }),
|
|
1213
|
-
/* @__PURE__ */ (0,
|
|
1214
|
-
/* @__PURE__ */ (0,
|
|
1215
|
-
/* @__PURE__ */ (0,
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1596
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Phone" }),
|
|
1597
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1216
1598
|
"input",
|
|
1217
1599
|
{
|
|
1218
1600
|
value: details.phone,
|
|
@@ -1220,9 +1602,9 @@ function BookingWidget({
|
|
|
1220
1602
|
}
|
|
1221
1603
|
)
|
|
1222
1604
|
] }),
|
|
1223
|
-
/* @__PURE__ */ (0,
|
|
1224
|
-
/* @__PURE__ */ (0,
|
|
1225
|
-
/* @__PURE__ */ (0,
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Notes" }),
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1226
1608
|
"textarea",
|
|
1227
1609
|
{
|
|
1228
1610
|
rows: 4,
|
|
@@ -1231,12 +1613,12 @@ function BookingWidget({
|
|
|
1231
1613
|
}
|
|
1232
1614
|
)
|
|
1233
1615
|
] }),
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "submit", className: "idk-button", disabled: createBooking.isPending, children: createBooking.isPending ? "Booking..." : "Confirm booking" })
|
|
1235
1617
|
] }),
|
|
1236
|
-
step === "done" && /* @__PURE__ */ (0,
|
|
1237
|
-
/* @__PURE__ */ (0,
|
|
1238
|
-
/* @__PURE__ */ (0,
|
|
1239
|
-
/* @__PURE__ */ (0,
|
|
1618
|
+
step === "done" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__done", children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__done-title", children: "Booking confirmed!" }),
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-booking__done-text", children: "We'll send a confirmation email shortly with your appointment details." }),
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1240
1622
|
"button",
|
|
1241
1623
|
{
|
|
1242
1624
|
type: "button",
|
|
@@ -1259,7 +1641,7 @@ function BookingWidget({
|
|
|
1259
1641
|
|
|
1260
1642
|
// src/components/AvailabilityPicker.tsx
|
|
1261
1643
|
var import_react8 = require("react");
|
|
1262
|
-
var
|
|
1644
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1263
1645
|
function AvailabilityPicker({
|
|
1264
1646
|
serviceId,
|
|
1265
1647
|
staffId,
|
|
@@ -1277,15 +1659,15 @@ function AvailabilityPicker({
|
|
|
1277
1659
|
days
|
|
1278
1660
|
});
|
|
1279
1661
|
if (isLoading) {
|
|
1280
|
-
return /* @__PURE__ */ (0,
|
|
1662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-state", children: "Loading availability..." });
|
|
1281
1663
|
}
|
|
1282
1664
|
if (!data?.dates?.length) {
|
|
1283
|
-
return /* @__PURE__ */ (0,
|
|
1665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-state", children: "No availability found." });
|
|
1284
1666
|
}
|
|
1285
1667
|
const activeDate = selectedDate || data.dates[0]?.date;
|
|
1286
1668
|
const activeSlots = data.dates.find((entry) => entry.date === activeDate)?.slots || [];
|
|
1287
|
-
return /* @__PURE__ */ (0,
|
|
1288
|
-
/* @__PURE__ */ (0,
|
|
1669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: ["idk-availability", className].filter(Boolean).join(" "), children: [
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-availability__dates", children: data.dates.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1289
1671
|
"button",
|
|
1290
1672
|
{
|
|
1291
1673
|
type: "button",
|
|
@@ -1298,7 +1680,7 @@ function AvailabilityPicker({
|
|
|
1298
1680
|
},
|
|
1299
1681
|
entry.date
|
|
1300
1682
|
)) }),
|
|
1301
|
-
/* @__PURE__ */ (0,
|
|
1683
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-availability__slots", children: activeSlots.filter((slot) => slot.available).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-state", children: "No slots available." }) : activeSlots.filter((slot) => slot.available).map((slot) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1302
1684
|
"button",
|
|
1303
1685
|
{
|
|
1304
1686
|
type: "button",
|
|
@@ -1321,22 +1703,22 @@ function AvailabilityPicker({
|
|
|
1321
1703
|
}
|
|
1322
1704
|
|
|
1323
1705
|
// src/components/ServicePicker.tsx
|
|
1324
|
-
var
|
|
1706
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1325
1707
|
function ServicePicker({
|
|
1326
1708
|
services,
|
|
1327
1709
|
selectedId,
|
|
1328
1710
|
onSelect,
|
|
1329
1711
|
className
|
|
1330
1712
|
}) {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
1713
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: ["idk-picker", className].filter(Boolean).join(" "), children: services.map((service) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1332
1714
|
"button",
|
|
1333
1715
|
{
|
|
1334
1716
|
type: "button",
|
|
1335
1717
|
className: selectedId === service.id ? "is-active" : void 0,
|
|
1336
1718
|
onClick: () => onSelect?.(service),
|
|
1337
1719
|
children: [
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1720
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: service.name }),
|
|
1721
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("small", { children: [
|
|
1340
1722
|
service.duration,
|
|
1341
1723
|
" min"
|
|
1342
1724
|
] })
|
|
@@ -1347,22 +1729,22 @@ function ServicePicker({
|
|
|
1347
1729
|
}
|
|
1348
1730
|
|
|
1349
1731
|
// src/components/StaffPicker.tsx
|
|
1350
|
-
var
|
|
1732
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1351
1733
|
function StaffPicker({
|
|
1352
1734
|
staff,
|
|
1353
1735
|
selectedId,
|
|
1354
1736
|
onSelect,
|
|
1355
1737
|
className
|
|
1356
1738
|
}) {
|
|
1357
|
-
return /* @__PURE__ */ (0,
|
|
1739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: ["idk-picker", className].filter(Boolean).join(" "), children: staff.map((member) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1358
1740
|
"button",
|
|
1359
1741
|
{
|
|
1360
1742
|
type: "button",
|
|
1361
1743
|
className: selectedId === member.id ? "is-active" : void 0,
|
|
1362
1744
|
onClick: () => onSelect?.(member),
|
|
1363
1745
|
children: [
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: member.name }),
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { children: member.role || "Staff" })
|
|
1366
1748
|
]
|
|
1367
1749
|
},
|
|
1368
1750
|
member.id
|
|
@@ -1370,14 +1752,14 @@ function StaffPicker({
|
|
|
1370
1752
|
}
|
|
1371
1753
|
|
|
1372
1754
|
// src/components/DatePicker.tsx
|
|
1373
|
-
var
|
|
1755
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1374
1756
|
function DatePicker({
|
|
1375
1757
|
dates,
|
|
1376
1758
|
selectedDate,
|
|
1377
1759
|
onSelect,
|
|
1378
1760
|
className
|
|
1379
1761
|
}) {
|
|
1380
|
-
return /* @__PURE__ */ (0,
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: ["idk-picker", className].filter(Boolean).join(" "), children: dates.map((date) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1381
1763
|
"button",
|
|
1382
1764
|
{
|
|
1383
1765
|
type: "button",
|
|
@@ -1390,14 +1772,14 @@ function DatePicker({
|
|
|
1390
1772
|
}
|
|
1391
1773
|
|
|
1392
1774
|
// src/components/TimePicker.tsx
|
|
1393
|
-
var
|
|
1775
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1394
1776
|
function TimePicker({
|
|
1395
1777
|
slots,
|
|
1396
1778
|
selectedTime,
|
|
1397
1779
|
onSelect,
|
|
1398
1780
|
className
|
|
1399
1781
|
}) {
|
|
1400
|
-
return /* @__PURE__ */ (0,
|
|
1782
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: ["idk-picker", className].filter(Boolean).join(" "), children: slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1401
1783
|
"button",
|
|
1402
1784
|
{
|
|
1403
1785
|
type: "button",
|