@zorgo/next 1.1.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cli.js +344 -1
  2. package/dist/cli.js.map +1 -0
  3. package/dist/cli.mjs +344 -1
  4. package/dist/cli.mjs.map +1 -0
  5. package/dist/components.d.mts +315 -87
  6. package/dist/components.d.ts +315 -87
  7. package/dist/components.js +1216 -820
  8. package/dist/components.js.map +1 -1
  9. package/dist/components.mjs +1195 -832
  10. package/dist/components.mjs.map +1 -1
  11. package/dist/images.d.mts +36 -0
  12. package/dist/images.d.ts +36 -0
  13. package/dist/images.js +62 -0
  14. package/dist/images.js.map +1 -0
  15. package/dist/images.mjs +32 -0
  16. package/dist/images.mjs.map +1 -0
  17. package/dist/index.d.mts +175 -6
  18. package/dist/index.d.ts +175 -6
  19. package/dist/index.js +162 -1
  20. package/dist/index.js.map +1 -0
  21. package/dist/index.mjs +162 -1
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/item-page.d.mts +151 -0
  24. package/dist/item-page.d.ts +151 -0
  25. package/dist/item-page.js +166 -0
  26. package/dist/item-page.js.map +1 -0
  27. package/dist/item-page.mjs +129 -0
  28. package/dist/item-page.mjs.map +1 -0
  29. package/dist/seo.d.mts +31 -1
  30. package/dist/seo.d.ts +31 -1
  31. package/dist/server.js +541 -1
  32. package/dist/server.js.map +1 -0
  33. package/dist/server.mjs +504 -1
  34. package/dist/server.mjs.map +1 -0
  35. package/dist/slugs.js.map +1 -1
  36. package/dist/slugs.mjs.map +1 -1
  37. package/dist/tree/app/components/ClientItemForm.tsx +7 -0
  38. package/dist/tree/app/components/Header.tsx +3 -0
  39. package/dist/tree/app/components/ModalRegistry.tsx +3 -2
  40. package/dist/tree/app/components/index.ts +2 -1
  41. package/dist/tree/app/globals.css.gen.ts +1 -0
  42. package/dist/tree/app/menu/[slug]/page.tsx +16 -48
  43. package/dist/tree/gitignore +1 -0
  44. package/dist/tree/image-loader.ts +4 -0
  45. package/dist/tree/next.config.ts +12 -0
  46. package/package.json +11 -1
  47. package/dist/cli.d.mts +0 -9
  48. package/dist/cli.d.ts +0 -9
  49. package/dist/tree/app/menu/[slug]/ItemCustomizationClient.tsx +0 -18
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- // src/components/CookieConsent.tsx
3
+ // src/components/client/CookieConsent.tsx
4
4
  import { useEffect as useEffect2, useState as useState2 } from "react";
5
5
 
6
6
  // ../../node_modules/@headlessui/react/dist/utils/env.js
@@ -495,7 +495,7 @@ var me = Y(Fe);
495
495
  var Oe = Y(Le);
496
496
  var Ke = Object.assign(X, { Child: Oe, Root: X });
497
497
 
498
- // src/components/CookieConsent.tsx
498
+ // src/components/client/CookieConsent.tsx
499
499
  import { useCustomer } from "@zorgo/next";
500
500
  import { jsx, jsxs } from "react/jsx-runtime";
501
501
  function CookieConsent() {
@@ -550,45 +550,19 @@ function CookieConsent() {
550
550
  );
551
551
  }
552
552
 
553
- // src/components/Breadcrumbs.tsx
553
+ // src/components/client/GridMenu.tsx
554
+ import Image from "next/image";
554
555
  import Link from "next/link";
555
- import { ChevronRight } from "lucide-react";
556
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
557
- function cn(...parts) {
558
- return parts.filter(Boolean).join(" ");
559
- }
560
- var BREADCRUMBS_DEFAULT_ITEM_CLASSES = {
561
- baseContainer: "flex flex-row items-center gap-2 text-sm opacity-75",
562
- crumbLink: "hover:opacity-75 transition-all duration-300 underline-offset-2 hover:underline",
563
- crumbText: "font-semibold",
564
- separator: "h-4 w-4 opacity-50"
565
- };
566
- function mergeBreadcrumbsItemClasses(overrides) {
567
- const d3 = BREADCRUMBS_DEFAULT_ITEM_CLASSES;
568
- return {
569
- baseContainer: cn(d3.baseContainer, overrides?.baseContainer),
570
- crumbLink: cn(d3.crumbLink, overrides?.crumbLink),
571
- crumbText: cn(d3.crumbText, overrides?.crumbText),
572
- separator: cn(d3.separator, overrides?.separator)
573
- };
574
- }
575
- function Breadcrumbs({
576
- items,
577
- itemClasses
578
- }) {
579
- const slots = mergeBreadcrumbsItemClasses(itemClasses);
580
- return /* @__PURE__ */ jsx2("nav", { "aria-label": "Breadcrumb", className: slots.baseContainer, children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { className: "flex flex-row items-center gap-2", children: [
581
- index > 0 && /* @__PURE__ */ jsx2(ChevronRight, { className: slots.separator }),
582
- item.href ? /* @__PURE__ */ jsx2(Link, { href: item.href, className: slots.crumbLink, children: item.label }) : /* @__PURE__ */ jsx2("span", { className: slots.crumbText, children: item.label })
583
- ] }, `${item.label}-${index}`)) });
584
- }
585
-
586
- // src/components/GridMenu.tsx
587
- import Link2 from "next/link";
588
- import { useMenu } from "@zorgo/next";
589
556
  import { menuItemSlug } from "@zorgo/next/slugs";
590
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
591
- function cn2(...parts) {
557
+ import { menuImageUrl as menuImageUrl2 } from "@zorgo/next/images";
558
+
559
+ // src/images.ts
560
+ import { menuImageUrl } from "@zorgo/next/images";
561
+ var ITEM_IMAGE_PREFIX = "/images/items/";
562
+
563
+ // src/components/client/GridMenu.tsx
564
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
565
+ function cn(...parts) {
592
566
  return parts.filter(Boolean).join(" ");
593
567
  }
594
568
  function money(cents) {
@@ -609,25 +583,25 @@ var GRID_MENU_DEFAULT_ITEM_CLASSES = {
609
583
  function mergeGridMenuItemClasses(overrides) {
610
584
  const d3 = GRID_MENU_DEFAULT_ITEM_CLASSES;
611
585
  return {
612
- baseContainer: cn2(d3.baseContainer, overrides?.baseContainer),
613
- categoryContainer: cn2(
586
+ baseContainer: cn(d3.baseContainer, overrides?.baseContainer),
587
+ categoryContainer: cn(
614
588
  d3.categoryContainer,
615
589
  overrides?.categoryContainer
616
590
  ),
617
- categoryTitle: cn2(d3.categoryTitle, overrides?.categoryTitle),
618
- itemCardContainer: cn2(
591
+ categoryTitle: cn(d3.categoryTitle, overrides?.categoryTitle),
592
+ itemCardContainer: cn(
619
593
  d3.itemCardContainer,
620
594
  overrides?.itemCardContainer
621
595
  ),
622
- itemCard: cn2(d3.itemCard, overrides?.itemCard),
623
- itemCardImage: cn2(d3.itemCardImage, overrides?.itemCardImage),
624
- itemCardTextContainer: cn2(
596
+ itemCard: cn(d3.itemCard, overrides?.itemCard),
597
+ itemCardImage: cn(d3.itemCardImage, overrides?.itemCardImage),
598
+ itemCardTextContainer: cn(
625
599
  d3.itemCardTextContainer,
626
600
  overrides?.itemCardTextContainer
627
601
  ),
628
- itemCardName: cn2(d3.itemCardName, overrides?.itemCardName),
629
- itemCardPrice: cn2(d3.itemCardPrice, overrides?.itemCardPrice),
630
- itemCardOldPrice: cn2(d3.itemCardOldPrice, overrides?.itemCardOldPrice)
602
+ itemCardName: cn(d3.itemCardName, overrides?.itemCardName),
603
+ itemCardPrice: cn(d3.itemCardPrice, overrides?.itemCardPrice),
604
+ itemCardOldPrice: cn(d3.itemCardOldPrice, overrides?.itemCardOldPrice)
631
605
  };
632
606
  }
633
607
  function GridMenu({
@@ -635,26 +609,25 @@ function GridMenu({
635
609
  categories,
636
610
  itemClasses
637
611
  }) {
638
- const { getItemImageUrl } = useMenu();
639
612
  const slots = mergeGridMenuItemClasses(itemClasses);
640
- return /* @__PURE__ */ jsx3("div", { className: slots.baseContainer, children: categories.map((category) => {
613
+ return /* @__PURE__ */ jsx2("div", { className: slots.baseContainer, children: categories.map((category) => {
641
614
  const itemsInCategory = items.filter(
642
615
  (item) => item.category_id === category.category_id
643
616
  );
644
617
  if (itemsInCategory.length === 0) {
645
618
  return null;
646
619
  }
647
- return /* @__PURE__ */ jsxs3(
620
+ return /* @__PURE__ */ jsxs2(
648
621
  "div",
649
622
  {
650
623
  className: slots.categoryContainer,
651
624
  children: [
652
- /* @__PURE__ */ jsx3("h1", { className: slots.categoryTitle, children: category.name }),
653
- /* @__PURE__ */ jsx3("div", { className: slots.itemCardContainer, children: itemsInCategory.map((item) => /* @__PURE__ */ jsx3(
625
+ /* @__PURE__ */ jsx2("h1", { className: slots.categoryTitle, children: category.name }),
626
+ /* @__PURE__ */ jsx2("div", { className: slots.itemCardContainer, children: itemsInCategory.map((item) => /* @__PURE__ */ jsx2(
654
627
  ItemCard,
655
628
  {
656
629
  item,
657
- imageUrl: getItemImageUrl(item.image_path),
630
+ imageUrl: menuImageUrl2(item.images?.[0]),
658
631
  slots
659
632
  },
660
633
  item.base_item_id
@@ -672,40 +645,43 @@ function ItemCard({
672
645
  }) {
673
646
  const variant = item.variants[0];
674
647
  const onSale = variant?.display_price != null && variant.display_price < variant.price;
675
- return /* @__PURE__ */ jsxs3(
676
- Link2,
648
+ return /* @__PURE__ */ jsxs2(
649
+ Link,
677
650
  {
678
651
  href: `/menu/${menuItemSlug(item.name, item.base_item_id)}`,
679
652
  className: slots.itemCard,
680
653
  children: [
681
- /* @__PURE__ */ jsx3("div", { className: slots.itemCardImage, children: imageUrl && // eslint-disable-next-line @next/next/no-img-element
682
- /* @__PURE__ */ jsx3(
683
- "img",
654
+ /* @__PURE__ */ jsx2("div", { className: slots.itemCardImage, children: imageUrl && /* @__PURE__ */ jsx2(
655
+ Image,
684
656
  {
685
657
  src: imageUrl,
686
658
  alt: item.name,
659
+ width: 640,
660
+ height: 640,
661
+ unoptimized: !imageUrl.startsWith(ITEM_IMAGE_PREFIX),
662
+ sizes: "(min-width: 1024px) 320px, (min-width: 640px) 50vw, 100vw",
687
663
  className: "w-full h-full object-cover"
688
664
  }
689
665
  ) }),
690
- /* @__PURE__ */ jsxs3("div", { className: slots.itemCardTextContainer, children: [
691
- /* @__PURE__ */ jsx3("p", { className: slots.itemCardName, children: item.name }),
692
- variant && /* @__PURE__ */ jsx3(Fragment, { children: onSale ? /* @__PURE__ */ jsxs3(Fragment, { children: [
693
- /* @__PURE__ */ jsx3("p", { className: slots.itemCardPrice, children: money(variant.display_price) }),
694
- /* @__PURE__ */ jsx3("p", { className: slots.itemCardOldPrice, children: money(variant.price) })
695
- ] }) : /* @__PURE__ */ jsx3("p", { className: slots.itemCardPrice, children: money(variant.price) }) })
666
+ /* @__PURE__ */ jsxs2("div", { className: slots.itemCardTextContainer, children: [
667
+ /* @__PURE__ */ jsx2("p", { className: slots.itemCardName, children: item.name }),
668
+ variant && /* @__PURE__ */ jsx2(Fragment, { children: onSale ? /* @__PURE__ */ jsxs2(Fragment, { children: [
669
+ /* @__PURE__ */ jsx2("p", { className: slots.itemCardPrice, children: money(variant.display_price) }),
670
+ /* @__PURE__ */ jsx2("p", { className: slots.itemCardOldPrice, children: money(variant.price) })
671
+ ] }) : /* @__PURE__ */ jsx2("p", { className: slots.itemCardPrice, children: money(variant.price) }) })
696
672
  ] })
697
673
  ]
698
674
  }
699
675
  );
700
676
  }
701
677
 
702
- // src/components/AccordionMenu.tsx
703
- import Link3 from "next/link";
678
+ // src/components/client/AccordionMenu.tsx
679
+ import Link2 from "next/link";
704
680
  import { useState as useState3 } from "react";
705
681
  import { ChevronDown, ChevronUp } from "lucide-react";
706
682
  import { menuItemSlug as menuItemSlug2 } from "@zorgo/next/slugs";
707
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
708
- function cn3(...parts) {
683
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
684
+ function cn2(...parts) {
709
685
  return parts.filter(Boolean).join(" ");
710
686
  }
711
687
  function money2(cents) {
@@ -729,34 +705,34 @@ var ACCORDION_MENU_DEFAULT_ITEM_CLASSES = {
729
705
  function mergeAccordionMenuItemClasses(overrides) {
730
706
  const d3 = ACCORDION_MENU_DEFAULT_ITEM_CLASSES;
731
707
  return {
732
- baseContainer: cn3(d3.baseContainer, overrides?.baseContainer),
733
- categoryContainer: cn3(
708
+ baseContainer: cn2(d3.baseContainer, overrides?.baseContainer),
709
+ categoryContainer: cn2(
734
710
  d3.categoryContainer,
735
711
  overrides?.categoryContainer
736
712
  ),
737
- categoryTrigger: cn3(d3.categoryTrigger, overrides?.categoryTrigger),
738
- categoryTitle: cn3(d3.categoryTitle, overrides?.categoryTitle),
739
- categoryIndicator: cn3(
713
+ categoryTrigger: cn2(d3.categoryTrigger, overrides?.categoryTrigger),
714
+ categoryTitle: cn2(d3.categoryTitle, overrides?.categoryTitle),
715
+ categoryIndicator: cn2(
740
716
  d3.categoryIndicator,
741
717
  overrides?.categoryIndicator
742
718
  ),
743
- itemsContainer: cn3(d3.itemsContainer, overrides?.itemsContainer),
744
- itemCard: cn3(d3.itemCard, overrides?.itemCard),
745
- itemCardTextContainer: cn3(
719
+ itemsContainer: cn2(d3.itemsContainer, overrides?.itemsContainer),
720
+ itemCard: cn2(d3.itemCard, overrides?.itemCard),
721
+ itemCardTextContainer: cn2(
746
722
  d3.itemCardTextContainer,
747
723
  overrides?.itemCardTextContainer
748
724
  ),
749
- itemCardName: cn3(d3.itemCardName, overrides?.itemCardName),
750
- itemCardDescription: cn3(
725
+ itemCardName: cn2(d3.itemCardName, overrides?.itemCardName),
726
+ itemCardDescription: cn2(
751
727
  d3.itemCardDescription,
752
728
  overrides?.itemCardDescription
753
729
  ),
754
- itemCardPriceContainer: cn3(
730
+ itemCardPriceContainer: cn2(
755
731
  d3.itemCardPriceContainer,
756
732
  overrides?.itemCardPriceContainer
757
733
  ),
758
- itemCardPrice: cn3(d3.itemCardPrice, overrides?.itemCardPrice),
759
- itemCardOldPrice: cn3(d3.itemCardOldPrice, overrides?.itemCardOldPrice)
734
+ itemCardPrice: cn2(d3.itemCardPrice, overrides?.itemCardPrice),
735
+ itemCardOldPrice: cn2(d3.itemCardOldPrice, overrides?.itemCardOldPrice)
760
736
  };
761
737
  }
762
738
  function AccordionMenu({
@@ -765,14 +741,14 @@ function AccordionMenu({
765
741
  itemClasses
766
742
  }) {
767
743
  const slots = mergeAccordionMenuItemClasses(itemClasses);
768
- return /* @__PURE__ */ jsx4("div", { className: slots.baseContainer, children: categories.map((category) => {
744
+ return /* @__PURE__ */ jsx3("div", { className: slots.baseContainer, children: categories.map((category) => {
769
745
  const itemsInCategory = items.filter(
770
746
  (item) => item.category_id === category.category_id
771
747
  );
772
748
  if (itemsInCategory.length === 0) {
773
749
  return null;
774
750
  }
775
- return /* @__PURE__ */ jsx4(
751
+ return /* @__PURE__ */ jsx3(
776
752
  MenuCategory,
777
753
  {
778
754
  category,
@@ -789,27 +765,27 @@ function MenuCategory({
789
765
  slots
790
766
  }) {
791
767
  const [isExpanded, setIsExpanded] = useState3(false);
792
- return /* @__PURE__ */ jsxs4("div", { className: slots.categoryContainer, children: [
793
- /* @__PURE__ */ jsxs4(
768
+ return /* @__PURE__ */ jsxs3("div", { className: slots.categoryContainer, children: [
769
+ /* @__PURE__ */ jsxs3(
794
770
  "button",
795
771
  {
796
772
  type: "button",
797
773
  onClick: () => setIsExpanded(!isExpanded),
798
774
  className: slots.categoryTrigger,
799
775
  children: [
800
- /* @__PURE__ */ jsx4("h2", { className: slots.categoryTitle, children: category.name }),
801
- isExpanded ? /* @__PURE__ */ jsx4(ChevronUp, { className: slots.categoryIndicator }) : /* @__PURE__ */ jsx4(ChevronDown, { className: slots.categoryIndicator })
776
+ /* @__PURE__ */ jsx3("h2", { className: slots.categoryTitle, children: category.name }),
777
+ isExpanded ? /* @__PURE__ */ jsx3(ChevronUp, { className: slots.categoryIndicator }) : /* @__PURE__ */ jsx3(ChevronDown, { className: slots.categoryIndicator })
802
778
  ]
803
779
  }
804
780
  ),
805
- /* @__PURE__ */ jsx4(
781
+ /* @__PURE__ */ jsx3(
806
782
  "div",
807
783
  {
808
- className: cn3(
784
+ className: cn2(
809
785
  isExpanded ? "flex" : "hidden",
810
786
  slots.itemsContainer
811
787
  ),
812
- children: itemsInCategory.map((item) => /* @__PURE__ */ jsx4(
788
+ children: itemsInCategory.map((item) => /* @__PURE__ */ jsx3(
813
789
  ItemCard2,
814
790
  {
815
791
  item,
@@ -827,36 +803,33 @@ function ItemCard2({
827
803
  }) {
828
804
  const variant = item.variants[0];
829
805
  const onSale = variant?.display_price != null && variant.display_price < variant.price;
830
- return /* @__PURE__ */ jsxs4(
831
- Link3,
806
+ return /* @__PURE__ */ jsxs3(
807
+ Link2,
832
808
  {
833
809
  href: `/menu/${menuItemSlug2(item.name, item.base_item_id)}`,
834
810
  className: slots.itemCard,
835
811
  children: [
836
- /* @__PURE__ */ jsxs4("div", { className: slots.itemCardTextContainer, children: [
837
- /* @__PURE__ */ jsx4("p", { className: slots.itemCardName, children: item.name }),
838
- item.description && /* @__PURE__ */ jsx4("p", { className: slots.itemCardDescription, children: item.description })
812
+ /* @__PURE__ */ jsxs3("div", { className: slots.itemCardTextContainer, children: [
813
+ /* @__PURE__ */ jsx3("p", { className: slots.itemCardName, children: item.name }),
814
+ item.description && /* @__PURE__ */ jsx3("p", { className: slots.itemCardDescription, children: item.description })
839
815
  ] }),
840
- variant && /* @__PURE__ */ jsx4("div", { className: slots.itemCardPriceContainer, children: onSale ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
841
- /* @__PURE__ */ jsx4("p", { className: slots.itemCardPrice, children: money2(variant.display_price) }),
842
- /* @__PURE__ */ jsx4("p", { className: slots.itemCardOldPrice, children: money2(variant.price) })
843
- ] }) : /* @__PURE__ */ jsx4("p", { className: slots.itemCardPrice, children: money2(variant.price) }) })
816
+ variant && /* @__PURE__ */ jsx3("div", { className: slots.itemCardPriceContainer, children: onSale ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
817
+ /* @__PURE__ */ jsx3("p", { className: slots.itemCardPrice, children: money2(variant.display_price) }),
818
+ /* @__PURE__ */ jsx3("p", { className: slots.itemCardOldPrice, children: money2(variant.price) })
819
+ ] }) : /* @__PURE__ */ jsx3("p", { className: slots.itemCardPrice, children: money2(variant.price) }) })
844
820
  ]
845
821
  }
846
822
  );
847
823
  }
848
824
 
849
- // src/components/ItemCustomizationForm.tsx
850
- import { Minus, Plus } from "lucide-react";
851
- import { useItemCustomization, useMenu as useMenu2 } from "@zorgo/next";
852
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
853
- function cn4(...parts) {
825
+ // src/components/client/ItemForm/classes.ts
826
+ function cn3(...parts) {
854
827
  return parts.filter(Boolean).join(" ");
855
828
  }
856
829
  function money3(cents) {
857
830
  return `$${(cents / 100).toFixed(2)}`;
858
831
  }
859
- var ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES = {
832
+ var CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES = {
860
833
  baseContainer: "flex flex-col gap-8",
861
834
  title: "text-4xl font-extrabold text-primary",
862
835
  description: "opacity-70 text-xl",
@@ -874,57 +847,496 @@ var ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES = {
874
847
  incrementButton: "bg-background text-foreground w-10 h-10 rounded-xl flex items-center justify-center hover:bg-foreground hover:text-background transition-all duration-300",
875
848
  servingsValue: "w-8 md:w-12 font-semibold opacity-75 text-center",
876
849
  ruleError: "text-sm text-red-500",
850
+ portionHint: "text-base font-normal opacity-60",
877
851
  commentsTextarea: "p-4 rounded-xl border-3 border-foreground/[15%] outline-none resize-none",
878
852
  quantityRow: "flex flex-row items-center gap-4 text-xl",
879
853
  submitButton: "bg-primary text-primary-foreground p-4 rounded-xl text-lg font-semibold hover:bg-primary/80 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",
880
854
  notFound: ""
881
855
  };
882
- function mergeItemCustomizationFormItemClasses(overrides) {
883
- const d3 = ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES;
856
+ function mergeClientItemFormItemClasses(overrides) {
857
+ const d3 = CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES;
884
858
  return {
885
- baseContainer: cn4(d3.baseContainer, overrides?.baseContainer),
886
- title: cn4(d3.title, overrides?.title),
887
- description: cn4(d3.description, overrides?.description),
888
- section: cn4(d3.section, overrides?.section),
889
- sectionTitle: cn4(d3.sectionTitle, overrides?.sectionTitle),
890
- optionsRow: cn4(d3.optionsRow, overrides?.optionsRow),
891
- optionButton: cn4(d3.optionButton, overrides?.optionButton),
892
- optionButtonSelected: cn4(
859
+ baseContainer: cn3(d3.baseContainer, overrides?.baseContainer),
860
+ title: cn3(d3.title, overrides?.title),
861
+ description: cn3(d3.description, overrides?.description),
862
+ section: cn3(d3.section, overrides?.section),
863
+ sectionTitle: cn3(d3.sectionTitle, overrides?.sectionTitle),
864
+ optionsRow: cn3(d3.optionsRow, overrides?.optionsRow),
865
+ optionButton: cn3(d3.optionButton, overrides?.optionButton),
866
+ optionButtonSelected: cn3(
893
867
  d3.optionButtonSelected,
894
868
  overrides?.optionButtonSelected
895
869
  ),
896
- optionButtonUnselected: cn4(
870
+ optionButtonUnselected: cn3(
897
871
  d3.optionButtonUnselected,
898
872
  overrides?.optionButtonUnselected
899
873
  ),
900
- optionButtonLabel: cn4(
874
+ optionButtonLabel: cn3(
901
875
  d3.optionButtonLabel,
902
876
  overrides?.optionButtonLabel
903
877
  ),
904
- optionButtonUpcharge: cn4(
878
+ optionButtonUpcharge: cn3(
905
879
  d3.optionButtonUpcharge,
906
880
  overrides?.optionButtonUpcharge
907
881
  ),
908
- servingsRow: cn4(d3.servingsRow, overrides?.servingsRow),
909
- servingsLabel: cn4(d3.servingsLabel, overrides?.servingsLabel),
910
- servingsControls: cn4(d3.servingsControls, overrides?.servingsControls),
911
- incrementButton: cn4(d3.incrementButton, overrides?.incrementButton),
912
- servingsValue: cn4(d3.servingsValue, overrides?.servingsValue),
913
- ruleError: cn4(d3.ruleError, overrides?.ruleError),
914
- commentsTextarea: cn4(d3.commentsTextarea, overrides?.commentsTextarea),
915
- quantityRow: cn4(d3.quantityRow, overrides?.quantityRow),
916
- submitButton: cn4(d3.submitButton, overrides?.submitButton),
917
- notFound: cn4(d3.notFound, overrides?.notFound)
882
+ servingsRow: cn3(d3.servingsRow, overrides?.servingsRow),
883
+ servingsLabel: cn3(d3.servingsLabel, overrides?.servingsLabel),
884
+ servingsControls: cn3(d3.servingsControls, overrides?.servingsControls),
885
+ incrementButton: cn3(d3.incrementButton, overrides?.incrementButton),
886
+ servingsValue: cn3(d3.servingsValue, overrides?.servingsValue),
887
+ ruleError: cn3(d3.ruleError, overrides?.ruleError),
888
+ portionHint: cn3(d3.portionHint, overrides?.portionHint),
889
+ commentsTextarea: cn3(d3.commentsTextarea, overrides?.commentsTextarea),
890
+ quantityRow: cn3(d3.quantityRow, overrides?.quantityRow),
891
+ submitButton: cn3(d3.submitButton, overrides?.submitButton),
892
+ notFound: cn3(d3.notFound, overrides?.notFound)
893
+ };
894
+ }
895
+ var CLIENT_ITEM_FORM_SLOTS = mergeClientItemFormItemClasses();
896
+
897
+ // src/components/client/ItemForm/ClientItemForm.tsx
898
+ import { useState as useState4 } from "react";
899
+ import { useRouter } from "next/navigation";
900
+ import { useItemCustomization, useMenu } from "@zorgo/next";
901
+
902
+ // src/components/client/ItemForm/Breadcrumbs.tsx
903
+ import Link3 from "next/link";
904
+ import { ChevronRight } from "lucide-react";
905
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
906
+ function cn4(...parts) {
907
+ return parts.filter(Boolean).join(" ");
908
+ }
909
+ var BREADCRUMBS_DEFAULT_ITEM_CLASSES = {
910
+ baseContainer: "flex flex-row items-center gap-2 text-sm opacity-75",
911
+ crumbLink: "hover:opacity-75 transition-all duration-300 underline-offset-2 hover:underline",
912
+ crumbText: "font-semibold",
913
+ separator: "h-4 w-4 opacity-50"
914
+ };
915
+ function mergeBreadcrumbsItemClasses(overrides) {
916
+ const d3 = BREADCRUMBS_DEFAULT_ITEM_CLASSES;
917
+ return {
918
+ baseContainer: cn4(d3.baseContainer, overrides?.baseContainer),
919
+ crumbLink: cn4(d3.crumbLink, overrides?.crumbLink),
920
+ crumbText: cn4(d3.crumbText, overrides?.crumbText),
921
+ separator: cn4(d3.separator, overrides?.separator)
918
922
  };
919
923
  }
920
- function ItemCustomizationForm({
924
+ function Breadcrumbs({
925
+ items,
926
+ itemClasses
927
+ }) {
928
+ const slots = mergeBreadcrumbsItemClasses(itemClasses);
929
+ return /* @__PURE__ */ jsx4("nav", { "aria-label": "Breadcrumb", className: slots.baseContainer, children: items.map((item, index) => /* @__PURE__ */ jsxs4("span", { className: "flex flex-row items-center gap-2", children: [
930
+ index > 0 && /* @__PURE__ */ jsx4(ChevronRight, { className: slots.separator }),
931
+ item.href ? /* @__PURE__ */ jsx4(Link3, { href: item.href, className: slots.crumbLink, children: item.label }) : /* @__PURE__ */ jsx4("span", { className: slots.crumbText, children: item.label })
932
+ ] }, `${item.label}-${index}`)) });
933
+ }
934
+
935
+ // src/components/client/ItemForm/CommentsSection.tsx
936
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
937
+ function CommentsSection({
938
+ comments,
939
+ setComments,
940
+ title = "Comments",
941
+ placeholder = "Special instructions...",
942
+ rows = 2,
943
+ slots = CLIENT_ITEM_FORM_SLOTS
944
+ }) {
945
+ return /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
946
+ /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: title }),
947
+ /* @__PURE__ */ jsx5(
948
+ "textarea",
949
+ {
950
+ value: comments,
951
+ onChange: (e) => setComments(e.target.value),
952
+ placeholder,
953
+ className: slots.commentsTextarea,
954
+ rows
955
+ }
956
+ )
957
+ ] });
958
+ }
959
+
960
+ // src/components/client/ItemForm/ComponentsSection.tsx
961
+ import { portionLabel } from "@zorgo/next";
962
+
963
+ // src/components/client/ItemForm/OptionButton.tsx
964
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
965
+ function OptionButton({
966
+ label,
967
+ subtext,
968
+ selected,
969
+ onClick,
970
+ slots = CLIENT_ITEM_FORM_SLOTS
971
+ }) {
972
+ return /* @__PURE__ */ jsxs6(
973
+ "button",
974
+ {
975
+ type: "button",
976
+ onClick,
977
+ className: cn3(
978
+ slots.optionButton,
979
+ selected ? slots.optionButtonSelected : slots.optionButtonUnselected
980
+ ),
981
+ children: [
982
+ /* @__PURE__ */ jsx6("span", { className: slots.optionButtonLabel, children: label }),
983
+ subtext && /* @__PURE__ */ jsx6("span", { className: slots.optionButtonUpcharge, children: subtext })
984
+ ]
985
+ }
986
+ );
987
+ }
988
+
989
+ // src/components/client/ItemForm/ComponentsSection.tsx
990
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
991
+ function ComponentsSection({
992
+ variant,
993
+ draft,
994
+ setComponentServings,
995
+ activeSection = null,
996
+ divisions = 1,
997
+ scheme,
998
+ title = "Includes",
999
+ slots = CLIENT_ITEM_FORM_SLOTS
1000
+ }) {
1001
+ const components = variant.components ?? [];
1002
+ if (components.length === 0) return null;
1003
+ const portion = activeSection != null ? `${activeSection}/${divisions}` : null;
1004
+ return /* @__PURE__ */ jsxs7("div", { className: slots.section, children: [
1005
+ /* @__PURE__ */ jsx7("h2", { className: slots.sectionTitle, children: title }),
1006
+ /* @__PURE__ */ jsx7("div", { className: slots.optionsRow, children: components.map((component) => {
1007
+ const defaultServings = component.servings_per_item ?? 1;
1008
+ const rows = (draft?.components ?? []).filter(
1009
+ (c6) => c6.id === component.id
1010
+ );
1011
+ const row = rows.find((c6) => c6.portion === portion) ?? rows.find((c6) => !c6.portion);
1012
+ const servings = row?.quantity_servings ?? defaultServings;
1013
+ const selected = servings > 0;
1014
+ const removedElsewhere = !portion && rows.some((c6) => c6.quantity_servings === 0);
1015
+ return /* @__PURE__ */ jsx7(
1016
+ OptionButton,
1017
+ {
1018
+ label: component.name,
1019
+ subtext: removedElsewhere && scheme ? `No ${component.name.toLowerCase()} on ${rows.filter((c6) => c6.quantity_servings === 0).map(
1020
+ (c6) => portionLabel(c6.portion, scheme).toLowerCase()
1021
+ ).join(", ")}` : void 0,
1022
+ selected,
1023
+ onClick: () => setComponentServings(
1024
+ component.id,
1025
+ selected ? 0 : defaultServings,
1026
+ portion
1027
+ ),
1028
+ slots
1029
+ },
1030
+ component.id
1031
+ );
1032
+ }) })
1033
+ ] });
1034
+ }
1035
+
1036
+ // src/components/client/ItemForm/PortionPicker.tsx
1037
+ import {
1038
+ divisionsFor,
1039
+ portionLabel as portionLabel2,
1040
+ radialSectionPath
1041
+ } from "@zorgo/next";
1042
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1043
+ function cn5(...parts) {
1044
+ return parts.filter(Boolean).join(" ");
1045
+ }
1046
+ var SECTION_FILL = "var(--color-background-elevated, #fff)";
1047
+ function sectionClass(isActive, isCovered) {
1048
+ return cn5(
1049
+ "transition-all duration-200 cursor-pointer",
1050
+ isActive ? "fill-primary stroke-primary" : isCovered ? "fill-primary/30 stroke-foreground/20" : "stroke-foreground/20 hover:fill-primary/10"
1051
+ );
1052
+ }
1053
+ function RadialPicker({ divisions, active, covered = [], onSelect }) {
1054
+ return /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 100 100", className: "w-32 h-32", role: "group", children: Array.from({ length: divisions }, (_, i4) => {
1055
+ const index = i4 + 1;
1056
+ return /* @__PURE__ */ jsx8(
1057
+ "path",
1058
+ {
1059
+ d: radialSectionPath(index, divisions),
1060
+ strokeWidth: 2,
1061
+ style: { fill: SECTION_FILL },
1062
+ className: sectionClass(active === index, covered.includes(index)),
1063
+ onClick: () => onSelect(active === index ? null : index)
1064
+ },
1065
+ index
1066
+ );
1067
+ }) });
1068
+ }
1069
+ function GridPicker({ divisions, active, covered = [], onSelect }) {
1070
+ const cols = Math.ceil(Math.sqrt(divisions));
1071
+ const rows = Math.ceil(divisions / cols);
1072
+ return /* @__PURE__ */ jsx8(
1073
+ "div",
1074
+ {
1075
+ className: "grid gap-1 w-32 h-32",
1076
+ style: {
1077
+ gridTemplateColumns: `repeat(${cols}, 1fr)`,
1078
+ gridTemplateRows: `repeat(${rows}, 1fr)`,
1079
+ gridAutoFlow: "column"
1080
+ },
1081
+ children: Array.from({ length: divisions }, (_, i4) => {
1082
+ const index = i4 + 1;
1083
+ return /* @__PURE__ */ jsx8(
1084
+ "button",
1085
+ {
1086
+ type: "button",
1087
+ "aria-pressed": active === index,
1088
+ onClick: () => onSelect(active === index ? null : index),
1089
+ className: cn5(
1090
+ "rounded-lg border-3 transition-all duration-200",
1091
+ active === index ? "bg-primary border-primary" : covered.includes(index) ? "bg-primary/30 border-foreground/15" : "bg-background-elevated border-foreground/15 hover:bg-primary/10"
1092
+ )
1093
+ },
1094
+ index
1095
+ );
1096
+ })
1097
+ }
1098
+ );
1099
+ }
1100
+ function LinearPicker({ divisions, active, covered = [], onSelect }) {
1101
+ return /* @__PURE__ */ jsx8("div", { className: "flex flex-row w-full max-w-xs h-12 gap-1", children: Array.from({ length: divisions }, (_, i4) => {
1102
+ const index = i4 + 1;
1103
+ return /* @__PURE__ */ jsx8(
1104
+ "button",
1105
+ {
1106
+ type: "button",
1107
+ "aria-pressed": active === index,
1108
+ onClick: () => onSelect(active === index ? null : index),
1109
+ className: cn5(
1110
+ "flex-1 rounded-lg border-3 transition-all duration-200",
1111
+ active === index ? "bg-primary border-primary" : covered.includes(index) ? "bg-primary/30 border-foreground/15" : "bg-background-elevated border-foreground/15 hover:bg-primary/10"
1112
+ )
1113
+ },
1114
+ index
1115
+ );
1116
+ }) });
1117
+ }
1118
+ function CountPicker({
1119
+ divisions,
1120
+ active,
1121
+ covered = [],
1122
+ onSelect,
1123
+ scheme
1124
+ }) {
1125
+ return /* @__PURE__ */ jsx8("div", { className: "flex flex-row flex-wrap gap-2", children: Array.from({ length: divisions }, (_, i4) => {
1126
+ const index = i4 + 1;
1127
+ return /* @__PURE__ */ jsx8(
1128
+ "button",
1129
+ {
1130
+ type: "button",
1131
+ "aria-pressed": active === index,
1132
+ onClick: () => onSelect(active === index ? null : index),
1133
+ className: cn5(
1134
+ "px-4 py-2 rounded-xl border-3 font-semibold transition-all duration-200",
1135
+ active === index ? "bg-primary text-primary-foreground border-primary" : covered.includes(index) ? "bg-primary/30 border-foreground/15" : "bg-background-elevated border-foreground/15 hover:bg-primary/10"
1136
+ ),
1137
+ children: portionLabel2(`${index}/${divisions}`, scheme)
1138
+ },
1139
+ index
1140
+ );
1141
+ }) });
1142
+ }
1143
+ function PortionPicker({
1144
+ scheme,
1145
+ divisions,
1146
+ active,
1147
+ covered,
1148
+ onSelect,
1149
+ onDivisionsChange,
1150
+ className
1151
+ }) {
1152
+ const cuts = divisionsFor(scheme);
1153
+ const shapeProps = { divisions, active, covered, onSelect };
1154
+ return /* @__PURE__ */ jsxs8("div", { className: cn5("flex flex-col gap-4 items-center", className), children: [
1155
+ cuts.length > 1 && /* @__PURE__ */ jsx8("div", { className: "flex flex-row gap-2", children: cuts.map((count) => /* @__PURE__ */ jsx8(
1156
+ "button",
1157
+ {
1158
+ type: "button",
1159
+ "aria-pressed": divisions === count,
1160
+ onClick: () => onDivisionsChange(count),
1161
+ className: cn5(
1162
+ "px-4 py-2 rounded-xl border-3 font-semibold transition-all duration-200",
1163
+ divisions === count ? "bg-primary text-primary-foreground border-primary" : "bg-background-elevated border-foreground/15 hover:bg-primary/10"
1164
+ ),
1165
+ children: count === 1 ? "Whole" : `${count} parts`
1166
+ },
1167
+ count
1168
+ )) }),
1169
+ divisions > 1 && /* @__PURE__ */ jsxs8(Fragment3, { children: [
1170
+ scheme.geometry === "radial" && /* @__PURE__ */ jsx8(RadialPicker, { ...shapeProps }),
1171
+ scheme.geometry === "grid" && /* @__PURE__ */ jsx8(GridPicker, { ...shapeProps }),
1172
+ scheme.geometry === "linear" && /* @__PURE__ */ jsx8(LinearPicker, { ...shapeProps }),
1173
+ scheme.geometry === "count" && /* @__PURE__ */ jsx8(CountPicker, { ...shapeProps, scheme })
1174
+ ] }),
1175
+ /* @__PURE__ */ jsx8("p", { className: "opacity-70", children: active == null ? divisions > 1 ? "Editing the whole item \u2014 tap a section to edit just that part" : "Editing the whole item" : `Editing ${portionLabel2(`${active}/${divisions}`, scheme).toLowerCase()}` })
1176
+ ] });
1177
+ }
1178
+
1179
+ // src/components/client/ItemForm/PortionSection.tsx
1180
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1181
+ function PortionSection({
1182
+ scheme,
1183
+ divisions,
1184
+ activeSection,
1185
+ setActiveSection,
1186
+ setDivisions,
1187
+ slots = CLIENT_ITEM_FORM_SLOTS
1188
+ }) {
1189
+ return /* @__PURE__ */ jsxs9("div", { className: slots.section, children: [
1190
+ /* @__PURE__ */ jsx9("h2", { className: slots.sectionTitle, children: scheme.name }),
1191
+ /* @__PURE__ */ jsx9(
1192
+ PortionPicker,
1193
+ {
1194
+ scheme,
1195
+ divisions,
1196
+ active: activeSection,
1197
+ onSelect: setActiveSection,
1198
+ onDivisionsChange: setDivisions
1199
+ }
1200
+ )
1201
+ ] });
1202
+ }
1203
+
1204
+ // src/components/client/ItemForm/QuantitySection.tsx
1205
+ import { Minus, Plus } from "lucide-react";
1206
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1207
+ function QuantitySection({
1208
+ quantity,
1209
+ setQuantity,
1210
+ title = "How many?",
1211
+ slots = CLIENT_ITEM_FORM_SLOTS
1212
+ }) {
1213
+ return /* @__PURE__ */ jsxs10("div", { className: slots.section, children: [
1214
+ /* @__PURE__ */ jsx10("h2", { className: slots.sectionTitle, children: title }),
1215
+ /* @__PURE__ */ jsxs10("div", { className: slots.quantityRow, children: [
1216
+ /* @__PURE__ */ jsx10(
1217
+ "button",
1218
+ {
1219
+ type: "button",
1220
+ className: slots.incrementButton,
1221
+ onClick: () => setQuantity((q2) => q2 - 1),
1222
+ children: /* @__PURE__ */ jsx10(Minus, { className: "h-4 w-4" })
1223
+ }
1224
+ ),
1225
+ /* @__PURE__ */ jsx10("p", { className: slots.servingsValue, children: quantity }),
1226
+ /* @__PURE__ */ jsx10(
1227
+ "button",
1228
+ {
1229
+ type: "button",
1230
+ className: slots.incrementButton,
1231
+ onClick: () => setQuantity((q2) => q2 + 1),
1232
+ children: /* @__PURE__ */ jsx10(Plus, { className: "h-4 w-4" })
1233
+ }
1234
+ )
1235
+ ] })
1236
+ ] });
1237
+ }
1238
+
1239
+ // src/components/client/ItemForm/RuleSection.tsx
1240
+ import { parsePortionKey, portionLabel as portionLabel3 } from "@zorgo/next";
1241
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1242
+ function RuleSection({
1243
+ rule,
1244
+ activeSection = null,
1245
+ divisions = 1,
1246
+ scheme,
1247
+ placeOption,
1248
+ slots = CLIENT_ITEM_FORM_SLOTS
1249
+ }) {
1250
+ const portion = rule.portionable && activeSection != null ? `${activeSection}/${divisions}` : null;
1251
+ return /* @__PURE__ */ jsxs11("div", { className: slots.section, children: [
1252
+ /* @__PURE__ */ jsxs11("h2", { className: slots.sectionTitle, children: [
1253
+ rule.group_name,
1254
+ activeSection != null && !rule.portionable && /* @__PURE__ */ jsx11("span", { className: slots.portionHint, children: " \u2014 whole item only" })
1255
+ ] }),
1256
+ /* @__PURE__ */ jsx11("div", { className: slots.optionsRow, children: rule.options.map((option) => /* @__PURE__ */ jsx11(
1257
+ OptionButton,
1258
+ {
1259
+ label: option.name,
1260
+ subtext: (
1261
+ // where it sits beats what it costs — the price is
1262
+ // already in the running total
1263
+ option.portion && scheme ? portionLabel3(option.portion, scheme) : option.upcharge > 0 ? `+${money3(option.upcharge)}` : void 0
1264
+ ),
1265
+ selected: option.selected,
1266
+ onClick: () => placeOption ? placeOption(
1267
+ rule.rule_id,
1268
+ parsePortionKey(option.key).baseKey,
1269
+ portion,
1270
+ rule.max
1271
+ ) : option.toggle(),
1272
+ slots
1273
+ },
1274
+ parsePortionKey(option.key).baseKey
1275
+ )) }),
1276
+ rule.message() && /* @__PURE__ */ jsx11("p", { className: slots.ruleError, children: rule.message() })
1277
+ ] });
1278
+ }
1279
+
1280
+ // src/components/client/ItemForm/SubmitButton.tsx
1281
+ import { jsx as jsx12 } from "react/jsx-runtime";
1282
+ function SubmitButton({
1283
+ canSubmit,
1284
+ unmetRule,
1285
+ price,
1286
+ salePrice,
1287
+ isEditMode,
1288
+ onSubmit,
1289
+ slots = CLIENT_ITEM_FORM_SLOTS
1290
+ }) {
1291
+ return /* @__PURE__ */ jsx12(
1292
+ "button",
1293
+ {
1294
+ type: "button",
1295
+ disabled: !canSubmit,
1296
+ onClick: onSubmit,
1297
+ className: slots.submitButton,
1298
+ children: unmetRule ? `Choose ${unmetRule.group_name}` : `${isEditMode ? "Save changes" : "Add to cart"} \u2014 ${money3(salePrice ?? price)}`
1299
+ }
1300
+ );
1301
+ }
1302
+
1303
+ // src/components/client/ItemForm/VariantSection.tsx
1304
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1305
+ function VariantSection({
1306
+ variants,
1307
+ variant,
1308
+ setVariant,
1309
+ title = "Variants",
1310
+ slots = CLIENT_ITEM_FORM_SLOTS
1311
+ }) {
1312
+ if (variants.length <= 1) return null;
1313
+ return /* @__PURE__ */ jsxs12("div", { className: slots.section, children: [
1314
+ /* @__PURE__ */ jsx13("h2", { className: slots.sectionTitle, children: title }),
1315
+ /* @__PURE__ */ jsx13("div", { className: slots.optionsRow, children: variants.map((v2) => /* @__PURE__ */ jsx13(
1316
+ OptionButton,
1317
+ {
1318
+ label: v2.name,
1319
+ subtext: money3(v2.price),
1320
+ selected: v2.item_id === variant.item_id,
1321
+ onClick: () => setVariant(v2),
1322
+ slots
1323
+ },
1324
+ v2.item_id
1325
+ )) })
1326
+ ] });
1327
+ }
1328
+
1329
+ // src/components/client/ItemForm/ClientItemForm.tsx
1330
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1331
+ function ClientItemForm({
921
1332
  baseItemId,
922
1333
  seed,
923
1334
  editIndex,
924
1335
  itemClasses,
925
1336
  onSubmitSuccess
926
1337
  }) {
927
- const slots = mergeItemCustomizationFormItemClasses(itemClasses);
1338
+ const router = useRouter();
1339
+ const slots = mergeClientItemFormItemClasses(itemClasses);
928
1340
  const {
929
1341
  item,
930
1342
  variant,
@@ -942,17 +1354,21 @@ function ItemCustomizationForm({
942
1354
  price,
943
1355
  salePrice,
944
1356
  isEditMode,
945
- draft
1357
+ draft,
1358
+ portionScheme,
1359
+ placeOption,
1360
+ recutSelections
946
1361
  } = useItemCustomization(baseItemId, seed, editIndex);
947
- const { categories } = useMenu2();
1362
+ const { categories } = useMenu();
1363
+ const [cut, setCut] = useState4(1);
1364
+ const [activeSection, setActiveSection] = useState4(null);
1365
+ const divisions = portionScheme ? Math.min(Math.max(cut, portionScheme.min_divisions), portionScheme.max_divisions) : 1;
948
1366
  if (!item) {
949
- return /* @__PURE__ */ jsx5("div", { className: slots.notFound, children: "Item not found." });
1367
+ return /* @__PURE__ */ jsx14("div", { className: slots.notFound, children: "Item not found." });
950
1368
  }
951
- const category = categories.find(
952
- (c6) => c6.category_id === item.category_id
953
- );
954
- return /* @__PURE__ */ jsxs5("div", { className: slots.baseContainer, children: [
955
- /* @__PURE__ */ jsx5(
1369
+ const category = categories.find((c6) => c6.category_id === item.category_id);
1370
+ return /* @__PURE__ */ jsxs13("div", { className: slots.baseContainer, children: [
1371
+ /* @__PURE__ */ jsx14(
956
1372
  Breadcrumbs,
957
1373
  {
958
1374
  items: [
@@ -962,141 +1378,98 @@ function ItemCustomizationForm({
962
1378
  ]
963
1379
  }
964
1380
  ),
965
- /* @__PURE__ */ jsx5("h1", { className: slots.title, children: item.name }),
966
- item.description && /* @__PURE__ */ jsx5("p", { className: slots.description, children: item.description }),
967
- variants.length > 1 && /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
968
- /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: "Variants" }),
969
- /* @__PURE__ */ jsx5("div", { className: slots.optionsRow, children: variants.map((v2) => /* @__PURE__ */ jsx5(
970
- OptionButton,
971
- {
972
- label: v2.name,
973
- subtext: money3(v2.price),
974
- selected: v2.item_id === variant.item_id,
975
- onClick: () => setVariant(v2),
976
- slots
1381
+ /* @__PURE__ */ jsx14("h1", { className: slots.title, children: item.name }),
1382
+ item.description && /* @__PURE__ */ jsx14("p", { className: slots.description, children: item.description }),
1383
+ /* @__PURE__ */ jsx14(
1384
+ VariantSection,
1385
+ {
1386
+ variants,
1387
+ variant,
1388
+ setVariant,
1389
+ slots
1390
+ }
1391
+ ),
1392
+ /* @__PURE__ */ jsx14(
1393
+ ComponentsSection,
1394
+ {
1395
+ variant,
1396
+ draft,
1397
+ setComponentServings,
1398
+ activeSection,
1399
+ divisions,
1400
+ scheme: portionScheme,
1401
+ slots
1402
+ }
1403
+ ),
1404
+ portionScheme && /* @__PURE__ */ jsx14(
1405
+ PortionSection,
1406
+ {
1407
+ scheme: portionScheme,
1408
+ divisions,
1409
+ activeSection,
1410
+ setActiveSection,
1411
+ setDivisions: (next) => {
1412
+ recutSelections(next);
1413
+ setCut(next);
1414
+ setActiveSection(
1415
+ (s5) => s5 != null && (next === 1 || s5 > next) ? null : s5
1416
+ );
977
1417
  },
978
- v2.item_id
979
- )) })
980
- ] }),
981
- (variant.components?.length ?? 0) > 0 && /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
982
- /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: "Includes" }),
983
- /* @__PURE__ */ jsx5("div", { className: slots.optionsRow, children: variant.components.map((component) => {
984
- const defaultServings = component.servings_per_item ?? 1;
985
- const servings = draft?.components?.find(
986
- (c6) => c6.id === component.id
987
- )?.quantity_servings ?? defaultServings;
988
- const selected = servings > 0;
989
- return /* @__PURE__ */ jsx5(
990
- OptionButton,
991
- {
992
- label: component.name,
993
- selected,
994
- onClick: () => setComponentServings(
995
- component.id,
996
- selected ? 0 : defaultServings
997
- ),
998
- slots
999
- },
1000
- component.id
1001
- );
1002
- }) })
1003
- ] }),
1004
- ruleGroups.map((rule) => /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
1005
- /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: rule.group_name }),
1006
- /* @__PURE__ */ jsx5("div", { className: slots.optionsRow, children: rule.options.map((option) => /* @__PURE__ */ jsx5(
1007
- OptionButton,
1008
- {
1009
- label: option.name,
1010
- subtext: option.upcharge > 0 ? `+${money3(option.upcharge)}` : void 0,
1011
- selected: option.selected,
1012
- onClick: option.toggle,
1013
- slots
1014
- },
1015
- option.key
1016
- )) }),
1017
- rule.message() && /* @__PURE__ */ jsx5("p", { className: slots.ruleError, children: rule.message() })
1018
- ] }, rule.rule_id)),
1019
- /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
1020
- /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: "Comments" }),
1021
- /* @__PURE__ */ jsx5(
1022
- "textarea",
1023
- {
1024
- value: comments,
1025
- onChange: (e) => setComments(e.target.value),
1026
- placeholder: "Special instructions...",
1027
- className: slots.commentsTextarea,
1028
- rows: 2
1029
- }
1030
- )
1031
- ] }),
1032
- /* @__PURE__ */ jsxs5("div", { className: slots.section, children: [
1033
- /* @__PURE__ */ jsx5("h2", { className: slots.sectionTitle, children: "How many?" }),
1034
- /* @__PURE__ */ jsxs5("div", { className: slots.quantityRow, children: [
1035
- /* @__PURE__ */ jsx5(
1036
- "button",
1037
- {
1038
- type: "button",
1039
- className: slots.incrementButton,
1040
- onClick: () => setQuantity((q2) => Math.max(1, q2 - 1)),
1041
- children: /* @__PURE__ */ jsx5(Minus, { className: "h-4 w-4" })
1042
- }
1043
- ),
1044
- /* @__PURE__ */ jsx5("p", { className: slots.servingsValue, children: quantity }),
1045
- /* @__PURE__ */ jsx5(
1046
- "button",
1047
- {
1048
- type: "button",
1049
- className: slots.incrementButton,
1050
- onClick: () => setQuantity((q2) => q2 + 1),
1051
- children: /* @__PURE__ */ jsx5(Plus, { className: "h-4 w-4" })
1052
- }
1053
- )
1054
- ] })
1055
- ] }),
1056
- /* @__PURE__ */ jsx5(
1057
- "button",
1418
+ slots
1419
+ }
1420
+ ),
1421
+ ruleGroups.map((rule) => /* @__PURE__ */ jsx14(
1422
+ RuleSection,
1058
1423
  {
1059
- type: "button",
1060
- disabled: !canSubmit,
1061
- onClick: () => {
1424
+ rule,
1425
+ activeSection,
1426
+ divisions,
1427
+ scheme: portionScheme,
1428
+ placeOption,
1429
+ slots
1430
+ },
1431
+ rule.rule_id
1432
+ )),
1433
+ /* @__PURE__ */ jsx14(
1434
+ CommentsSection,
1435
+ {
1436
+ comments,
1437
+ setComments,
1438
+ slots
1439
+ }
1440
+ ),
1441
+ /* @__PURE__ */ jsx14(
1442
+ QuantitySection,
1443
+ {
1444
+ quantity,
1445
+ setQuantity,
1446
+ slots
1447
+ }
1448
+ ),
1449
+ /* @__PURE__ */ jsx14(
1450
+ SubmitButton,
1451
+ {
1452
+ canSubmit,
1453
+ unmetRule,
1454
+ price,
1455
+ salePrice,
1456
+ isEditMode,
1457
+ onSubmit: () => {
1062
1458
  submit();
1063
- onSubmitSuccess?.();
1459
+ if (onSubmitSuccess) onSubmitSuccess();
1460
+ else router.push("/menu");
1064
1461
  },
1065
- className: slots.submitButton,
1066
- children: unmetRule ? `Choose ${unmetRule.group_name}` : `${isEditMode ? "Save changes" : "Add to cart"} \u2014 ${money3(salePrice ?? price)}`
1462
+ slots
1067
1463
  }
1068
1464
  )
1069
1465
  ] });
1070
1466
  }
1071
- function OptionButton({
1072
- label,
1073
- subtext,
1074
- selected,
1075
- onClick,
1076
- slots
1077
- }) {
1078
- return /* @__PURE__ */ jsxs5(
1079
- "button",
1080
- {
1081
- type: "button",
1082
- onClick,
1083
- className: cn4(
1084
- slots.optionButton,
1085
- selected ? slots.optionButtonSelected : slots.optionButtonUnselected
1086
- ),
1087
- children: [
1088
- /* @__PURE__ */ jsx5("span", { className: slots.optionButtonLabel, children: label }),
1089
- subtext && /* @__PURE__ */ jsx5("span", { className: slots.optionButtonUpcharge, children: subtext })
1090
- ]
1091
- }
1092
- );
1093
- }
1094
1467
 
1095
- // src/components/FindLocation.tsx
1096
- import { useMemo, useState as useState4 } from "react";
1468
+ // src/components/client/FindLocation.tsx
1469
+ import { useMemo, useState as useState5 } from "react";
1097
1470
  import { Search } from "lucide-react";
1098
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1099
- function cn5(...parts) {
1471
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1472
+ function cn6(...parts) {
1100
1473
  return parts.filter(Boolean).join(" ");
1101
1474
  }
1102
1475
  function searchableText(location) {
@@ -1147,26 +1520,26 @@ var FIND_LOCATION_DEFAULT_ITEM_CLASSES = {
1147
1520
  function mergeFindLocationItemClasses(overrides) {
1148
1521
  const d3 = FIND_LOCATION_DEFAULT_ITEM_CLASSES;
1149
1522
  return {
1150
- baseContainer: cn5(d3.baseContainer, overrides?.baseContainer),
1151
- searchContainer: cn5(d3.searchContainer, overrides?.searchContainer),
1152
- searchIcon: cn5(d3.searchIcon, overrides?.searchIcon),
1153
- searchInput: cn5(d3.searchInput, overrides?.searchInput),
1154
- noMatchesMessage: cn5(d3.noMatchesMessage, overrides?.noMatchesMessage),
1155
- emptyMessage: cn5(d3.emptyMessage, overrides?.emptyMessage),
1156
- list: cn5(d3.list, overrides?.list),
1157
- locationRow: cn5(d3.locationRow, overrides?.locationRow),
1158
- locationRowSelected: cn5(
1523
+ baseContainer: cn6(d3.baseContainer, overrides?.baseContainer),
1524
+ searchContainer: cn6(d3.searchContainer, overrides?.searchContainer),
1525
+ searchIcon: cn6(d3.searchIcon, overrides?.searchIcon),
1526
+ searchInput: cn6(d3.searchInput, overrides?.searchInput),
1527
+ noMatchesMessage: cn6(d3.noMatchesMessage, overrides?.noMatchesMessage),
1528
+ emptyMessage: cn6(d3.emptyMessage, overrides?.emptyMessage),
1529
+ list: cn6(d3.list, overrides?.list),
1530
+ locationRow: cn6(d3.locationRow, overrides?.locationRow),
1531
+ locationRowSelected: cn6(
1159
1532
  d3.locationRowSelected,
1160
1533
  overrides?.locationRowSelected
1161
1534
  ),
1162
- locationRowUnselected: cn5(
1535
+ locationRowUnselected: cn6(
1163
1536
  d3.locationRowUnselected,
1164
1537
  overrides?.locationRowUnselected
1165
1538
  ),
1166
- locationButton: cn5(d3.locationButton, overrides?.locationButton),
1167
- locationName: cn5(d3.locationName, overrides?.locationName),
1168
- locationAddress: cn5(d3.locationAddress, overrides?.locationAddress),
1169
- selectButton: cn5(d3.selectButton, overrides?.selectButton)
1539
+ locationButton: cn6(d3.locationButton, overrides?.locationButton),
1540
+ locationName: cn6(d3.locationName, overrides?.locationName),
1541
+ locationAddress: cn6(d3.locationAddress, overrides?.locationAddress),
1542
+ selectButton: cn6(d3.selectButton, overrides?.selectButton)
1170
1543
  };
1171
1544
  }
1172
1545
  function FindLocation({
@@ -1175,8 +1548,8 @@ function FindLocation({
1175
1548
  onSelect,
1176
1549
  itemClasses
1177
1550
  }) {
1178
- const [query, setQuery] = useState4("");
1179
- const [selected, setSelected] = useState4(
1551
+ const [query, setQuery] = useState5("");
1552
+ const [selected, setSelected] = useState5(
1180
1553
  () => initialSelected ?? null
1181
1554
  );
1182
1555
  const slots = mergeFindLocationItemClasses(itemClasses);
@@ -1187,10 +1560,10 @@ function FindLocation({
1187
1560
  );
1188
1561
  const trimmedQuery = query.trim();
1189
1562
  const noMatches = trimmedQuery.length > 0 && locations.every((location) => matchRank(location, trimmedQuery) === 2);
1190
- return /* @__PURE__ */ jsxs6("div", { className: slots.baseContainer, children: [
1191
- /* @__PURE__ */ jsxs6("div", { className: slots.searchContainer, children: [
1192
- /* @__PURE__ */ jsx6(Search, { className: slots.searchIcon, strokeWidth: 2 }),
1193
- /* @__PURE__ */ jsx6(
1563
+ return /* @__PURE__ */ jsxs14("div", { className: slots.baseContainer, children: [
1564
+ /* @__PURE__ */ jsxs14("div", { className: slots.searchContainer, children: [
1565
+ /* @__PURE__ */ jsx15(Search, { className: slots.searchIcon, strokeWidth: 2 }),
1566
+ /* @__PURE__ */ jsx15(
1194
1567
  "input",
1195
1568
  {
1196
1569
  type: "search",
@@ -1202,22 +1575,22 @@ function FindLocation({
1202
1575
  }
1203
1576
  )
1204
1577
  ] }),
1205
- noMatches && /* @__PURE__ */ jsxs6("p", { className: slots.noMatchesMessage, children: [
1578
+ noMatches && /* @__PURE__ */ jsxs14("p", { className: slots.noMatchesMessage, children: [
1206
1579
  "No locations match \u201C",
1207
1580
  trimmedQuery,
1208
1581
  "\u201D. Showing all locations anyway."
1209
1582
  ] }),
1210
- ranked.length === 0 ? /* @__PURE__ */ jsx6("p", { className: slots.emptyMessage, children: "No locations available." }) : /* @__PURE__ */ jsx6("ul", { className: slots.list, children: ranked.map((location) => {
1583
+ ranked.length === 0 ? /* @__PURE__ */ jsx15("p", { className: slots.emptyMessage, children: "No locations available." }) : /* @__PURE__ */ jsx15("ul", { className: slots.list, children: ranked.map((location) => {
1211
1584
  const isSelected = selected?.location_id === location.location_id;
1212
- return /* @__PURE__ */ jsxs6(
1585
+ return /* @__PURE__ */ jsxs14(
1213
1586
  "li",
1214
1587
  {
1215
- className: cn5(
1588
+ className: cn6(
1216
1589
  slots.locationRow,
1217
1590
  isSelected ? slots.locationRowSelected : slots.locationRowUnselected
1218
1591
  ),
1219
1592
  children: [
1220
- /* @__PURE__ */ jsxs6(
1593
+ /* @__PURE__ */ jsxs14(
1221
1594
  "button",
1222
1595
  {
1223
1596
  type: "button",
@@ -1225,12 +1598,12 @@ function FindLocation({
1225
1598
  "aria-pressed": isSelected,
1226
1599
  className: slots.locationButton,
1227
1600
  children: [
1228
- /* @__PURE__ */ jsx6("p", { className: slots.locationName, children: location.name }),
1229
- location.address && /* @__PURE__ */ jsx6("p", { className: slots.locationAddress, children: location.address })
1601
+ /* @__PURE__ */ jsx15("p", { className: slots.locationName, children: location.name }),
1602
+ location.address && /* @__PURE__ */ jsx15("p", { className: slots.locationAddress, children: location.address })
1230
1603
  ]
1231
1604
  }
1232
1605
  ),
1233
- isSelected && /* @__PURE__ */ jsx6(
1606
+ isSelected && /* @__PURE__ */ jsx15(
1234
1607
  "button",
1235
1608
  {
1236
1609
  type: "button",
@@ -1247,40 +1620,7 @@ function FindLocation({
1247
1620
  ] });
1248
1621
  }
1249
1622
 
1250
- // src/components/CheckoutForm.tsx
1251
- import { useEffect as useEffect3, useState as useState5 } from "react";
1252
- import Link4 from "next/link";
1253
- import {
1254
- Elements,
1255
- PaymentElement,
1256
- useElements,
1257
- useStripe
1258
- } from "@stripe/react-stripe-js";
1259
- import { Minus as Minus2, Pencil, Plus as Plus2 } from "lucide-react";
1260
- import {
1261
- useCart,
1262
- useCustomer as useCustomer2,
1263
- useLocation,
1264
- useModal,
1265
- usePayment,
1266
- usePromotions
1267
- } from "@zorgo/next";
1268
- import {
1269
- DynamicFormShell,
1270
- NameFields,
1271
- PhoneField,
1272
- EmailField,
1273
- FieldError,
1274
- CheckboxField,
1275
- SubmitButton
1276
- } from "@zorgo/next";
1277
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1278
- function money4(cents) {
1279
- return `$${(cents / 100).toFixed(2)}`;
1280
- }
1281
- function cn6(...parts) {
1282
- return parts.filter(Boolean).join(" ");
1283
- }
1623
+ // src/components/client/CheckoutForm/classes.ts
1284
1624
  var CHECKOUT_FORM_DEFAULT_ITEM_CLASSES = {
1285
1625
  shell: "",
1286
1626
  shellInner: "max-w-2xl mx-auto w-full flex flex-col gap-6",
@@ -1333,522 +1673,208 @@ var CHECKOUT_FORM_DEFAULT_ITEM_CLASSES = {
1333
1673
  };
1334
1674
  function mergeCheckoutFormItemClasses(overrides) {
1335
1675
  const d3 = CHECKOUT_FORM_DEFAULT_ITEM_CLASSES;
1336
- return {
1337
- shell: cn6(d3.shell, overrides?.shell),
1338
- shellInner: cn6(d3.shellInner, overrides?.shellInner),
1339
- pageTitle: cn6(d3.pageTitle, overrides?.pageTitle),
1340
- primaryButton: cn6(d3.primaryButton, overrides?.primaryButton),
1341
- secondaryButton: cn6(d3.secondaryButton, overrides?.secondaryButton),
1342
- incrementButton: cn6(d3.incrementButton, overrides?.incrementButton),
1343
- surface: cn6(d3.surface, overrides?.surface),
1344
- fieldInput: cn6(d3.fieldInput, overrides?.fieldInput),
1345
- fieldContainer: cn6(d3.fieldContainer, overrides?.fieldContainer),
1346
- fieldLabel: cn6(d3.fieldLabel, overrides?.fieldLabel),
1347
- fieldError: cn6(d3.fieldError, overrides?.fieldError),
1348
- statusPanel: cn6(d3.statusPanel, overrides?.statusPanel),
1349
- statusTitle: cn6(d3.statusTitle, overrides?.statusTitle),
1350
- statusMessage: cn6(d3.statusMessage, overrides?.statusMessage),
1351
- statusMessageError: cn6(
1352
- d3.statusMessageError,
1353
- overrides?.statusMessageError
1354
- ),
1355
- statusActions: cn6(d3.statusActions, overrides?.statusActions),
1356
- stepSection: cn6(d3.stepSection, overrides?.stepSection),
1357
- sectionTitle: cn6(d3.sectionTitle, overrides?.sectionTitle),
1358
- cartList: cn6(d3.cartList, overrides?.cartList),
1359
- totals: cn6(d3.totals, overrides?.totals),
1360
- totalsRow: cn6(d3.totalsRow, overrides?.totalsRow),
1361
- totalsDivider: cn6(d3.totalsDivider, overrides?.totalsDivider),
1362
- totalsTotalRow: cn6(d3.totalsTotalRow, overrides?.totalsTotalRow),
1363
- form: cn6(d3.form, overrides?.form),
1364
- formActions: cn6(d3.formActions, overrides?.formActions),
1365
- submitError: cn6(d3.submitError, overrides?.submitError),
1366
- paymentSurface: cn6(d3.paymentSurface, overrides?.paymentSurface),
1367
- steps: cn6(d3.steps, overrides?.steps),
1368
- stepBadge: cn6(d3.stepBadge, overrides?.stepBadge),
1369
- stepBadgeActive: cn6(d3.stepBadgeActive, overrides?.stepBadgeActive),
1370
- stepBadgeInactive: cn6(
1371
- d3.stepBadgeInactive,
1372
- overrides?.stepBadgeInactive
1373
- ),
1374
- stepLabel: cn6(d3.stepLabel, overrides?.stepLabel),
1375
- stepLabelActive: cn6(d3.stepLabelActive, overrides?.stepLabelActive),
1376
- stepLabelInactive: cn6(
1377
- d3.stepLabelInactive,
1378
- overrides?.stepLabelInactive
1379
- ),
1380
- stepDivider: cn6(d3.stepDivider, overrides?.stepDivider),
1381
- stepDividerActive: cn6(
1382
- d3.stepDividerActive,
1383
- overrides?.stepDividerActive
1384
- ),
1385
- stepDividerInactive: cn6(
1386
- d3.stepDividerInactive,
1387
- overrides?.stepDividerInactive
1388
- ),
1389
- cartLine: cn6(d3.cartLine, overrides?.cartLine),
1390
- cartLineName: cn6(d3.cartLineName, overrides?.cartLineName),
1391
- cartLineSelection: cn6(
1392
- d3.cartLineSelection,
1393
- overrides?.cartLineSelection
1394
- ),
1395
- cartLinePrice: cn6(d3.cartLinePrice, overrides?.cartLinePrice),
1396
- cartLineControls: cn6(d3.cartLineControls, overrides?.cartLineControls),
1397
- cartLineQuantity: cn6(d3.cartLineQuantity, overrides?.cartLineQuantity),
1398
- promoApplied: cn6(d3.promoApplied, overrides?.promoApplied),
1399
- promoAppliedLabel: cn6(
1400
- d3.promoAppliedLabel,
1401
- overrides?.promoAppliedLabel
1402
- ),
1403
- promoRow: cn6(d3.promoRow, overrides?.promoRow),
1404
- promoInput: cn6(d3.promoInput, overrides?.promoInput),
1405
- promoError: cn6(d3.promoError, overrides?.promoError)
1406
- };
1676
+ return Object.fromEntries(
1677
+ Object.keys(d3).map((key) => [
1678
+ key,
1679
+ cn3(d3[key], overrides?.[key])
1680
+ ])
1681
+ );
1407
1682
  }
1408
- function CheckoutForm({
1409
- itemClasses,
1410
- homeHref = "/",
1411
- menuHref = "/menu",
1412
- checkoutHref = "/checkout"
1683
+ var CHECKOUT_FORM_SLOTS = mergeCheckoutFormItemClasses();
1684
+
1685
+ // src/components/client/CheckoutForm/CheckoutForm.tsx
1686
+ import { useEffect as useEffect3, useState as useState9 } from "react";
1687
+ import Link4 from "next/link";
1688
+ import { Elements } from "@stripe/react-stripe-js";
1689
+ import {
1690
+ useCart as useCart4,
1691
+ useLocation,
1692
+ useModal as useModal2,
1693
+ usePayment as usePayment3
1694
+ } from "@zorgo/next";
1695
+
1696
+ // src/components/client/CheckoutForm/CheckoutShell.tsx
1697
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1698
+ function CheckoutShell({
1699
+ children,
1700
+ title = "Checkout",
1701
+ slots = CHECKOUT_FORM_SLOTS
1413
1702
  }) {
1414
- const slots = mergeCheckoutFormItemClasses(itemClasses);
1415
- const {
1416
- clientSecret,
1417
- stripe,
1418
- elementOptions,
1419
- isReady,
1420
- isLoading,
1421
- error,
1422
- getReturnStatus
1423
- } = usePayment();
1424
- const { isEmpty, resetCart } = useCart();
1425
- const { currentLocation, needsLocationSelection } = useLocation({
1426
- promptLocationSelection: true
1427
- });
1428
- const { open } = useModal();
1429
- const [returnStatus, setReturnStatus] = useState5(null);
1430
- useEffect3(() => {
1431
- if (window.location.search.includes("redirect_status")) {
1432
- const status = getReturnStatus(window.location.href);
1433
- setReturnStatus(status);
1434
- if (status.succeeded) resetCart();
1435
- }
1436
- }, []);
1437
- if (returnStatus) {
1438
- return /* @__PURE__ */ jsx7(Shell, { slots, children: returnStatus.succeeded ? /* @__PURE__ */ jsx7(
1439
- StatusPanel,
1440
- {
1441
- slots,
1442
- title: "You're all set",
1443
- message: "Payment successful. Thank you!",
1444
- action: /* @__PURE__ */ jsx7(
1445
- Link4,
1446
- {
1447
- href: homeHref,
1448
- className: cn6(
1449
- slots.primaryButton,
1450
- "block w-full text-center"
1451
- ),
1452
- children: "Back home"
1453
- }
1454
- )
1455
- }
1456
- ) : /* @__PURE__ */ jsx7(
1457
- StatusPanel,
1458
- {
1459
- slots,
1460
- title: "Payment didn't go through",
1461
- message: returnStatus.error,
1462
- tone: "error",
1463
- action: /* @__PURE__ */ jsx7(
1464
- Link4,
1465
- {
1466
- href: checkoutHref,
1467
- className: cn6(
1468
- slots.primaryButton,
1469
- "block w-full text-center"
1470
- ),
1471
- children: "Try again"
1472
- }
1473
- )
1474
- }
1475
- ) });
1476
- }
1477
- if (isEmpty && !isLoading && !clientSecret) {
1478
- return /* @__PURE__ */ jsx7(Shell, { slots, children: /* @__PURE__ */ jsx7(
1479
- StatusPanel,
1480
- {
1481
- slots,
1482
- title: "Your cart is empty",
1483
- message: "Add something from the menu to get started.",
1484
- action: /* @__PURE__ */ jsx7(
1485
- Link4,
1703
+ return /* @__PURE__ */ jsx16("div", { className: slots.shell, children: /* @__PURE__ */ jsxs15("div", { className: slots.shellInner, children: [
1704
+ /* @__PURE__ */ jsx16("h1", { className: slots.pageTitle, children: title }),
1705
+ children
1706
+ ] }) });
1707
+ }
1708
+
1709
+ // src/components/client/CheckoutForm/DetailsStep.tsx
1710
+ import { useState as useState7 } from "react";
1711
+ import { DynamicFormShell, SubmitButton as SubmitButton2 } from "@zorgo/next";
1712
+ import { useCart as useCart3, useCustomer as useCustomer3, usePayment } from "@zorgo/next";
1713
+
1714
+ // src/components/client/CheckoutForm/CheckoutSteps.tsx
1715
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
1716
+ function CheckoutSteps({
1717
+ current,
1718
+ labels = ["Your details", "Payment"],
1719
+ slots = CHECKOUT_FORM_SLOTS
1720
+ }) {
1721
+ return /* @__PURE__ */ jsx17("div", { className: slots.steps, children: labels.map((label, i4) => {
1722
+ const n3 = i4 + 1;
1723
+ const active = n3 <= current;
1724
+ return /* @__PURE__ */ jsxs16("div", { className: "contents", children: [
1725
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
1726
+ /* @__PURE__ */ jsx17(
1727
+ "div",
1486
1728
  {
1487
- href: menuHref,
1488
- className: cn6(
1489
- slots.primaryButton,
1490
- "block w-full text-center"
1729
+ className: cn3(
1730
+ slots.stepBadge,
1731
+ active ? slots.stepBadgeActive : slots.stepBadgeInactive
1491
1732
  ),
1492
- children: "Browse the menu"
1733
+ children: n3
1493
1734
  }
1494
- )
1495
- }
1496
- ) });
1497
- }
1498
- if (error) {
1499
- return /* @__PURE__ */ jsx7(Shell, { slots, children: /* @__PURE__ */ jsx7(
1500
- StatusPanel,
1501
- {
1502
- slots,
1503
- title: "Something went wrong",
1504
- message: error,
1505
- tone: "error",
1506
- action: /* @__PURE__ */ jsx7(
1507
- Link4,
1735
+ ),
1736
+ /* @__PURE__ */ jsx17(
1737
+ "p",
1508
1738
  {
1509
- href: menuHref,
1510
- className: cn6(
1511
- slots.primaryButton,
1512
- "block w-full text-center"
1739
+ className: cn3(
1740
+ slots.stepLabel,
1741
+ active ? slots.stepLabelActive : slots.stepLabelInactive
1513
1742
  ),
1514
- children: "Back to menu"
1515
- }
1516
- )
1517
- }
1518
- ) });
1519
- }
1520
- if (needsLocationSelection) {
1521
- return /* @__PURE__ */ jsx7(Shell, { slots, children: /* @__PURE__ */ jsx7(
1522
- StatusPanel,
1523
- {
1524
- slots,
1525
- title: "Choose a location",
1526
- message: "Please choose a location to continue checkout.",
1527
- action: /* @__PURE__ */ jsx7(
1528
- "button",
1529
- {
1530
- type: "button",
1531
- onClick: () => open("FIND_LOCATION_MODAL"),
1532
- className: cn6(slots.primaryButton, "w-full"),
1533
- children: "Select a location"
1743
+ children: label
1534
1744
  }
1535
1745
  )
1536
- }
1537
- ) });
1538
- }
1539
- if (isReady && elementOptions) {
1540
- return /* @__PURE__ */ jsx7(Shell, { slots, children: /* @__PURE__ */ jsx7(
1541
- Elements,
1542
- {
1543
- stripe,
1544
- options: elementOptions,
1545
- children: /* @__PURE__ */ jsx7(PaymentStep, { slots, checkoutHref })
1546
- },
1547
- currentLocation?.stripe_account_id
1548
- ) });
1549
- }
1550
- return /* @__PURE__ */ jsx7(Shell, { slots, children: /* @__PURE__ */ jsx7(DetailsStep, { slots }) });
1746
+ ] }),
1747
+ i4 < labels.length - 1 && /* @__PURE__ */ jsx17(
1748
+ "div",
1749
+ {
1750
+ className: cn3(
1751
+ slots.stepDivider,
1752
+ current > n3 ? slots.stepDividerActive : slots.stepDividerInactive
1753
+ )
1754
+ }
1755
+ )
1756
+ ] }, label);
1757
+ }) });
1551
1758
  }
1552
- function StatusPanel({
1553
- title,
1554
- message,
1555
- action,
1556
- tone = "default",
1557
- slots
1759
+
1760
+ // src/components/client/CheckoutForm/ConsentFields.tsx
1761
+ import { CheckboxField } from "@zorgo/next";
1762
+ import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
1763
+ function ConsentFields({
1764
+ termsLabel = "I have read and agree to the terms of service.",
1765
+ marketingLabel = "I consent to receive promotions via text and email.",
1766
+ slots = CHECKOUT_FORM_SLOTS
1558
1767
  }) {
1559
- return /* @__PURE__ */ jsxs7("div", { className: cn6(slots.statusPanel, slots.surface), children: [
1560
- /* @__PURE__ */ jsx7("h2", { className: slots.statusTitle, children: title }),
1561
- message && /* @__PURE__ */ jsx7(
1562
- "p",
1768
+ return /* @__PURE__ */ jsxs17(Fragment4, { children: [
1769
+ /* @__PURE__ */ jsx18(
1770
+ CheckboxField,
1563
1771
  {
1564
- className: tone === "error" ? slots.statusMessageError : slots.statusMessage,
1565
- children: message
1772
+ fieldId: "termsAccepted",
1773
+ required: true,
1774
+ requiredText: "You must agree to the terms of service to continue.",
1775
+ fieldErrorClassName: slots.fieldError,
1776
+ children: termsLabel
1566
1777
  }
1567
1778
  ),
1568
- /* @__PURE__ */ jsx7("div", { className: slots.statusActions, children: action })
1779
+ /* @__PURE__ */ jsx18(CheckboxField, { fieldId: "marketingConsent", required: false, children: marketingLabel })
1569
1780
  ] });
1570
1781
  }
1571
- function DetailsStep({ slots }) {
1572
- const {
1573
- items,
1574
- subtotal,
1575
- discount,
1576
- tax,
1577
- serviceFee,
1578
- total,
1579
- removeItem,
1580
- resetCart
1581
- } = useCart();
1582
- const { customer, setCustomer } = useCustomer2();
1583
- const { startCheckout } = usePayment();
1584
- const [submitError, setSubmitError] = useState5();
1585
- const fieldContainerClass = slots.fieldContainer;
1782
+
1783
+ // src/components/client/CheckoutForm/ContactFields.tsx
1784
+ import {
1785
+ NameFields,
1786
+ PhoneField,
1787
+ EmailField,
1788
+ FieldError
1789
+ } from "@zorgo/next";
1790
+ import { useCustomer as useCustomer2 } from "@zorgo/next";
1791
+ import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
1792
+ function ContactFields({
1793
+ slots = CHECKOUT_FORM_SLOTS
1794
+ }) {
1795
+ const { customer } = useCustomer2();
1586
1796
  const fieldStyleProps = {
1587
1797
  fieldClassName: slots.fieldInput,
1588
- containerClassName: fieldContainerClass,
1798
+ containerClassName: slots.fieldContainer,
1589
1799
  fieldLabelClassName: slots.fieldLabel,
1590
1800
  fieldErrorClassName: slots.fieldError
1591
1801
  };
1592
- const handleSubmit = async (values) => {
1593
- const filledCustomer = {
1594
- first_name: values.firstName,
1595
- last_name: values.lastName,
1596
- phone: values.phone,
1597
- email: values.email,
1598
- allow_marketing: values.marketingConsent
1599
- };
1600
- setCustomer(filledCustomer);
1601
- try {
1602
- await startCheckout();
1603
- } catch (err) {
1604
- setSubmitError(
1605
- err instanceof Error ? err.message : "Could not start payment."
1606
- );
1607
- }
1608
- };
1609
- return /* @__PURE__ */ jsxs7("div", { className: slots.stepSection, children: [
1610
- /* @__PURE__ */ jsx7(Steps, { current: 1, slots }),
1611
- /* @__PURE__ */ jsx7("h2", { className: slots.sectionTitle, children: "Your order" }),
1612
- /* @__PURE__ */ jsx7("div", { className: slots.cartList, children: items.map((item, index) => /* @__PURE__ */ jsx7(
1613
- CartLine,
1802
+ return /* @__PURE__ */ jsxs18(Fragment5, { children: [
1803
+ /* @__PURE__ */ jsx19(
1804
+ NameFields,
1614
1805
  {
1615
- item,
1616
- index,
1617
- onRemove: () => removeItem(index),
1618
- slots
1619
- },
1620
- `${item.item_id}-${index}`
1621
- )) }),
1622
- /* @__PURE__ */ jsxs7("div", { className: cn6(slots.totals, slots.surface), children: [
1623
- /* @__PURE__ */ jsxs7("div", { className: slots.totalsRow, children: [
1624
- /* @__PURE__ */ jsx7("span", { children: "Subtotal" }),
1625
- /* @__PURE__ */ jsx7("span", { children: money4(subtotal) })
1626
- ] }),
1627
- discount > 0 && /* @__PURE__ */ jsxs7("div", { className: slots.totalsRow, children: [
1628
- /* @__PURE__ */ jsx7("span", { children: "Discount" }),
1629
- /* @__PURE__ */ jsx7("span", { children: money4(-discount) })
1630
- ] }),
1631
- /* @__PURE__ */ jsxs7("div", { className: slots.totalsRow, children: [
1632
- /* @__PURE__ */ jsx7("span", { children: "Tax" }),
1633
- /* @__PURE__ */ jsx7("span", { children: money4(tax) })
1634
- ] }),
1635
- serviceFee > 0 && /* @__PURE__ */ jsxs7("div", { className: slots.totalsRow, children: [
1636
- /* @__PURE__ */ jsx7("span", { children: "Service fee" }),
1637
- /* @__PURE__ */ jsx7("span", { children: serviceFee })
1638
- ] }),
1639
- /* @__PURE__ */ jsx7("div", { className: slots.totalsDivider }),
1640
- /* @__PURE__ */ jsxs7("div", { className: slots.totalsTotalRow, children: [
1641
- /* @__PURE__ */ jsx7("span", { children: "Total" }),
1642
- /* @__PURE__ */ jsx7("span", { children: money4(total) })
1643
- ] })
1644
- ] }),
1645
- /* @__PURE__ */ jsx7(PromoCode, { slots }),
1646
- /* @__PURE__ */ jsx7("h2", { className: slots.sectionTitle, children: "Contact information" }),
1647
- /* @__PURE__ */ jsxs7(DynamicFormShell, { onSubmit: handleSubmit, className: slots.form, children: [
1648
- /* @__PURE__ */ jsx7(
1649
- NameFields,
1806
+ firstNameInitialValue: customer.first_name ?? "",
1807
+ lastNameInitialValue: customer.last_name ?? "",
1808
+ fieldClassName: slots.fieldInput,
1809
+ fieldLabelClassName: slots.fieldLabel,
1810
+ fieldErrorClassName: slots.fieldError,
1811
+ childClassName: cn3(
1812
+ slots.fieldContainer,
1813
+ "md:flex-1 md:min-w-0"
1814
+ )
1815
+ }
1816
+ ),
1817
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col w-full gap-1", children: [
1818
+ /* @__PURE__ */ jsx19(
1819
+ PhoneField,
1650
1820
  {
1651
- firstNameInitialValue: customer.first_name ?? "",
1652
- lastNameInitialValue: customer.last_name ?? "",
1653
- fieldClassName: slots.fieldInput,
1654
- fieldLabelClassName: slots.fieldLabel,
1655
- fieldErrorClassName: slots.fieldError,
1656
- childClassName: cn6(
1657
- fieldContainerClass,
1658
- "md:flex-1 md:min-w-0"
1659
- )
1821
+ initialValue: customer.phone ?? "",
1822
+ showError: false,
1823
+ ...fieldStyleProps
1660
1824
  }
1661
1825
  ),
1662
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-col w-full gap-1", children: [
1663
- /* @__PURE__ */ jsx7(
1664
- PhoneField,
1665
- {
1666
- initialValue: customer.phone ?? "",
1667
- showError: false,
1668
- ...fieldStyleProps
1669
- }
1670
- ),
1671
- /* @__PURE__ */ jsx7(FieldError, { name: "phone", className: slots.fieldError })
1672
- ] }),
1673
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-col w-full gap-1", children: [
1674
- /* @__PURE__ */ jsx7(
1675
- EmailField,
1676
- {
1677
- initialValue: customer.email ?? "",
1678
- showError: false,
1679
- ...fieldStyleProps
1680
- }
1681
- ),
1682
- /* @__PURE__ */ jsx7(FieldError, { name: "email", className: slots.fieldError })
1683
- ] }),
1684
- /* @__PURE__ */ jsx7(
1685
- CheckboxField,
1826
+ /* @__PURE__ */ jsx19(FieldError, { name: "phone", className: slots.fieldError })
1827
+ ] }),
1828
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col w-full gap-1", children: [
1829
+ /* @__PURE__ */ jsx19(
1830
+ EmailField,
1686
1831
  {
1687
- fieldId: "termsAccepted",
1688
- required: true,
1689
- requiredText: "You must agree to the terms of service to continue.",
1690
- fieldErrorClassName: slots.fieldError,
1691
- children: "I have read and agree to the terms of service."
1832
+ initialValue: customer.email ?? "",
1833
+ showError: false,
1834
+ ...fieldStyleProps
1692
1835
  }
1693
1836
  ),
1694
- /* @__PURE__ */ jsx7(CheckboxField, { fieldId: "marketingConsent", required: false, children: "I consent to receive promotions via text and email." }),
1695
- submitError && /* @__PURE__ */ jsx7("p", { className: slots.submitError, children: submitError }),
1696
- /* @__PURE__ */ jsxs7("div", { className: slots.formActions, children: [
1697
- /* @__PURE__ */ jsx7(
1698
- "button",
1699
- {
1700
- type: "button",
1701
- onClick: resetCart,
1702
- className: slots.secondaryButton,
1703
- children: "Clear cart"
1704
- }
1705
- ),
1706
- /* @__PURE__ */ jsx7(
1707
- SubmitButton,
1708
- {
1709
- label: "Continue to payment",
1710
- loadingLabel: "Setting up...",
1711
- className: cn6("flex-1", slots.primaryButton)
1712
- }
1713
- )
1714
- ] })
1715
- ] })
1716
- ] });
1717
- }
1718
- function PaymentStep({
1719
- slots,
1720
- checkoutHref
1721
- }) {
1722
- const stripe = useStripe();
1723
- const elements = useElements();
1724
- const {
1725
- total,
1726
- clientSecret,
1727
- submitPayment,
1728
- paymentElementOptions,
1729
- getReturnUrl,
1730
- resetCheckout
1731
- } = usePayment();
1732
- const { customer } = useCustomer2();
1733
- const [submitError, setSubmitError] = useState5();
1734
- const handleSubmit = async () => {
1735
- if (!stripe || !elements || !clientSecret) return;
1736
- const { error } = await elements.submit();
1737
- if (error) {
1738
- setSubmitError(error.message ?? "Please check your card details.");
1739
- throw error;
1740
- }
1741
- const returnUrl = `${getReturnUrl()}${checkoutHref.startsWith("/") ? checkoutHref : `/${checkoutHref}`}`;
1742
- const result = await submitPayment(
1743
- stripe,
1744
- elements,
1745
- clientSecret,
1746
- returnUrl,
1747
- customer
1748
- );
1749
- if (!result.success) setSubmitError(result.error);
1750
- };
1751
- return /* @__PURE__ */ jsxs7("div", { className: slots.stepSection, children: [
1752
- /* @__PURE__ */ jsx7(Steps, { current: 2, slots }),
1753
- /* @__PURE__ */ jsxs7(DynamicFormShell, { onSubmit: handleSubmit, className: slots.form, children: [
1754
- /* @__PURE__ */ jsx7("div", { className: cn6(slots.paymentSurface, slots.surface), children: /* @__PURE__ */ jsx7(PaymentElement, { options: paymentElementOptions }) }),
1755
- submitError && /* @__PURE__ */ jsx7("p", { className: slots.submitError, children: submitError }),
1756
- /* @__PURE__ */ jsxs7("div", { className: slots.formActions, children: [
1757
- /* @__PURE__ */ jsx7(
1758
- "button",
1759
- {
1760
- type: "button",
1761
- onClick: resetCheckout,
1762
- className: slots.secondaryButton,
1763
- children: "Back to order"
1764
- }
1765
- ),
1766
- /* @__PURE__ */ jsx7(
1767
- SubmitButton,
1768
- {
1769
- label: `Pay ${money4(total ?? 0)}`,
1770
- loadingLabel: "Processing...",
1771
- className: cn6("flex-1", slots.primaryButton)
1772
- }
1773
- )
1774
- ] })
1837
+ /* @__PURE__ */ jsx19(FieldError, { name: "email", className: slots.fieldError })
1775
1838
  ] })
1776
1839
  ] });
1777
1840
  }
1778
- function Steps({ current, slots }) {
1779
- const labels = ["Your details", "Payment"];
1780
- return /* @__PURE__ */ jsx7("div", { className: slots.steps, children: labels.map((label, i4) => {
1781
- const n3 = i4 + 1;
1782
- const active = n3 <= current;
1783
- return /* @__PURE__ */ jsxs7("div", { className: "contents", children: [
1784
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1785
- /* @__PURE__ */ jsx7(
1786
- "div",
1787
- {
1788
- className: cn6(
1789
- slots.stepBadge,
1790
- active ? slots.stepBadgeActive : slots.stepBadgeInactive
1791
- ),
1792
- children: n3
1793
- }
1794
- ),
1795
- /* @__PURE__ */ jsx7(
1796
- "p",
1797
- {
1798
- className: cn6(
1799
- slots.stepLabel,
1800
- active ? slots.stepLabelActive : slots.stepLabelInactive
1801
- ),
1802
- children: label
1803
- }
1804
- )
1805
- ] }),
1806
- i4 < labels.length - 1 && /* @__PURE__ */ jsx7(
1807
- "div",
1808
- {
1809
- className: cn6(
1810
- slots.stepDivider,
1811
- current > n3 ? slots.stepDividerActive : slots.stepDividerInactive
1812
- )
1813
- }
1814
- )
1815
- ] }, label);
1816
- }) });
1817
- }
1818
- function CartLine({
1841
+
1842
+ // src/components/client/CheckoutForm/OrderLine.tsx
1843
+ import { Minus as Minus2, Pencil, Plus as Plus2 } from "lucide-react";
1844
+ import { useCart, useModal } from "@zorgo/next";
1845
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
1846
+ function OrderLine({
1819
1847
  item,
1820
1848
  index,
1821
1849
  onRemove,
1822
- slots
1850
+ slots = CHECKOUT_FORM_SLOTS
1823
1851
  }) {
1824
1852
  const { open } = useModal();
1825
1853
  const { updateItem, getItemTotal } = useCart();
1826
1854
  const setQuantity = (next) => next < 1 ? onRemove() : updateItem({ ...item, quantity: next }, index);
1827
- return /* @__PURE__ */ jsxs7("div", { className: cn6(slots.cartLine, slots.surface), children: [
1828
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1 flex-1 min-w-0", children: [
1829
- /* @__PURE__ */ jsx7("p", { className: slots.cartLineName, children: item.name }),
1830
- (() => {
1831
- const added = (item.selections ?? []).flatMap((rs) => rs.selections.map((s5) => s5.name));
1832
- const removed = (item.components ?? []).filter((c6) => c6.quantity_servings === 0).map((c6) => c6.name);
1833
- return /* @__PURE__ */ jsxs7(Fragment3, { children: [
1834
- added.length > 0 && /* @__PURE__ */ jsxs7("p", { className: slots.cartLineSelection, children: [
1835
- "Add ",
1836
- added.join(", ")
1837
- ] }),
1838
- removed.length > 0 && /* @__PURE__ */ jsxs7("p", { className: slots.cartLineSelection, children: [
1839
- "Remove ",
1840
- removed.join(", ")
1841
- ] }),
1842
- item.comments && /* @__PURE__ */ jsxs7("p", { className: slots.cartLineSelection, children: [
1843
- "Comments: ",
1844
- item.comments
1845
- ] })
1846
- ] });
1847
- })(),
1848
- /* @__PURE__ */ jsx7("p", { className: slots.cartLinePrice, children: money4(getItemTotal(item)) })
1855
+ const added = (item.selections ?? []).flatMap(
1856
+ (rs) => rs.selections.map((s5) => s5.name)
1857
+ );
1858
+ const removed = (item.components ?? []).filter((c6) => c6.quantity_servings === 0).map((c6) => c6.name);
1859
+ return /* @__PURE__ */ jsxs19("div", { className: cn3(slots.cartLine, slots.surface), children: [
1860
+ /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-1 flex-1 min-w-0", children: [
1861
+ /* @__PURE__ */ jsx20("p", { className: slots.cartLineName, children: item.name }),
1862
+ added.length > 0 && /* @__PURE__ */ jsxs19("p", { className: slots.cartLineSelection, children: [
1863
+ "Add ",
1864
+ added.join(", ")
1865
+ ] }),
1866
+ removed.length > 0 && /* @__PURE__ */ jsxs19("p", { className: slots.cartLineSelection, children: [
1867
+ "Remove ",
1868
+ removed.join(", ")
1869
+ ] }),
1870
+ item.comments && /* @__PURE__ */ jsxs19("p", { className: slots.cartLineSelection, children: [
1871
+ "Comments: ",
1872
+ item.comments
1873
+ ] }),
1874
+ /* @__PURE__ */ jsx20("p", { className: slots.cartLinePrice, children: money3(getItemTotal(item)) })
1849
1875
  ] }),
1850
- /* @__PURE__ */ jsxs7("div", { className: slots.cartLineControls, children: [
1851
- /* @__PURE__ */ jsx7(
1876
+ /* @__PURE__ */ jsxs19("div", { className: slots.cartLineControls, children: [
1877
+ /* @__PURE__ */ jsx20(
1852
1878
  "button",
1853
1879
  {
1854
1880
  type: "button",
@@ -1859,41 +1885,96 @@ function CartLine({
1859
1885
  seed: item,
1860
1886
  editIndex: index
1861
1887
  }),
1862
- children: /* @__PURE__ */ jsx7(Pencil, { className: "w-5 h-5" })
1888
+ children: /* @__PURE__ */ jsx20(Pencil, { className: "w-5 h-5" })
1863
1889
  }
1864
1890
  ),
1865
- /* @__PURE__ */ jsx7(
1891
+ /* @__PURE__ */ jsx20(
1866
1892
  "button",
1867
1893
  {
1868
1894
  type: "button",
1869
1895
  className: slots.incrementButton,
1870
1896
  onClick: () => setQuantity(item.quantity - 1),
1871
- children: /* @__PURE__ */ jsx7(Minus2, { className: "w-5 h-5" })
1897
+ children: /* @__PURE__ */ jsx20(Minus2, { className: "w-5 h-5" })
1872
1898
  }
1873
1899
  ),
1874
- /* @__PURE__ */ jsx7("p", { className: slots.cartLineQuantity, children: item.quantity }),
1875
- /* @__PURE__ */ jsx7(
1900
+ /* @__PURE__ */ jsx20("p", { className: slots.cartLineQuantity, children: item.quantity }),
1901
+ /* @__PURE__ */ jsx20(
1876
1902
  "button",
1877
1903
  {
1878
1904
  type: "button",
1879
1905
  className: slots.incrementButton,
1880
1906
  onClick: () => setQuantity(item.quantity + 1),
1881
- children: /* @__PURE__ */ jsx7(Plus2, { className: "w-5 h-5" })
1907
+ children: /* @__PURE__ */ jsx20(Plus2, { className: "w-5 h-5" })
1882
1908
  }
1883
1909
  )
1884
1910
  ] })
1885
1911
  ] });
1886
1912
  }
1887
- function PromoCode({ slots }) {
1913
+ function OrderLines({
1914
+ slots = CHECKOUT_FORM_SLOTS
1915
+ }) {
1916
+ const { items, removeItem } = useCart();
1917
+ return /* @__PURE__ */ jsx20("div", { className: slots.cartList, children: items.map((item, index) => /* @__PURE__ */ jsx20(
1918
+ OrderLine,
1919
+ {
1920
+ item,
1921
+ index,
1922
+ onRemove: () => removeItem(index),
1923
+ slots
1924
+ },
1925
+ `${item.item_id}-${index}`
1926
+ )) });
1927
+ }
1928
+
1929
+ // src/components/client/CheckoutForm/OrderTotals.tsx
1930
+ import { useCart as useCart2 } from "@zorgo/next";
1931
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
1932
+ function OrderTotals({
1933
+ slots = CHECKOUT_FORM_SLOTS
1934
+ }) {
1935
+ const { subtotal, discount, tax, serviceFee, total } = useCart2();
1936
+ return /* @__PURE__ */ jsxs20("div", { className: cn3(slots.totals, slots.surface), children: [
1937
+ /* @__PURE__ */ jsxs20("div", { className: slots.totalsRow, children: [
1938
+ /* @__PURE__ */ jsx21("span", { children: "Subtotal" }),
1939
+ /* @__PURE__ */ jsx21("span", { children: money3(subtotal) })
1940
+ ] }),
1941
+ discount > 0 && /* @__PURE__ */ jsxs20("div", { className: slots.totalsRow, children: [
1942
+ /* @__PURE__ */ jsx21("span", { children: "Discount" }),
1943
+ /* @__PURE__ */ jsx21("span", { children: money3(-discount) })
1944
+ ] }),
1945
+ /* @__PURE__ */ jsxs20("div", { className: slots.totalsRow, children: [
1946
+ /* @__PURE__ */ jsx21("span", { children: "Tax" }),
1947
+ /* @__PURE__ */ jsx21("span", { children: money3(tax) })
1948
+ ] }),
1949
+ serviceFee > 0 && /* @__PURE__ */ jsxs20("div", { className: slots.totalsRow, children: [
1950
+ /* @__PURE__ */ jsx21("span", { children: "Service fee" }),
1951
+ /* @__PURE__ */ jsx21("span", { children: money3(serviceFee) })
1952
+ ] }),
1953
+ /* @__PURE__ */ jsx21("div", { className: slots.totalsDivider }),
1954
+ /* @__PURE__ */ jsxs20("div", { className: slots.totalsTotalRow, children: [
1955
+ /* @__PURE__ */ jsx21("span", { children: "Total" }),
1956
+ /* @__PURE__ */ jsx21("span", { children: money3(total) })
1957
+ ] })
1958
+ ] });
1959
+ }
1960
+
1961
+ // src/components/client/CheckoutForm/PromoCode.tsx
1962
+ import { useState as useState6 } from "react";
1963
+ import { usePromotions } from "@zorgo/next";
1964
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
1965
+ function PromoCode({
1966
+ placeholder = "Promo code",
1967
+ slots = CHECKOUT_FORM_SLOTS
1968
+ }) {
1888
1969
  const { promoCode, appliedPromo, applyPromo, removePromo, error, loading } = usePromotions();
1889
- const [draft, setDraft] = useState5("");
1970
+ const [draft, setDraft] = useState6("");
1890
1971
  if (appliedPromo) {
1891
- return /* @__PURE__ */ jsxs7("div", { className: cn6(slots.promoApplied, slots.surface), children: [
1892
- /* @__PURE__ */ jsxs7("span", { className: slots.promoAppliedLabel, children: [
1972
+ return /* @__PURE__ */ jsxs21("div", { className: cn3(slots.promoApplied, slots.surface), children: [
1973
+ /* @__PURE__ */ jsxs21("span", { className: slots.promoAppliedLabel, children: [
1893
1974
  appliedPromo.name,
1894
1975
  " applied"
1895
1976
  ] }),
1896
- promoCode && /* @__PURE__ */ jsx7(
1977
+ promoCode && /* @__PURE__ */ jsx22(
1897
1978
  "button",
1898
1979
  {
1899
1980
  type: "button",
@@ -1904,39 +1985,294 @@ function PromoCode({ slots }) {
1904
1985
  )
1905
1986
  ] });
1906
1987
  }
1907
- return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-2 w-full", children: [
1908
- /* @__PURE__ */ jsxs7("div", { className: slots.promoRow, children: [
1909
- /* @__PURE__ */ jsx7(
1988
+ return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2 w-full", children: [
1989
+ /* @__PURE__ */ jsxs21("div", { className: slots.promoRow, children: [
1990
+ /* @__PURE__ */ jsx22(
1910
1991
  "input",
1911
1992
  {
1912
1993
  value: draft,
1913
1994
  onChange: (e) => setDraft(e.target.value),
1914
- placeholder: "Promo code",
1995
+ placeholder,
1915
1996
  className: slots.promoInput
1916
1997
  }
1917
1998
  ),
1918
- /* @__PURE__ */ jsx7(
1999
+ /* @__PURE__ */ jsx22(
1919
2000
  "button",
1920
2001
  {
1921
2002
  type: "button",
1922
2003
  disabled: loading || !draft.trim(),
1923
2004
  onClick: () => applyPromo(draft),
1924
- className: cn6(slots.primaryButton, "shrink-0"),
2005
+ className: cn3(slots.primaryButton, "shrink-0"),
1925
2006
  children: loading ? "Applying\u2026" : "Apply"
1926
2007
  }
1927
2008
  )
1928
2009
  ] }),
1929
- error && /* @__PURE__ */ jsx7("p", { className: slots.promoError, children: error })
2010
+ error && /* @__PURE__ */ jsx22("p", { className: slots.promoError, children: error })
1930
2011
  ] });
1931
2012
  }
1932
- function Shell({
1933
- children,
1934
- slots
2013
+
2014
+ // src/components/client/CheckoutForm/DetailsStep.tsx
2015
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2016
+ function DetailsStep({
2017
+ slots = CHECKOUT_FORM_SLOTS
1935
2018
  }) {
1936
- return /* @__PURE__ */ jsx7("div", { className: slots.shell, children: /* @__PURE__ */ jsxs7("div", { className: slots.shellInner, children: [
1937
- /* @__PURE__ */ jsx7("h1", { className: slots.pageTitle, children: "Checkout" }),
1938
- children
1939
- ] }) });
2019
+ const { resetCart } = useCart3();
2020
+ const { setCustomer } = useCustomer3();
2021
+ const { startCheckout } = usePayment();
2022
+ const [submitError, setSubmitError] = useState7();
2023
+ const handleSubmit = async (values) => {
2024
+ const filledCustomer = {
2025
+ first_name: values.firstName,
2026
+ last_name: values.lastName,
2027
+ phone: values.phone,
2028
+ email: values.email,
2029
+ allow_marketing: values.marketingConsent
2030
+ };
2031
+ setCustomer(filledCustomer);
2032
+ try {
2033
+ await startCheckout();
2034
+ } catch (err) {
2035
+ setSubmitError(
2036
+ err instanceof Error ? err.message : "Could not start payment."
2037
+ );
2038
+ }
2039
+ };
2040
+ return /* @__PURE__ */ jsxs22("div", { className: slots.stepSection, children: [
2041
+ /* @__PURE__ */ jsx23(CheckoutSteps, { current: 1, slots }),
2042
+ /* @__PURE__ */ jsx23("h2", { className: slots.sectionTitle, children: "Your order" }),
2043
+ /* @__PURE__ */ jsx23(OrderLines, { slots }),
2044
+ /* @__PURE__ */ jsx23(OrderTotals, { slots }),
2045
+ /* @__PURE__ */ jsx23(PromoCode, { slots }),
2046
+ /* @__PURE__ */ jsx23("h2", { className: slots.sectionTitle, children: "Contact information" }),
2047
+ /* @__PURE__ */ jsxs22(DynamicFormShell, { onSubmit: handleSubmit, className: slots.form, children: [
2048
+ /* @__PURE__ */ jsx23(ContactFields, { slots }),
2049
+ /* @__PURE__ */ jsx23(ConsentFields, { slots }),
2050
+ submitError && /* @__PURE__ */ jsx23("p", { className: slots.submitError, children: submitError }),
2051
+ /* @__PURE__ */ jsxs22("div", { className: slots.formActions, children: [
2052
+ /* @__PURE__ */ jsx23(
2053
+ "button",
2054
+ {
2055
+ type: "button",
2056
+ onClick: resetCart,
2057
+ className: slots.secondaryButton,
2058
+ children: "Clear cart"
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsx23(
2062
+ SubmitButton2,
2063
+ {
2064
+ label: "Continue to payment",
2065
+ loadingLabel: "Setting up...",
2066
+ className: cn3("flex-1", slots.primaryButton)
2067
+ }
2068
+ )
2069
+ ] })
2070
+ ] })
2071
+ ] });
2072
+ }
2073
+
2074
+ // src/components/client/CheckoutForm/PaymentStep.tsx
2075
+ import { useState as useState8 } from "react";
2076
+ import { PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js";
2077
+ import { DynamicFormShell as DynamicFormShell2, SubmitButton as SubmitButton3 } from "@zorgo/next";
2078
+ import { useCustomer as useCustomer4, usePayment as usePayment2 } from "@zorgo/next";
2079
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
2080
+ function PaymentStep({
2081
+ slots = CHECKOUT_FORM_SLOTS,
2082
+ checkoutHref = "/checkout"
2083
+ }) {
2084
+ const stripe = useStripe();
2085
+ const elements = useElements();
2086
+ const {
2087
+ total,
2088
+ clientSecret,
2089
+ submitPayment,
2090
+ paymentElementOptions,
2091
+ getReturnUrl,
2092
+ resetCheckout
2093
+ } = usePayment2();
2094
+ const { customer } = useCustomer4();
2095
+ const [submitError, setSubmitError] = useState8();
2096
+ const handleSubmit = async () => {
2097
+ if (!stripe || !elements || !clientSecret) return;
2098
+ const { error } = await elements.submit();
2099
+ if (error) {
2100
+ setSubmitError(error.message ?? "Please check your card details.");
2101
+ throw error;
2102
+ }
2103
+ const returnUrl = `${getReturnUrl()}${checkoutHref.startsWith("/") ? checkoutHref : `/${checkoutHref}`}`;
2104
+ const result = await submitPayment(
2105
+ stripe,
2106
+ elements,
2107
+ clientSecret,
2108
+ returnUrl,
2109
+ customer
2110
+ );
2111
+ if (!result.success) setSubmitError(result.error);
2112
+ };
2113
+ return /* @__PURE__ */ jsxs23("div", { className: slots.stepSection, children: [
2114
+ /* @__PURE__ */ jsx24(CheckoutSteps, { current: 2, slots }),
2115
+ /* @__PURE__ */ jsxs23(DynamicFormShell2, { onSubmit: handleSubmit, className: slots.form, children: [
2116
+ /* @__PURE__ */ jsx24("div", { className: cn3(slots.paymentSurface, slots.surface), children: /* @__PURE__ */ jsx24(PaymentElement, { options: paymentElementOptions }) }),
2117
+ submitError && /* @__PURE__ */ jsx24("p", { className: slots.submitError, children: submitError }),
2118
+ /* @__PURE__ */ jsxs23("div", { className: slots.formActions, children: [
2119
+ /* @__PURE__ */ jsx24(
2120
+ "button",
2121
+ {
2122
+ type: "button",
2123
+ onClick: resetCheckout,
2124
+ className: slots.secondaryButton,
2125
+ children: "Back to order"
2126
+ }
2127
+ ),
2128
+ /* @__PURE__ */ jsx24(
2129
+ SubmitButton3,
2130
+ {
2131
+ label: `Pay ${money3(total ?? 0)}`,
2132
+ loadingLabel: "Processing...",
2133
+ className: cn3("flex-1", slots.primaryButton)
2134
+ }
2135
+ )
2136
+ ] })
2137
+ ] })
2138
+ ] });
2139
+ }
2140
+
2141
+ // src/components/client/CheckoutForm/StatusPanel.tsx
2142
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
2143
+ function StatusPanel({
2144
+ title,
2145
+ message,
2146
+ action,
2147
+ tone = "default",
2148
+ slots = CHECKOUT_FORM_SLOTS
2149
+ }) {
2150
+ return /* @__PURE__ */ jsxs24("div", { className: cn3(slots.statusPanel, slots.surface), children: [
2151
+ /* @__PURE__ */ jsx25("h2", { className: slots.statusTitle, children: title }),
2152
+ message && /* @__PURE__ */ jsx25(
2153
+ "p",
2154
+ {
2155
+ className: tone === "error" ? slots.statusMessageError : slots.statusMessage,
2156
+ children: message
2157
+ }
2158
+ ),
2159
+ /* @__PURE__ */ jsx25("div", { className: slots.statusActions, children: action })
2160
+ ] });
2161
+ }
2162
+
2163
+ // src/components/client/CheckoutForm/CheckoutForm.tsx
2164
+ import { jsx as jsx26 } from "react/jsx-runtime";
2165
+ function CheckoutForm({
2166
+ itemClasses,
2167
+ homeHref = "/",
2168
+ menuHref = "/menu",
2169
+ checkoutHref = "/checkout"
2170
+ }) {
2171
+ const slots = mergeCheckoutFormItemClasses(itemClasses);
2172
+ const {
2173
+ clientSecret,
2174
+ stripe,
2175
+ elementOptions,
2176
+ isReady,
2177
+ isLoading,
2178
+ error,
2179
+ getReturnStatus
2180
+ } = usePayment3();
2181
+ const { isEmpty, resetCart } = useCart4();
2182
+ const { currentLocation, needsLocationSelection } = useLocation({
2183
+ promptLocationSelection: true
2184
+ });
2185
+ const { open } = useModal2();
2186
+ const [returnStatus, setReturnStatus] = useState9(null);
2187
+ useEffect3(() => {
2188
+ if (window.location.search.includes("redirect_status")) {
2189
+ const status = getReturnStatus(window.location.href);
2190
+ setReturnStatus(status);
2191
+ if (status.succeeded) resetCart();
2192
+ }
2193
+ }, []);
2194
+ const linkAction = (href, label) => /* @__PURE__ */ jsx26(
2195
+ Link4,
2196
+ {
2197
+ href,
2198
+ className: cn3(slots.primaryButton, "block w-full text-center"),
2199
+ children: label
2200
+ }
2201
+ );
2202
+ if (returnStatus) {
2203
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: returnStatus.succeeded ? /* @__PURE__ */ jsx26(
2204
+ StatusPanel,
2205
+ {
2206
+ slots,
2207
+ title: "You're all set",
2208
+ message: "Payment successful. Thank you!",
2209
+ action: linkAction(homeHref, "Back home")
2210
+ }
2211
+ ) : /* @__PURE__ */ jsx26(
2212
+ StatusPanel,
2213
+ {
2214
+ slots,
2215
+ title: "Payment didn't go through",
2216
+ message: returnStatus.error,
2217
+ tone: "error",
2218
+ action: linkAction(checkoutHref, "Try again")
2219
+ }
2220
+ ) });
2221
+ }
2222
+ if (isEmpty && !isLoading && !clientSecret) {
2223
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: /* @__PURE__ */ jsx26(
2224
+ StatusPanel,
2225
+ {
2226
+ slots,
2227
+ title: "Your cart is empty",
2228
+ message: "Add something from the menu to get started.",
2229
+ action: linkAction(menuHref, "Browse the menu")
2230
+ }
2231
+ ) });
2232
+ }
2233
+ if (error) {
2234
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: /* @__PURE__ */ jsx26(
2235
+ StatusPanel,
2236
+ {
2237
+ slots,
2238
+ title: "Something went wrong",
2239
+ message: error,
2240
+ tone: "error",
2241
+ action: linkAction(menuHref, "Back to menu")
2242
+ }
2243
+ ) });
2244
+ }
2245
+ if (needsLocationSelection) {
2246
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: /* @__PURE__ */ jsx26(
2247
+ StatusPanel,
2248
+ {
2249
+ slots,
2250
+ title: "Choose a location",
2251
+ message: "Please choose a location to continue checkout.",
2252
+ action: /* @__PURE__ */ jsx26(
2253
+ "button",
2254
+ {
2255
+ type: "button",
2256
+ onClick: () => open("FIND_LOCATION_MODAL"),
2257
+ className: cn3(slots.primaryButton, "w-full"),
2258
+ children: "Select a location"
2259
+ }
2260
+ )
2261
+ }
2262
+ ) });
2263
+ }
2264
+ if (isReady && elementOptions) {
2265
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: /* @__PURE__ */ jsx26(
2266
+ Elements,
2267
+ {
2268
+ stripe,
2269
+ options: elementOptions,
2270
+ children: /* @__PURE__ */ jsx26(PaymentStep, { slots, checkoutHref })
2271
+ },
2272
+ currentLocation?.stripe_account_id
2273
+ ) });
2274
+ }
2275
+ return /* @__PURE__ */ jsx26(CheckoutShell, { slots, children: /* @__PURE__ */ jsx26(DetailsStep, { slots }) });
1940
2276
  }
1941
2277
  export {
1942
2278
  ACCORDION_MENU_DEFAULT_ITEM_CLASSES,
@@ -1944,19 +2280,46 @@ export {
1944
2280
  BREADCRUMBS_DEFAULT_ITEM_CLASSES,
1945
2281
  Breadcrumbs,
1946
2282
  CHECKOUT_FORM_DEFAULT_ITEM_CLASSES,
2283
+ CHECKOUT_FORM_SLOTS,
2284
+ CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES,
2285
+ CLIENT_ITEM_FORM_SLOTS,
1947
2286
  CheckoutForm,
2287
+ CheckoutShell,
2288
+ CheckoutSteps,
2289
+ ClientItemForm,
2290
+ CommentsSection,
2291
+ ComponentsSection,
2292
+ ConsentFields,
2293
+ ContactFields,
1948
2294
  CookieConsent,
2295
+ DetailsStep,
1949
2296
  FIND_LOCATION_DEFAULT_ITEM_CLASSES,
1950
2297
  FindLocation,
1951
2298
  GRID_MENU_DEFAULT_ITEM_CLASSES,
1952
2299
  GridMenu,
1953
- ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES,
1954
- ItemCustomizationForm,
2300
+ CLIENT_ITEM_FORM_DEFAULT_ITEM_CLASSES as ITEM_CUSTOMIZATION_FORM_DEFAULT_ITEM_CLASSES,
2301
+ ClientItemForm as ItemCustomizationClient,
2302
+ ClientItemForm as ItemCustomizationForm,
2303
+ OptionButton,
2304
+ OrderLine,
2305
+ OrderLines,
2306
+ OrderTotals,
2307
+ PaymentStep,
2308
+ PortionPicker,
2309
+ PortionSection,
2310
+ PromoCode,
2311
+ QuantitySection,
2312
+ RuleSection,
2313
+ StatusPanel,
2314
+ SubmitButton,
2315
+ VariantSection,
1955
2316
  mergeAccordionMenuItemClasses,
1956
2317
  mergeBreadcrumbsItemClasses,
1957
2318
  mergeCheckoutFormItemClasses,
2319
+ mergeClientItemFormItemClasses,
1958
2320
  mergeFindLocationItemClasses,
1959
2321
  mergeGridMenuItemClasses,
1960
- mergeItemCustomizationFormItemClasses
2322
+ mergeClientItemFormItemClasses as mergeItemCustomizationFormItemClasses,
2323
+ money3 as money
1961
2324
  };
1962
2325
  //# sourceMappingURL=components.mjs.map