@idkwebsites/components 0.1.8 → 0.1.14
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 +494 -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 +447 -137
- package/dist/index.js.map +1 -1
- package/dist/styles.css +119 -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,118 @@ 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 handlePrevDates = () => {
|
|
949
|
+
if (availabilityStartDate <= todayString) return;
|
|
950
|
+
setAvailabilityStartDate((prev) => addDays(prev, -availabilityDays));
|
|
951
|
+
setSelectedDate(null);
|
|
952
|
+
setSelectedTime(null);
|
|
953
|
+
setSelectedEndTime(null);
|
|
954
|
+
setBookingError(null);
|
|
955
|
+
};
|
|
956
|
+
const handleNextDates = () => {
|
|
957
|
+
if (maxAdvanceDate) {
|
|
958
|
+
const nextStart = parseDateOnly(addDays(availabilityStartDate, availabilityDays));
|
|
959
|
+
if (nextStart && nextStart > maxAdvanceDate) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
setAvailabilityStartDate((prev) => addDays(prev, availabilityDays));
|
|
964
|
+
setSelectedDate(null);
|
|
965
|
+
setSelectedTime(null);
|
|
966
|
+
setSelectedEndTime(null);
|
|
967
|
+
setBookingError(null);
|
|
968
|
+
};
|
|
969
|
+
const handlePrevMonth = () => {
|
|
970
|
+
setCalendarMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1));
|
|
971
|
+
setSelectedDate(null);
|
|
972
|
+
setSelectedTime(null);
|
|
973
|
+
setSelectedEndTime(null);
|
|
974
|
+
setBookingError(null);
|
|
975
|
+
};
|
|
976
|
+
const handleNextMonth = () => {
|
|
977
|
+
if (maxAdvanceMonthStart) {
|
|
978
|
+
const nextMonth = new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() + 1, 1);
|
|
979
|
+
if (nextMonth > maxAdvanceMonthStart) return;
|
|
980
|
+
}
|
|
981
|
+
setCalendarMonth((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1));
|
|
982
|
+
setSelectedDate(null);
|
|
983
|
+
setSelectedTime(null);
|
|
984
|
+
setSelectedEndTime(null);
|
|
985
|
+
setBookingError(null);
|
|
986
|
+
};
|
|
987
|
+
(0, import_react7.useEffect)(() => {
|
|
988
|
+
if (step !== "time") return;
|
|
989
|
+
if (!availability.data?.dates?.length) return;
|
|
990
|
+
const matches = selectedDate ? availability.data.dates.some((entry) => entry.date === selectedDate) : false;
|
|
991
|
+
if (matches) return;
|
|
992
|
+
setSelectedDate(availability.data.dates[0].date);
|
|
993
|
+
}, [step, availability.data, selectedDate]);
|
|
994
|
+
(0, import_react7.useEffect)(() => {
|
|
995
|
+
if (!selectedService) return;
|
|
996
|
+
if (datePickerMode === "calendar") {
|
|
997
|
+
const now = /* @__PURE__ */ new Date();
|
|
998
|
+
setCalendarMonth(new Date(now.getFullYear(), now.getMonth(), 1));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
setAvailabilityStartDate((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
1002
|
+
setAvailabilityDays(Math.max(1, availabilityDaysProp));
|
|
1003
|
+
}, [selectedService?.id, selectedStaff?.id, availabilityDaysProp, datePickerMode]);
|
|
1004
|
+
(0, import_react7.useEffect)(() => {
|
|
1005
|
+
if (datePickerMode !== "calendar") return;
|
|
1006
|
+
const start = getMonthStart(calendarMonth);
|
|
1007
|
+
const end = getMonthEnd(calendarMonth);
|
|
1008
|
+
const startString = start.toISOString().slice(0, 10);
|
|
1009
|
+
const daysInMonth = end.getDate();
|
|
1010
|
+
setAvailabilityStartDate(startString);
|
|
1011
|
+
setAvailabilityDays(daysInMonth);
|
|
1012
|
+
}, [calendarMonth, datePickerMode, getMonthEnd, getMonthStart]);
|
|
813
1013
|
const handleBack = () => {
|
|
814
1014
|
if (step === "service") return;
|
|
815
1015
|
if (step === "staff") {
|
|
@@ -879,32 +1079,32 @@ function BookingWidget({
|
|
|
879
1079
|
};
|
|
880
1080
|
const isServicesLoading = services ? false : servicesLoading;
|
|
881
1081
|
if (isServicesLoading) {
|
|
882
|
-
return /* @__PURE__ */ (0,
|
|
1082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "Loading booking options..." });
|
|
883
1083
|
}
|
|
884
1084
|
if (!servicesList.length) {
|
|
885
|
-
return /* @__PURE__ */ (0,
|
|
1085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No services available." });
|
|
886
1086
|
}
|
|
887
|
-
return /* @__PURE__ */ (0,
|
|
1087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
888
1088
|
"div",
|
|
889
1089
|
{
|
|
890
1090
|
ref: widgetRef,
|
|
891
1091
|
className: ["idk-booking", className].filter(Boolean).join(" "),
|
|
892
1092
|
children: [
|
|
893
|
-
/* @__PURE__ */ (0,
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
/* @__PURE__ */ (0,
|
|
896
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
1093
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__header", children: [
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__title-wrap", children: [
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "idk-booking__title", children: title }),
|
|
1096
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-booking__subtitle", children: subtitle }) : null
|
|
897
1097
|
] }),
|
|
898
|
-
step !== "service" && step !== "done" ? /* @__PURE__ */ (0,
|
|
1098
|
+
step !== "service" && step !== "done" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "idk-link", onClick: handleBack, children: "Back" }) : null
|
|
899
1099
|
] }),
|
|
900
|
-
step !== "done" ? /* @__PURE__ */ (0,
|
|
901
|
-
/* @__PURE__ */ (0,
|
|
1100
|
+
step !== "done" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__progress", children: [
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
|
|
902
1102
|
"Step ",
|
|
903
1103
|
stepNumber,
|
|
904
1104
|
" of ",
|
|
905
1105
|
totalSteps
|
|
906
1106
|
] }),
|
|
907
|
-
/* @__PURE__ */ (0,
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__bar", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
908
1108
|
"div",
|
|
909
1109
|
{
|
|
910
1110
|
className: "idk-booking__bar-fill",
|
|
@@ -912,10 +1112,10 @@ function BookingWidget({
|
|
|
912
1112
|
}
|
|
913
1113
|
) })
|
|
914
1114
|
] }) : null,
|
|
915
|
-
step === "service" && /* @__PURE__ */ (0,
|
|
916
|
-
/* @__PURE__ */ (0,
|
|
917
|
-
enableServiceSearch || enableCategoryFilter ? /* @__PURE__ */ (0,
|
|
918
|
-
enableServiceSearch ? /* @__PURE__ */ (0,
|
|
1115
|
+
step === "service" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a service" }),
|
|
1117
|
+
enableServiceSearch || enableCategoryFilter ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__filters", children: [
|
|
1118
|
+
enableServiceSearch ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
919
1119
|
"input",
|
|
920
1120
|
{
|
|
921
1121
|
type: "search",
|
|
@@ -924,19 +1124,19 @@ function BookingWidget({
|
|
|
924
1124
|
placeholder: serviceSearchPlaceholder
|
|
925
1125
|
}
|
|
926
1126
|
) : null,
|
|
927
|
-
enableCategoryFilter && categories.length > 0 ? /* @__PURE__ */ (0,
|
|
1127
|
+
enableCategoryFilter && categories.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
928
1128
|
"select",
|
|
929
1129
|
{
|
|
930
1130
|
value: categoryFilter,
|
|
931
1131
|
onChange: (event) => setCategoryFilter(event.target.value),
|
|
932
1132
|
children: [
|
|
933
|
-
/* @__PURE__ */ (0,
|
|
934
|
-
categories.map((category) => /* @__PURE__ */ (0,
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "all", children: categoryLabel }),
|
|
1134
|
+
categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: category, children: category }, category))
|
|
935
1135
|
]
|
|
936
1136
|
}
|
|
937
1137
|
) : null
|
|
938
1138
|
] }) : null,
|
|
939
|
-
filteredServices.length === 0 ? /* @__PURE__ */ (0,
|
|
1139
|
+
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
1140
|
"div",
|
|
941
1141
|
{
|
|
942
1142
|
className: [
|
|
@@ -949,7 +1149,7 @@ function BookingWidget({
|
|
|
949
1149
|
},
|
|
950
1150
|
children: pagedServices.map((service) => {
|
|
951
1151
|
const isSelected = selectedService?.id === service.id;
|
|
952
|
-
return /* @__PURE__ */ (0,
|
|
1152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
953
1153
|
"button",
|
|
954
1154
|
{
|
|
955
1155
|
type: "button",
|
|
@@ -967,20 +1167,20 @@ function BookingWidget({
|
|
|
967
1167
|
}
|
|
968
1168
|
},
|
|
969
1169
|
children: [
|
|
970
|
-
/* @__PURE__ */ (0,
|
|
971
|
-
/* @__PURE__ */ (0,
|
|
972
|
-
/* @__PURE__ */ (0,
|
|
973
|
-
isSelected ? /* @__PURE__ */ (0,
|
|
974
|
-
typeof service.price === "number" && service.price > 0 ? /* @__PURE__ */ (0,
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__header", children: [
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: service.name }),
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "idk-card__aside", children: [
|
|
1173
|
+
isSelected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__check", children: "\u2713" }) : null,
|
|
1174
|
+
typeof service.price === "number" && service.price > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "idk-card__price", children: [
|
|
975
1175
|
"$",
|
|
976
1176
|
(service.price / 100).toFixed(2)
|
|
977
1177
|
] }) : null
|
|
978
1178
|
] })
|
|
979
1179
|
] }),
|
|
980
|
-
service.description ? /* @__PURE__ */ (0,
|
|
981
|
-
/* @__PURE__ */ (0,
|
|
982
|
-
/* @__PURE__ */ (0,
|
|
983
|
-
service.category ? /* @__PURE__ */ (0,
|
|
1180
|
+
service.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-card__description", children: service.description }) : null,
|
|
1181
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__meta", children: [
|
|
1182
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: formatDuration(service.duration) }),
|
|
1183
|
+
service.category ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-pill", children: service.category }) : null
|
|
984
1184
|
] })
|
|
985
1185
|
]
|
|
986
1186
|
},
|
|
@@ -989,8 +1189,8 @@ function BookingWidget({
|
|
|
989
1189
|
})
|
|
990
1190
|
}
|
|
991
1191
|
),
|
|
992
|
-
/* @__PURE__ */ (0,
|
|
993
|
-
shouldPaginate ? /* @__PURE__ */ (0,
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__actions", children: [
|
|
1193
|
+
shouldPaginate ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
994
1194
|
"button",
|
|
995
1195
|
{
|
|
996
1196
|
type: "button",
|
|
@@ -1000,12 +1200,12 @@ function BookingWidget({
|
|
|
1000
1200
|
children: hasMoreServices ? "Show more services" : "All services shown"
|
|
1001
1201
|
}
|
|
1002
1202
|
) : null,
|
|
1003
|
-
selectedService && !autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1203
|
+
selectedService && !autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "idk-button", onClick: handleServiceContinue, children: "Continue" }) : null
|
|
1004
1204
|
] })
|
|
1005
1205
|
] }),
|
|
1006
|
-
step === "staff" && /* @__PURE__ */ (0,
|
|
1007
|
-
/* @__PURE__ */ (0,
|
|
1008
|
-
staffOptions.length === 0 ? /* @__PURE__ */ (0,
|
|
1206
|
+
step === "staff" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a team member" }),
|
|
1208
|
+
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
1209
|
"div",
|
|
1010
1210
|
{
|
|
1011
1211
|
className: [
|
|
@@ -1014,7 +1214,7 @@ function BookingWidget({
|
|
|
1014
1214
|
].join(" "),
|
|
1015
1215
|
style: staffLayout === "grid" ? { gridTemplateColumns: `repeat(${Math.max(1, staffColumns)}, minmax(0, 1fr))` } : void 0,
|
|
1016
1216
|
children: [
|
|
1017
|
-
showAnyStaffOption && canSkipStaff ? /* @__PURE__ */ (0,
|
|
1217
|
+
showAnyStaffOption && canSkipStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1018
1218
|
"button",
|
|
1019
1219
|
{
|
|
1020
1220
|
type: "button",
|
|
@@ -1030,16 +1230,16 @@ function BookingWidget({
|
|
|
1030
1230
|
}
|
|
1031
1231
|
},
|
|
1032
1232
|
children: [
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1034
|
-
/* @__PURE__ */ (0,
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-card__header", children: [
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: "Any Available" }),
|
|
1235
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__badge", children: "Recommended" })
|
|
1036
1236
|
] }),
|
|
1037
|
-
/* @__PURE__ */ (0,
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-card__description", children: "We'll match you with the first available stylist." })
|
|
1038
1238
|
]
|
|
1039
1239
|
},
|
|
1040
1240
|
"any-staff"
|
|
1041
1241
|
) : null,
|
|
1042
|
-
|
|
1242
|
+
pagedStaff.map((staff) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1043
1243
|
"button",
|
|
1044
1244
|
{
|
|
1045
1245
|
type: "button",
|
|
@@ -1055,12 +1255,12 @@ function BookingWidget({
|
|
|
1055
1255
|
scrollToTop();
|
|
1056
1256
|
}
|
|
1057
1257
|
},
|
|
1058
|
-
children: /* @__PURE__ */ (0,
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1061
|
-
/* @__PURE__ */ (0,
|
|
1062
|
-
/* @__PURE__ */ (0,
|
|
1063
|
-
staff.bio ? /* @__PURE__ */ (0,
|
|
1258
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-team__card", children: [
|
|
1259
|
+
/* @__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() }) }),
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1261
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__title", children: staff.name }),
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-card__meta", children: staff.role || "Staff" }),
|
|
1263
|
+
staff.bio ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-card__description", children: renderLinkedText(staff.bio) }) : null
|
|
1064
1264
|
] })
|
|
1065
1265
|
] })
|
|
1066
1266
|
},
|
|
@@ -1069,8 +1269,18 @@ function BookingWidget({
|
|
|
1069
1269
|
]
|
|
1070
1270
|
}
|
|
1071
1271
|
),
|
|
1072
|
-
/* @__PURE__ */ (0,
|
|
1073
|
-
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__actions", children: [
|
|
1273
|
+
shouldPaginateStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1274
|
+
"button",
|
|
1275
|
+
{
|
|
1276
|
+
type: "button",
|
|
1277
|
+
className: "idk-button idk-button--ghost",
|
|
1278
|
+
onClick: () => setStaffPage((prev) => hasMoreStaff ? prev + 1 : 1),
|
|
1279
|
+
disabled: !hasMoreStaff && staffPage === 1,
|
|
1280
|
+
children: hasMoreStaff ? "Show more staff" : staffPage > 1 ? "Show fewer staff" : "All staff shown"
|
|
1281
|
+
}
|
|
1282
|
+
) : null,
|
|
1283
|
+
canSkipStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1074
1284
|
"button",
|
|
1075
1285
|
{
|
|
1076
1286
|
type: "button",
|
|
@@ -1083,7 +1293,7 @@ function BookingWidget({
|
|
|
1083
1293
|
children: "Continue without selecting"
|
|
1084
1294
|
}
|
|
1085
1295
|
) : null,
|
|
1086
|
-
!autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1296
|
+
!autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1087
1297
|
"button",
|
|
1088
1298
|
{
|
|
1089
1299
|
type: "button",
|
|
@@ -1095,37 +1305,137 @@ function BookingWidget({
|
|
|
1095
1305
|
) : null
|
|
1096
1306
|
] })
|
|
1097
1307
|
] }),
|
|
1098
|
-
step === "time" && /* @__PURE__ */ (0,
|
|
1099
|
-
/* @__PURE__ */ (0,
|
|
1100
|
-
availability.isLoading ? /* @__PURE__ */ (0,
|
|
1101
|
-
/* @__PURE__ */ (0,
|
|
1102
|
-
"
|
|
1308
|
+
step === "time" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__step", children: [
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Select a time" }),
|
|
1310
|
+
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: [
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__dates", children: datePickerMode === "calendar" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1312
|
+
"div",
|
|
1103
1313
|
{
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1314
|
+
className: [
|
|
1315
|
+
"idk-calendar",
|
|
1316
|
+
calendarVariant === "compact" ? "idk-calendar--compact" : ""
|
|
1317
|
+
].filter(Boolean).join(" "),
|
|
1318
|
+
children: [
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-calendar__header", children: [
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1321
|
+
"button",
|
|
1322
|
+
{
|
|
1323
|
+
type: "button",
|
|
1324
|
+
className: "idk-button idk-button--ghost",
|
|
1325
|
+
onClick: handlePrevMonth,
|
|
1326
|
+
disabled: calendarMonth <= getMonthStart(todayDate),
|
|
1327
|
+
children: "Previous"
|
|
1328
|
+
}
|
|
1329
|
+
),
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__title", children: new Intl.DateTimeFormat("en-US", {
|
|
1331
|
+
month: "long",
|
|
1332
|
+
year: "numeric"
|
|
1333
|
+
}).format(calendarMonth) }),
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1335
|
+
"button",
|
|
1336
|
+
{
|
|
1337
|
+
type: "button",
|
|
1338
|
+
className: "idk-button idk-button--ghost",
|
|
1339
|
+
onClick: handleNextMonth,
|
|
1340
|
+
disabled: Boolean(maxAdvanceMonthStart && calendarMonth >= maxAdvanceMonthStart),
|
|
1341
|
+
children: "Next"
|
|
1342
|
+
}
|
|
1343
|
+
)
|
|
1344
|
+
] }),
|
|
1345
|
+
/* @__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)) }),
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-calendar__grid", children: getMonthDays(calendarMonth).map((day) => {
|
|
1347
|
+
const entry = availability.data?.dates?.find(
|
|
1348
|
+
(item) => item.date === day.date
|
|
1349
|
+
);
|
|
1350
|
+
const hasAvailable = entry?.slots?.some((slot) => slot.available) ?? false;
|
|
1351
|
+
const dateValue = parseDateOnly(day.date);
|
|
1352
|
+
const isPast = dateValue ? dateValue < todayDate : false;
|
|
1353
|
+
const isBeyondMax = maxAdvanceDate ? dateValue ? dateValue > maxAdvanceDate : false : false;
|
|
1354
|
+
const weekday = dateValue ? dateValue.getDay() : null;
|
|
1355
|
+
const isDisabledWeekday = weekday !== null ? disabledWeekdaysSet.has(weekday) : false;
|
|
1356
|
+
const isBlocked = Boolean(entry) && !hasAvailable;
|
|
1357
|
+
const isDisabled = !entry || isPast || isBeyondMax || isBlocked || isDisabledWeekday;
|
|
1358
|
+
const isActive = selectedDate === day.date;
|
|
1359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1360
|
+
"button",
|
|
1361
|
+
{
|
|
1362
|
+
type: "button",
|
|
1363
|
+
className: [
|
|
1364
|
+
"idk-calendar__day",
|
|
1365
|
+
day.isCurrentMonth ? "" : "is-muted",
|
|
1366
|
+
hasAvailable ? "is-available" : "",
|
|
1367
|
+
isBlocked ? "is-blocked" : "",
|
|
1368
|
+
isDisabledWeekday ? "is-disabled" : "",
|
|
1369
|
+
isActive ? "is-active" : ""
|
|
1370
|
+
].filter(Boolean).join(" "),
|
|
1371
|
+
disabled: isDisabled,
|
|
1372
|
+
onClick: () => {
|
|
1373
|
+
setSelectedDate(day.date);
|
|
1374
|
+
setSelectedTime(null);
|
|
1375
|
+
setSelectedEndTime(null);
|
|
1376
|
+
setBookingError(null);
|
|
1377
|
+
},
|
|
1378
|
+
children: [
|
|
1379
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: day.date.split("-")[2] }),
|
|
1380
|
+
showFullyBookedLabel && isBlocked && day.isCurrentMonth ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-calendar__label", children: calendarVariant === "compact" ? "Full" : "Fully booked" }) : null
|
|
1381
|
+
]
|
|
1382
|
+
},
|
|
1383
|
+
day.date
|
|
1384
|
+
);
|
|
1385
|
+
}) })
|
|
1386
|
+
]
|
|
1387
|
+
}
|
|
1388
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1389
|
+
enableDatePaging ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-availability__nav", children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1391
|
+
"button",
|
|
1392
|
+
{
|
|
1393
|
+
type: "button",
|
|
1394
|
+
className: "idk-button idk-button--ghost",
|
|
1395
|
+
onClick: handlePrevDates,
|
|
1396
|
+
disabled: availabilityStartDate <= todayString,
|
|
1397
|
+
children: "Previous"
|
|
1398
|
+
}
|
|
1399
|
+
),
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1401
|
+
"button",
|
|
1402
|
+
{
|
|
1403
|
+
type: "button",
|
|
1404
|
+
className: "idk-button idk-button--ghost",
|
|
1405
|
+
onClick: handleNextDates,
|
|
1406
|
+
children: "Next"
|
|
1407
|
+
}
|
|
1408
|
+
)
|
|
1409
|
+
] }) : null,
|
|
1410
|
+
availability.data.dates.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1411
|
+
"button",
|
|
1412
|
+
{
|
|
1413
|
+
type: "button",
|
|
1414
|
+
className: entry.date === selectedDate ? "is-active" : void 0,
|
|
1415
|
+
onClick: () => {
|
|
1416
|
+
setSelectedDate(entry.date);
|
|
1417
|
+
setSelectedTime(null);
|
|
1418
|
+
setSelectedEndTime(null);
|
|
1419
|
+
setBookingError(null);
|
|
1420
|
+
},
|
|
1421
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-date-chip__day", children: formatDateLabel(entry.date) })
|
|
1111
1422
|
},
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1119
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "idk-availability__panel-subtitle", children: timeZoneLabel })
|
|
1423
|
+
entry.date
|
|
1424
|
+
))
|
|
1425
|
+
] }) }),
|
|
1426
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-availability__panel", children: [
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__panel-header", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1428
|
+
/* @__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" }),
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__panel-subtitle", children: timeZoneLabel })
|
|
1120
1430
|
] }) }),
|
|
1121
|
-
/* @__PURE__ */ (0,
|
|
1122
|
-
const activeEntry = availability.data.dates.find((entry) => entry.date === selectedDate)
|
|
1123
|
-
if (!activeEntry) return /* @__PURE__ */ (0,
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-availability__slots", children: (() => {
|
|
1432
|
+
const activeEntry = selectedDate ? availability.data.dates.find((entry) => entry.date === selectedDate) : availability.data.dates[0];
|
|
1433
|
+
if (!activeEntry) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "Select a date to see times." });
|
|
1124
1434
|
const slots = (activeEntry.slots || []).filter((slot) => slot.available);
|
|
1125
1435
|
if (slots.length === 0) {
|
|
1126
|
-
return /* @__PURE__ */ (0,
|
|
1436
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No available times for this date." });
|
|
1127
1437
|
}
|
|
1128
|
-
return slots.map((slot) => /* @__PURE__ */ (0,
|
|
1438
|
+
return slots.map((slot, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1129
1439
|
"button",
|
|
1130
1440
|
{
|
|
1131
1441
|
type: "button",
|
|
@@ -1143,12 +1453,12 @@ function BookingWidget({
|
|
|
1143
1453
|
},
|
|
1144
1454
|
children: formatTimeLabel(slot.time)
|
|
1145
1455
|
},
|
|
1146
|
-
`${slot.time}-${slot.endTime}`
|
|
1456
|
+
`${activeEntry.date}-${slot.time}-${slot.endTime}-${index}`
|
|
1147
1457
|
));
|
|
1148
1458
|
})() })
|
|
1149
1459
|
] })
|
|
1150
|
-
] }) : /* @__PURE__ */ (0,
|
|
1151
|
-
!autoAdvanceOnSelect ? /* @__PURE__ */ (0,
|
|
1460
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-state", children: "No availability found." }),
|
|
1461
|
+
!autoAdvanceOnSelect ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__actions", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1152
1462
|
"button",
|
|
1153
1463
|
{
|
|
1154
1464
|
type: "button",
|
|
@@ -1159,37 +1469,37 @@ function BookingWidget({
|
|
|
1159
1469
|
}
|
|
1160
1470
|
) }) : null
|
|
1161
1471
|
] }),
|
|
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,
|
|
1472
|
+
step === "details" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { className: "idk-form", onSubmit: handleSubmit, children: [
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h4", { children: "Your details" }),
|
|
1474
|
+
bookingError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__error", children: bookingError }) : null,
|
|
1475
|
+
selectedService && selectedTime ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__summary", children: [
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Service" }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: selectedService.name })
|
|
1169
1479
|
] }),
|
|
1170
|
-
selectedStaff ? /* @__PURE__ */ (0,
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1172
|
-
/* @__PURE__ */ (0,
|
|
1480
|
+
selectedStaff ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Staff" }),
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: selectedStaff.name })
|
|
1173
1483
|
] }) : null,
|
|
1174
|
-
/* @__PURE__ */ (0,
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1485
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "When" }),
|
|
1486
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
|
|
1177
1487
|
formatDateHeading(selectedDate || ""),
|
|
1178
1488
|
" \xB7 ",
|
|
1179
1489
|
formatTimeLabel(selectedTime)
|
|
1180
1490
|
] })
|
|
1181
1491
|
] }),
|
|
1182
|
-
selectedService.price ? /* @__PURE__ */ (0,
|
|
1183
|
-
/* @__PURE__ */ (0,
|
|
1184
|
-
/* @__PURE__ */ (0,
|
|
1492
|
+
selectedService.price ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "idk-booking__summary-label", children: "Price" }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
|
|
1185
1495
|
"$",
|
|
1186
1496
|
(selectedService.price / 100).toFixed(2)
|
|
1187
1497
|
] })
|
|
1188
1498
|
] }) : null
|
|
1189
1499
|
] }) : null,
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1191
|
-
/* @__PURE__ */ (0,
|
|
1192
|
-
/* @__PURE__ */ (0,
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1501
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Name" }),
|
|
1502
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1193
1503
|
"input",
|
|
1194
1504
|
{
|
|
1195
1505
|
value: details.name,
|
|
@@ -1198,9 +1508,9 @@ function BookingWidget({
|
|
|
1198
1508
|
}
|
|
1199
1509
|
)
|
|
1200
1510
|
] }),
|
|
1201
|
-
/* @__PURE__ */ (0,
|
|
1202
|
-
/* @__PURE__ */ (0,
|
|
1203
|
-
/* @__PURE__ */ (0,
|
|
1511
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1512
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Email" }),
|
|
1513
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1204
1514
|
"input",
|
|
1205
1515
|
{
|
|
1206
1516
|
type: "email",
|
|
@@ -1210,9 +1520,9 @@ function BookingWidget({
|
|
|
1210
1520
|
}
|
|
1211
1521
|
)
|
|
1212
1522
|
] }),
|
|
1213
|
-
/* @__PURE__ */ (0,
|
|
1214
|
-
/* @__PURE__ */ (0,
|
|
1215
|
-
/* @__PURE__ */ (0,
|
|
1523
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1524
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Phone" }),
|
|
1525
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1216
1526
|
"input",
|
|
1217
1527
|
{
|
|
1218
1528
|
value: details.phone,
|
|
@@ -1220,9 +1530,9 @@ function BookingWidget({
|
|
|
1220
1530
|
}
|
|
1221
1531
|
)
|
|
1222
1532
|
] }),
|
|
1223
|
-
/* @__PURE__ */ (0,
|
|
1224
|
-
/* @__PURE__ */ (0,
|
|
1225
|
-
/* @__PURE__ */ (0,
|
|
1533
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "idk-form__field", children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Notes" }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1226
1536
|
"textarea",
|
|
1227
1537
|
{
|
|
1228
1538
|
rows: 4,
|
|
@@ -1231,12 +1541,12 @@ function BookingWidget({
|
|
|
1231
1541
|
}
|
|
1232
1542
|
)
|
|
1233
1543
|
] }),
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1544
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "submit", className: "idk-button", disabled: createBooking.isPending, children: createBooking.isPending ? "Booking..." : "Confirm booking" })
|
|
1235
1545
|
] }),
|
|
1236
|
-
step === "done" && /* @__PURE__ */ (0,
|
|
1237
|
-
/* @__PURE__ */ (0,
|
|
1238
|
-
/* @__PURE__ */ (0,
|
|
1239
|
-
/* @__PURE__ */ (0,
|
|
1546
|
+
step === "done" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "idk-booking__done", children: [
|
|
1547
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "idk-booking__done-title", children: "Booking confirmed!" }),
|
|
1548
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "idk-booking__done-text", children: "We'll send a confirmation email shortly with your appointment details." }),
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1240
1550
|
"button",
|
|
1241
1551
|
{
|
|
1242
1552
|
type: "button",
|
|
@@ -1259,7 +1569,7 @@ function BookingWidget({
|
|
|
1259
1569
|
|
|
1260
1570
|
// src/components/AvailabilityPicker.tsx
|
|
1261
1571
|
var import_react8 = require("react");
|
|
1262
|
-
var
|
|
1572
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1263
1573
|
function AvailabilityPicker({
|
|
1264
1574
|
serviceId,
|
|
1265
1575
|
staffId,
|
|
@@ -1277,15 +1587,15 @@ function AvailabilityPicker({
|
|
|
1277
1587
|
days
|
|
1278
1588
|
});
|
|
1279
1589
|
if (isLoading) {
|
|
1280
|
-
return /* @__PURE__ */ (0,
|
|
1590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-state", children: "Loading availability..." });
|
|
1281
1591
|
}
|
|
1282
1592
|
if (!data?.dates?.length) {
|
|
1283
|
-
return /* @__PURE__ */ (0,
|
|
1593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-state", children: "No availability found." });
|
|
1284
1594
|
}
|
|
1285
1595
|
const activeDate = selectedDate || data.dates[0]?.date;
|
|
1286
1596
|
const activeSlots = data.dates.find((entry) => entry.date === activeDate)?.slots || [];
|
|
1287
|
-
return /* @__PURE__ */ (0,
|
|
1288
|
-
/* @__PURE__ */ (0,
|
|
1597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: ["idk-availability", className].filter(Boolean).join(" "), children: [
|
|
1598
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "idk-availability__dates", children: data.dates.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1289
1599
|
"button",
|
|
1290
1600
|
{
|
|
1291
1601
|
type: "button",
|
|
@@ -1298,7 +1608,7 @@ function AvailabilityPicker({
|
|
|
1298
1608
|
},
|
|
1299
1609
|
entry.date
|
|
1300
1610
|
)) }),
|
|
1301
|
-
/* @__PURE__ */ (0,
|
|
1611
|
+
/* @__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
1612
|
"button",
|
|
1303
1613
|
{
|
|
1304
1614
|
type: "button",
|
|
@@ -1321,22 +1631,22 @@ function AvailabilityPicker({
|
|
|
1321
1631
|
}
|
|
1322
1632
|
|
|
1323
1633
|
// src/components/ServicePicker.tsx
|
|
1324
|
-
var
|
|
1634
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1325
1635
|
function ServicePicker({
|
|
1326
1636
|
services,
|
|
1327
1637
|
selectedId,
|
|
1328
1638
|
onSelect,
|
|
1329
1639
|
className
|
|
1330
1640
|
}) {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
1641
|
+
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
1642
|
"button",
|
|
1333
1643
|
{
|
|
1334
1644
|
type: "button",
|
|
1335
1645
|
className: selectedId === service.id ? "is-active" : void 0,
|
|
1336
1646
|
onClick: () => onSelect?.(service),
|
|
1337
1647
|
children: [
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: service.name }),
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("small", { children: [
|
|
1340
1650
|
service.duration,
|
|
1341
1651
|
" min"
|
|
1342
1652
|
] })
|
|
@@ -1347,22 +1657,22 @@ function ServicePicker({
|
|
|
1347
1657
|
}
|
|
1348
1658
|
|
|
1349
1659
|
// src/components/StaffPicker.tsx
|
|
1350
|
-
var
|
|
1660
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1351
1661
|
function StaffPicker({
|
|
1352
1662
|
staff,
|
|
1353
1663
|
selectedId,
|
|
1354
1664
|
onSelect,
|
|
1355
1665
|
className
|
|
1356
1666
|
}) {
|
|
1357
|
-
return /* @__PURE__ */ (0,
|
|
1667
|
+
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
1668
|
"button",
|
|
1359
1669
|
{
|
|
1360
1670
|
type: "button",
|
|
1361
1671
|
className: selectedId === member.id ? "is-active" : void 0,
|
|
1362
1672
|
onClick: () => onSelect?.(member),
|
|
1363
1673
|
children: [
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: member.name }),
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { children: member.role || "Staff" })
|
|
1366
1676
|
]
|
|
1367
1677
|
},
|
|
1368
1678
|
member.id
|
|
@@ -1370,14 +1680,14 @@ function StaffPicker({
|
|
|
1370
1680
|
}
|
|
1371
1681
|
|
|
1372
1682
|
// src/components/DatePicker.tsx
|
|
1373
|
-
var
|
|
1683
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1374
1684
|
function DatePicker({
|
|
1375
1685
|
dates,
|
|
1376
1686
|
selectedDate,
|
|
1377
1687
|
onSelect,
|
|
1378
1688
|
className
|
|
1379
1689
|
}) {
|
|
1380
|
-
return /* @__PURE__ */ (0,
|
|
1690
|
+
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
1691
|
"button",
|
|
1382
1692
|
{
|
|
1383
1693
|
type: "button",
|
|
@@ -1390,14 +1700,14 @@ function DatePicker({
|
|
|
1390
1700
|
}
|
|
1391
1701
|
|
|
1392
1702
|
// src/components/TimePicker.tsx
|
|
1393
|
-
var
|
|
1703
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1394
1704
|
function TimePicker({
|
|
1395
1705
|
slots,
|
|
1396
1706
|
selectedTime,
|
|
1397
1707
|
onSelect,
|
|
1398
1708
|
className
|
|
1399
1709
|
}) {
|
|
1400
|
-
return /* @__PURE__ */ (0,
|
|
1710
|
+
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
1711
|
"button",
|
|
1402
1712
|
{
|
|
1403
1713
|
type: "button",
|