@gait-financial/react 0.1.6 → 0.1.7

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 (3) hide show
  1. package/dist/wc/button.js +1769 -102
  2. package/package.json +3 -1
  3. package/wc/button.js +1769 -102
package/dist/wc/button.js CHANGED
@@ -1,25 +1,128 @@
1
- (function(I){"use strict";function F(r,t){const e=r.replace("#",""),i=parseInt(e,16),a=i>>16&255,n=i>>8&255,o=i&255,d=Math.max(0,Math.floor(a*(1-t))),l=Math.max(0,Math.floor(n*(1-t))),s=Math.max(0,Math.floor(o*(1-t)));return`#${(d<<16|l<<8|s).toString(16).padStart(6,"0")}`}function q(r){const t=r.replace("#",""),e=parseInt(t,16),i=e>>16&255,a=e>>8&255,n=e&255;return(.299*i+.587*a+.114*n)/255<.5}const h={primary:{main:"rgb(47, 44, 37)",dark:"rgb(35, 33, 28)",contrastText:"#ffffff"}},E={sm:"8px",md:"16px",lg:"24px"},P={md:"8px"},f={normal:"250ms ease-in-out"},O={modalBackdrop:1040},y={fontFamily:{primary:'"Inter", "Helvetica", "Arial", sans-serif'},fontSize:{sm:"0.875rem",md:"1rem",lg:"1.125rem"},fontWeight:{medium:500},lineHeight:{normal:1.5}},g="#4147BF",C="#F3F2FF",B={fee:10};function N(r,t){return{bg:g,bgHover:r(g,.15),bgActive:r(g,.25),color:t(g)?"#ffffff":"#000000"}}function G(r){return{small:{padding:"8px 20px",fontSize:y.fontSize.sm,minHeight:"36px"},medium:{padding:"12px 28px",fontSize:y.fontSize.md,minHeight:"44px"},large:{padding:"16px 36px",fontSize:y.fontSize.lg,minHeight:"52px"}}[r]}function D(r,t,e){const i=N(t,e),a=G(r);return`
1
+ (function(exports) {
2
+ "use strict";
3
+ function darkenColor(hex, percent) {
4
+ const color = hex.replace("#", "");
5
+ const num = parseInt(color, 16);
6
+ const r = num >> 16 & 255;
7
+ const g = num >> 8 & 255;
8
+ const b = num & 255;
9
+ const newR = Math.max(0, Math.floor(r * (1 - percent)));
10
+ const newG = Math.max(0, Math.floor(g * (1 - percent)));
11
+ const newB = Math.max(0, Math.floor(b * (1 - percent)));
12
+ return `#${(newR << 16 | newG << 8 | newB).toString(16).padStart(6, "0")}`;
13
+ }
14
+ function isColorDark(hex) {
15
+ const color = hex.replace("#", "");
16
+ const num = parseInt(color, 16);
17
+ const r = num >> 16 & 255;
18
+ const g = num >> 8 & 255;
19
+ const b = num & 255;
20
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
21
+ return luminance < 0.5;
22
+ }
23
+ const colors = {
24
+ // Primary colors (CTA button - dark)
25
+ primary: {
26
+ main: "rgb(47, 44, 37)",
27
+ dark: "rgb(35, 33, 28)",
28
+ contrastText: "#ffffff"
29
+ }
30
+ };
31
+ const spacing = {
32
+ sm: "8px",
33
+ md: "16px",
34
+ lg: "24px"
35
+ };
36
+ const borderRadius = {
37
+ md: "8px"
38
+ };
39
+ const transitions = {
40
+ normal: "250ms ease-in-out"
41
+ };
42
+ const zIndex = {
43
+ modalBackdrop: 1040
44
+ };
45
+ const typography = {
46
+ fontFamily: {
47
+ primary: '"Inter", "Helvetica", "Arial", sans-serif'
48
+ },
49
+ fontSize: {
50
+ // 12px
51
+ sm: "0.875rem",
52
+ // 14px
53
+ md: "1rem",
54
+ // 16px
55
+ lg: "1.125rem"
56
+ },
57
+ fontWeight: {
58
+ medium: 500
59
+ },
60
+ lineHeight: {
61
+ normal: 1.5
62
+ }
63
+ };
64
+ const GAIT_BRAND_COLOR = "#4147BF";
65
+ const GAIT_SECONDARY_COLOR = "#F3F2FF";
66
+ const splitPaymentConfig = {
67
+ /**
68
+ * Split payment fee amount
69
+ * This fee is added to the total cost when using split payment
70
+ */
71
+ fee: 10
72
+ };
73
+ function getThemeStyles(darkenColor2, isColorDark2) {
74
+ return {
75
+ bg: GAIT_BRAND_COLOR,
76
+ bgHover: darkenColor2(GAIT_BRAND_COLOR, 0.15),
77
+ bgActive: darkenColor2(GAIT_BRAND_COLOR, 0.25),
78
+ color: isColorDark2(GAIT_BRAND_COLOR) ? "#ffffff" : "#000000"
79
+ };
80
+ }
81
+ function getSizeStyles(size) {
82
+ const sizeStyles = {
83
+ small: {
84
+ padding: "8px 20px",
85
+ fontSize: typography.fontSize.sm,
86
+ minHeight: "36px"
87
+ },
88
+ medium: {
89
+ padding: "12px 28px",
90
+ fontSize: typography.fontSize.md,
91
+ minHeight: "44px"
92
+ },
93
+ large: {
94
+ padding: "16px 36px",
95
+ fontSize: typography.fontSize.lg,
96
+ minHeight: "52px"
97
+ }
98
+ };
99
+ return sizeStyles[size];
100
+ }
101
+ function generateButtonStyles(size, darkenColorFn, isColorDarkFn) {
102
+ const themeStyles = getThemeStyles(darkenColorFn, isColorDarkFn);
103
+ const currentSize = getSizeStyles(size);
104
+ return `
2
105
  <style>
3
106
  :host {
4
107
  display: inline-block;
5
- --gait-button-bg: ${i.bg};
6
- --gait-button-bg-hover: ${i.bgHover};
7
- --gait-button-bg-active: ${i.bgActive};
8
- --gait-button-color: ${i.color};
9
- --gait-button-padding: ${a.padding};
10
- --gait-button-font-size: ${a.fontSize};
11
- --gait-button-min-height: ${a.minHeight};
108
+ --gait-button-bg: ${themeStyles.bg};
109
+ --gait-button-bg-hover: ${themeStyles.bgHover};
110
+ --gait-button-bg-active: ${themeStyles.bgActive};
111
+ --gait-button-color: ${themeStyles.color};
112
+ --gait-button-padding: ${currentSize.padding};
113
+ --gait-button-font-size: ${currentSize.fontSize};
114
+ --gait-button-min-height: ${currentSize.minHeight};
12
115
  }
13
116
 
14
117
  button {
15
118
  display: inline-flex;
16
119
  align-items: center;
17
120
  justify-content: center;
18
- gap: ${E.sm};
121
+ gap: ${spacing.sm};
19
122
 
20
- font-family: ${y.fontFamily.primary};
21
- font-weight: ${y.fontWeight.medium};
22
- line-height: ${y.lineHeight.normal};
123
+ font-family: ${typography.fontFamily.primary};
124
+ font-weight: ${typography.fontWeight.medium};
125
+ line-height: ${typography.lineHeight.normal};
23
126
  font-size: var(--gait-button-font-size);
24
127
 
25
128
  padding: var(--gait-button-padding);
@@ -29,10 +132,10 @@
29
132
  color: var(--gait-button-color);
30
133
 
31
134
  border: none;
32
- border-radius: ${P.md};
135
+ border-radius: ${borderRadius.md};
33
136
  cursor: pointer;
34
137
 
35
- transition: all ${f.normal};
138
+ transition: all ${transitions.normal};
36
139
 
37
140
  /* Remove default button styles */
38
141
  outline: none;
@@ -81,7 +184,15 @@
81
184
  width: 100%;
82
185
  }
83
186
  </style>
84
- `}function V(){if(document.getElementById("gait-modal-styles"))return;const r=document.createElement("style");r.id="gait-modal-styles",r.textContent=`
187
+ `;
188
+ }
189
+ function injectModalStyles() {
190
+ if (document.getElementById("gait-modal-styles")) {
191
+ return;
192
+ }
193
+ const style = document.createElement("style");
194
+ style.id = "gait-modal-styles";
195
+ style.textContent = `
85
196
  /* Modal Backdrop - The overlay behind the modal */
86
197
  .gait-modal-backdrop {
87
198
  position: fixed;
@@ -93,9 +204,9 @@
93
204
  display: flex;
94
205
  align-items: center;
95
206
  justify-content: center;
96
- z-index: ${O.modalBackdrop};
207
+ z-index: ${zIndex.modalBackdrop};
97
208
  opacity: 0;
98
- transition: opacity ${f.normal};
209
+ transition: opacity ${transitions.normal};
99
210
  overflow: hidden;
100
211
  }
101
212
 
@@ -396,7 +507,7 @@
396
507
  border: 1px solid #e5e7eb;
397
508
  border-radius: 8px;
398
509
  cursor: pointer;
399
- transition: all ${f.normal};
510
+ transition: all ${transitions.normal};
400
511
  color: #6b7280;
401
512
  }
402
513
 
@@ -407,9 +518,9 @@
407
518
  }
408
519
 
409
520
  .gait-modal-split-option.selected {
410
- background: ${C};
411
- border: 1px solid ${g};
412
- color: ${g};
521
+ background: ${GAIT_SECONDARY_COLOR};
522
+ border: 1px solid ${GAIT_BRAND_COLOR};
523
+ color: ${GAIT_BRAND_COLOR};
413
524
  }
414
525
 
415
526
  .gait-modal-email-inputs {
@@ -428,11 +539,11 @@
428
539
  background: #fff;
429
540
  color: #111827;
430
541
  outline: none;
431
- transition: all ${f.normal};
542
+ transition: all ${transitions.normal};
432
543
  }
433
544
 
434
545
  .gait-modal-email-input:focus {
435
- border-color: ${h.primary.main};
546
+ border-color: ${colors.primary.main};
436
547
  box-shadow: 0 0 0 2px rgba(47, 44, 37, 0.1);
437
548
  }
438
549
 
@@ -495,7 +606,7 @@
495
606
 
496
607
  .gait-modal-email-item-amount {
497
608
  font-weight: 500;
498
- color: ${h.primary.main};
609
+ color: ${colors.primary.main};
499
610
  font-size: 14px;
500
611
  }
501
612
 
@@ -514,12 +625,12 @@
514
625
  border: none;
515
626
  cursor: pointer;
516
627
  padding: 2px 4px;
517
- transition: color ${f.normal};
628
+ transition: color ${transitions.normal};
518
629
  }
519
630
 
520
631
  .gait-modal-email-item-edit:hover,
521
632
  .gait-modal-email-item-remove:hover {
522
- color: ${h.primary.main};
633
+ color: ${colors.primary.main};
523
634
  }
524
635
 
525
636
  /* For "By amount" mode - two input fields side by side */
@@ -542,18 +653,18 @@
542
653
  padding: 8px 16px;
543
654
  font-size: 13px;
544
655
  font-weight: 500;
545
- border: 1px solid ${h.primary.main};
656
+ border: 1px solid ${colors.primary.main};
546
657
  border-radius: 6px;
547
- background: ${h.primary.main};
548
- color: ${h.primary.contrastText};
658
+ background: ${colors.primary.main};
659
+ color: ${colors.primary.contrastText};
549
660
  cursor: pointer;
550
- transition: all ${f.normal};
661
+ transition: all ${transitions.normal};
551
662
  white-space: nowrap;
552
663
  }
553
664
 
554
665
  .gait-modal-done-button:hover {
555
- background: ${h.primary.dark};
556
- border-color: ${h.primary.dark};
666
+ background: ${colors.primary.dark};
667
+ border-color: ${colors.primary.dark};
557
668
  }
558
669
 
559
670
  .gait-modal-email-amount-input {
@@ -569,7 +680,7 @@
569
680
  }
570
681
 
571
682
  .gait-modal-email-amount-input:focus {
572
- border-color: ${h.primary.main};
683
+ border-color: ${colors.primary.main};
573
684
  box-shadow: 0 0 0 2px rgba(47, 44, 37, 0.1);
574
685
  }
575
686
 
@@ -581,11 +692,11 @@
581
692
  border: none;
582
693
  cursor: pointer;
583
694
  text-align: left;
584
- transition: color ${f.normal};
695
+ transition: color ${transitions.normal};
585
696
  }
586
697
 
587
698
  .gait-modal-add-email-button:hover {
588
- color: ${h.primary.main};
699
+ color: ${colors.primary.main};
589
700
  text-decoration: underline;
590
701
  }
591
702
 
@@ -605,7 +716,7 @@
605
716
  .gait-modal-split-amount {
606
717
  font-size: 18px;
607
718
  font-weight: 600;
608
- color: ${g};
719
+ color: ${GAIT_BRAND_COLOR};
609
720
  }
610
721
 
611
722
  .gait-modal-send-split-button {
@@ -614,16 +725,16 @@
614
725
  font-size: 14px;
615
726
  font-weight: 500;
616
727
  border-radius: 8px;
617
- border: 1px solid ${g};
618
- background: ${C};
619
- color: ${g};
728
+ border: 1px solid ${GAIT_BRAND_COLOR};
729
+ background: ${GAIT_SECONDARY_COLOR};
730
+ color: ${GAIT_BRAND_COLOR};
620
731
  cursor: pointer;
621
- transition: all ${f.normal};
732
+ transition: all ${transitions.normal};
622
733
  margin-top: 16px;
623
734
  }
624
735
 
625
736
  .gait-modal-send-split-button:hover {
626
- background: ${C};
737
+ background: ${GAIT_SECONDARY_COLOR};
627
738
  filter: brightness(0.98);
628
739
  }
629
740
 
@@ -643,10 +754,10 @@
643
754
  font-weight: 600;
644
755
  border-radius: 10px;
645
756
  border: none;
646
- background: var(--gait-modal-button-bg, ${h.primary.main});
647
- color: var(--gait-modal-button-color, ${h.primary.contrastText});
757
+ background: var(--gait-modal-button-bg, ${colors.primary.main});
758
+ color: var(--gait-modal-button-color, ${colors.primary.contrastText});
648
759
  cursor: pointer;
649
- transition: all ${f.normal};
760
+ transition: all ${transitions.normal};
650
761
  margin-top: 12px;
651
762
  display: flex;
652
763
  flex-direction: row;
@@ -657,7 +768,7 @@
657
768
  }
658
769
 
659
770
  .gait-modal-confirm-button-with-amount:hover {
660
- background-color: var(--gait-modal-button-bg-hover, ${h.primary.dark});
771
+ background-color: var(--gait-modal-button-bg-hover, ${colors.primary.dark});
661
772
  }
662
773
 
663
774
  .gait-modal-confirm-button-with-amount:active {
@@ -704,7 +815,7 @@
704
815
  background: var(--gait-modal-button-bg, #e91e63);
705
816
  color: var(--gait-modal-button-color, #fff);
706
817
  cursor: pointer;
707
- transition: all ${f.normal};
818
+ transition: all ${transitions.normal};
708
819
  }
709
820
 
710
821
  .gait-modal-confirm-button:hover {
@@ -717,29 +828,29 @@
717
828
 
718
829
  /* Modal Footer - The button section */
719
830
  .gait-modal-footer {
720
- padding: ${E.lg};
831
+ padding: ${spacing.lg};
721
832
  border-top: 1px solid #e5e7eb;
722
833
  display: flex;
723
834
  justify-content: flex-end;
724
- gap: ${E.md};
835
+ gap: ${spacing.md};
725
836
  }
726
837
 
727
838
  /* Modal Button - The close button */
728
839
  .gait-modal-button {
729
- padding: ${E.sm} ${E.lg};
730
- font-family: ${y.fontFamily.primary};
731
- font-size: ${y.fontSize.md};
732
- font-weight: ${y.fontWeight.medium};
840
+ padding: ${spacing.sm} ${spacing.lg};
841
+ font-family: ${typography.fontFamily.primary};
842
+ font-size: ${typography.fontSize.md};
843
+ font-weight: ${typography.fontWeight.medium};
733
844
  border: none;
734
- border-radius: ${P.md};
845
+ border-radius: ${borderRadius.md};
735
846
  cursor: pointer;
736
- transition: all ${f.normal};
737
- background-color: ${h.primary.main};
738
- color: ${h.primary.contrastText};
847
+ transition: all ${transitions.normal};
848
+ background-color: ${colors.primary.main};
849
+ color: ${colors.primary.contrastText};
739
850
  }
740
851
 
741
852
  .gait-modal-button:hover {
742
- background-color: ${h.primary.dark};
853
+ background-color: ${colors.primary.dark};
743
854
  }
744
855
 
745
856
  .gait-modal-button:active {
@@ -834,55 +945,73 @@
834
945
  background-color: #ef4444;
835
946
  color: #fff;
836
947
  }
837
- `,document.head.appendChild(r)}const j='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 311.96 313.95" width="20" height="20" aria-hidden="true"><path fill="currentColor" d="M168.07,139.33c6.81-15.69,22.45-26.66,40.65-26.66s33.83,10.97,40.66,26.66h62.58C303.19,60.94,236.71,0,155.98,0S8.77,60.95,0,139.33h168.07Z"/><path fill="currentColor" d="M249.37,174.62c-6.81,15.68-22.46,26.65-40.65,26.65s-33.82-10.97-40.64-26.65H0c8.77,78.39,75.25,139.33,155.98,139.33s147.21-60.94,155.98-139.33h-62.59Z"/></svg>';function H(r,t){return`
948
+ `;
949
+ document.head.appendChild(style);
950
+ }
951
+ const GAIT_LOGO_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 311.96 313.95" width="20" height="20" aria-hidden="true"><path fill="currentColor" d="M168.07,139.33c6.81-15.69,22.45-26.66,40.65-26.66s33.83,10.97,40.66,26.66h62.58C303.19,60.94,236.71,0,155.98,0S8.77,60.95,0,139.33h168.07Z"/><path fill="currentColor" d="M249.37,174.62c-6.81,15.68-22.46,26.65-40.65,26.65s-33.82-10.97-40.64-26.65H0c8.77,78.39,75.25,139.33,155.98,139.33s147.21-60.94,155.98-139.33h-62.59Z"/></svg>`;
952
+ function generateButtonTemplate(disabled, customStyle) {
953
+ return `
838
954
  <button
839
955
  type="button"
840
- ${r?"disabled":""}
841
- style="${t}"
956
+ ${disabled ? "disabled" : ""}
957
+ style="${customStyle}"
842
958
  >
843
- <span class="gait-button-icon">${j}</span>
959
+ <span class="gait-button-icon">${GAIT_LOGO_ICON}</span>
844
960
  <span class="gait-button-label">Gait</span>
845
961
  </button>
846
- `}function A(r){return`R ${r.toFixed(2)}`}const _=`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
847
- <path d="M18 6L6 18M6 6l12 12" />
848
- </svg>
849
- `,$=`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
850
- <path d="M20 6L9 17l-5-5" />
851
- </svg>
852
- `,U=`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
853
- <path d="M18 6L6 18M6 6l12 12" />
854
- </svg>
855
- `,W=`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
856
- <path d="M21 12a9 9 0 11-6.22-8.56" />
857
- </svg>
858
- `;function J(r){return!r||r.length===0?"":r.map(t=>`
962
+ `;
963
+ }
964
+ function formatCurrency(amount) {
965
+ return `R ${amount.toFixed(2)}`;
966
+ }
967
+ const closeIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">\n <path d="M18 6L6 18M6 6l12 12" />\n</svg>\n';
968
+ const checkIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">\n <path d="M20 6L9 17l-5-5" />\n</svg>\n';
969
+ const crossIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">\n <path d="M18 6L6 18M6 6l12 12" />\n</svg>\n';
970
+ const spinnerIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">\n <path d="M21 12a9 9 0 11-6.22-8.56" />\n</svg>\n';
971
+ function renderItems(items) {
972
+ if (!items || items.length === 0) {
973
+ return "";
974
+ }
975
+ return items.map((item) => `
859
976
  <div class="gait-modal-item">
860
977
  <img
861
- src="${t.image||""}"
862
- alt="${t.name||"Product"}"
978
+ src="${item.image || ""}"
979
+ alt="${item.name || "Product"}"
863
980
  class="gait-modal-item-image"
864
981
  />
865
982
  <div class="gait-modal-item-meta">
866
983
  <h3 class="gait-modal-item-title">
867
- ${t.name||""}
984
+ ${item.name || ""}
868
985
  </h3>
869
986
  <div class="gait-modal-item-quantity">
870
- Qty: ${t.quantity||0}
871
- <span class="gait-modal-item-price">${A(t.price||0)}</span>
987
+ Qty: ${item.quantity || 0}
988
+ <span class="gait-modal-item-price">${formatCurrency(item.price || 0)}</span>
872
989
  </div>
873
990
  </div>
874
991
  </div>
875
- `).join("")}function Y(r){return!r||r.length===0?"":r.map(t=>{const e=typeof t.price=="number"?t.price:parseFloat(String(t.price))||0;return`
992
+ `).join("");
993
+ }
994
+ function renderPriceBreakdown(breakdown) {
995
+ if (!breakdown || breakdown.length === 0) {
996
+ return "";
997
+ }
998
+ return breakdown.map((item) => {
999
+ const price = typeof item.price === "number" ? item.price : parseFloat(String(item.price)) || 0;
1000
+ return `
876
1001
  <div class="gait-modal-price-item">
877
- <span>${t.name||""}</span>
878
- <span>${A(e)}</span>
1002
+ <span>${item.name || ""}</span>
1003
+ <span>${formatCurrency(price)}</span>
879
1004
  </div>
880
- `}).join("")}function K(r,t,e){return`
1005
+ `;
1006
+ }).join("");
1007
+ }
1008
+ function generateModalTemplate(items, priceBreakdown, totalCost) {
1009
+ return `
881
1010
  <div class="gait-modal-container">
882
1011
  <div class="gait-modal-header">
883
1012
  <h2 class="gait-modal-header-title">Split Payment</h2>
884
1013
  <button class="gait-modal-close-icon" data-gait-modal-close aria-label="Close">
885
- ${_}
1014
+ ${closeIcon}
886
1015
  </button>
887
1016
  </div>
888
1017
 
@@ -890,20 +1019,20 @@
890
1019
  <!-- LEFT -->
891
1020
  <div class="gait-modal-left-panel">
892
1021
  <div class="gait-modal-items-container">
893
- ${J(r)}
1022
+ ${renderItems(items)}
894
1023
  </div>
895
1024
 
896
1025
  <div class="gait-modal-price-section">
897
1026
  <h4 class="gait-modal-price-title">Price details</h4>
898
1027
 
899
- ${Y(t)}
1028
+ ${renderPriceBreakdown(priceBreakdown)}
900
1029
 
901
- ${e>0?`
1030
+ ${totalCost > 0 ? `
902
1031
  <div class="gait-modal-price-total">
903
1032
  <span>Total</span>
904
- <span>${A(e)}</span>
1033
+ <span>${formatCurrency(totalCost)}</span>
905
1034
  </div>
906
- `:""}
1035
+ ` : ""}
907
1036
  </div>
908
1037
  </div>
909
1038
 
@@ -937,22 +1066,1560 @@
937
1066
  </div>
938
1067
  </div>
939
1068
  </div>
940
- `}function Z(r){const t={};return Array.from(r.attributes).forEach(e=>{e.name.startsWith("data-")&&(t[e.name]=e.value)}),t}function Q(r){const t={};return Array.from(r.attributes).forEach(e=>{t[e.name]=e.value}),t}function X(r){return{get dataId(){return r.getAttribute("data-id")||null},get disabled(){return r.hasAttribute("disabled")&&r.getAttribute("disabled")!=="false"},get size(){return r.getAttribute("size")||"medium"},get items(){const t=r.getAttribute("items");if(!t)return[];try{return JSON.parse(t)}catch(e){return console.warn("[GaitButton] Failed to parse items attribute:",e),[]}},get totalCost(){const t=r.getAttribute("total-cost");if(!t)return 0;const e=parseFloat(t);return(isNaN(e)?0:e)+B.fee},get priceBreakdown(){const t=r.getAttribute("total-cost"),e=parseFloat(t||"0");return[{name:"Subtotal",price:isNaN(e)?0:e},{name:"Split Payment Fee",price:B.fee}]},get customer(){const t=r.getAttribute("customer");if(!t)return null;try{return JSON.parse(t)}catch(e){return console.warn("[GaitButton] Failed to parse customer attribute:",e),null}},get webhook(){const t=r.getAttribute("webhook");if(!t)return null;try{return JSON.parse(t)}catch(e){return console.warn("[GaitButton] Failed to parse webhook attribute:",e),null}},get merchantStoreUrl(){const t=r.getAttribute("merchant-store-url");return t&&t.trim()!==""?t.trim():typeof window<"u"&&window.location?window.location.origin:""}}}function v(r){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r)}function L(r,t,e){if(e.length===0)return r;if(t==="equally"){const i=e.length+1,a=r/i;return Math.max(0,r-a*e.length)}else if(t==="by-amount"){let i=0;return e.forEach(a=>{const n=a.amount||0;i+=n}),Math.max(0,r-i)}return r}function w(r,t){return r/t}function R(r,t,e){const i=[],a=r.querySelectorAll("[data-email-item]");return a.forEach(n=>{const o=n.getAttribute("data-email-item")||"";if(o)if(t==="by-amount"){const d=n.querySelector(".gait-modal-email-item-amount"),l=d&&parseFloat(d.textContent?.replace(/[^\d.]/g,"")||"0")||0;i.push({email:o,amount:l})}else{const d=a.length+1,l=w(e,d);i.push({email:o,amount:l})}}),i}function z(r){const t=r.querySelectorAll("[data-email-item]"),e=r.querySelectorAll("[data-email-input]");return t.length+e.length}class tt{modalElement;totalCost;currentSplitMethod="equally";dispatchEventFn;isSplitSent=!1;isSplitLoading=!1;splitFeedbackElement=null;feedbackHandler=null;constructor(t,e,i){this.modalElement=t,this.totalCost=e,this.dispatchEventFn=i,this.setup(),this.setupFeedbackListener()}setup(){const t=this.modalElement.querySelectorAll("[data-split-method]"),e=this.modalElement.querySelector("[data-email-inputs]"),i=this.modalElement.querySelector("[data-add-email]"),a=this.modalElement.querySelector("[data-send-split]");!e||!i||!a||(t.forEach(n=>{n.addEventListener("click",()=>{if(this.isSplitSent)return;t.forEach(l=>l.classList.remove("selected")),n.classList.add("selected");const o=n.getAttribute("data-split-method")||"equally",d=this.currentSplitMethod;this.currentSplitMethod=o,d!==o&&this.updateActiveInputsForSplitMethod(d,o),this.updateEmailItemsForSplitMethod(),this.updateSplitCalculation()})}),i.addEventListener("click",()=>this.addEmailField()),e.addEventListener("input",n=>{n.target.hasAttribute("data-email-input")&&this.updateSplitCalculation()}),a.addEventListener("click",()=>this.handleSendSplit()),this.updateSplitCalculation())}addEmailField(){if(this.isSplitSent)return;const t=this.modalElement.querySelector("[data-email-inputs]");if(!t)return;const e=this.findEmptyInput(t);if(e){if(e instanceof HTMLInputElement)e.focus();else{const i=e.querySelector("[data-email-input]");i&&i.focus()}return}this.currentSplitMethod==="by-amount"?this.addByAmountInput(t):this.addEquallyInput(t)}findEmptyInput(t){if(this.currentSplitMethod==="by-amount"){const e=t.querySelectorAll(".gait-modal-email-amount-row");for(const i of Array.from(e)){const a=i.querySelector("[data-email-input]");if(a&&!a.value.trim())return i}}else{const e=t.querySelectorAll("[data-email-input]");for(const i of Array.from(e))if(!i.parentElement?.classList.contains("gait-modal-email-amount-row")&&!i.value.trim())return i}return null}removeEmptyInputs(t){t.querySelectorAll(".gait-modal-email-amount-row").forEach(a=>{const n=a.querySelector("[data-email-input]");n&&!n.value.trim()&&t.removeChild(a)}),t.querySelectorAll("[data-email-input]").forEach(a=>{a.parentElement?.classList.contains("gait-modal-email-amount-row")||a.value.trim()||t.removeChild(a)})}calculateRemainingAmount(t){const e=this.modalElement.querySelector("[data-email-inputs]");if(!e)return this.totalCost;let i=0;return e.querySelectorAll("[data-email-item]").forEach(d=>{const l=d.querySelector(".gait-modal-email-item-amount");if(l){const s=l.textContent||"0.00",m=parseFloat(s.replace(/[^\d.]/g,""))||0;i+=m}}),e.querySelectorAll(".gait-modal-email-amount-row").forEach(d=>{if(d===t)return;const l=d.querySelector("[data-email-amount-input]");if(l&&l.value){const s=parseFloat(l.value)||0;i+=s}}),Math.max(0,this.totalCost-i)}updateAmountInputMaxValues(t){const e=this.modalElement.querySelector("[data-email-inputs]");if(!e)return;const i=this.calculateRemainingAmount(t),a=i.toFixed(2);e.querySelectorAll("[data-email-amount-input]").forEach(o=>{o.closest(".gait-modal-email-amount-row")!==t&&(o.max=a,(parseFloat(o.value)||0)>i&&(o.value=a,o.style.borderColor="#ef4444",setTimeout(()=>{o.style.borderColor=""},2e3)))})}addByAmountInput(t){const e=document.createElement("div");e.className="gait-modal-email-amount-row";const i=document.createElement("input");i.type="email",i.className="gait-modal-email-input",i.placeholder="Email address",i.setAttribute("data-email-input","");const a=document.createElement("input");a.type="number",a.className="gait-modal-email-amount-input",a.placeholder="0.00",a.step="0.01",a.min="0",a.setAttribute("data-email-amount-input","");const n=this.calculateRemainingAmount();a.max=n.toFixed(2);const o=document.createElement("button");o.type="button",o.className="gait-modal-done-button",o.textContent="Done",o.setAttribute("data-done-email","");const d=()=>{const l=i.value.trim();let s=parseFloat(a.value)||0;const m=this.calculateRemainingAmount(e);if(s>m&&(s=m,a.value=m.toFixed(2),a.style.borderColor="#ef4444",setTimeout(()=>{a.style.borderColor=""},2e3)),l&&v(l)){const u=this.createEmailItem(l,s);t.replaceChild(u,e),this.updateSplitCalculation(),this.updateAmountInputMaxValues()}else l||(t.removeChild(e),this.updateAmountInputMaxValues())};a.addEventListener("input",()=>{const l=this.calculateRemainingAmount(e);(parseFloat(a.value)||0)>l?(a.value=l.toFixed(2),a.style.borderColor="#ef4444",setTimeout(()=>{a.style.borderColor=""},2e3)):a.style.borderColor="",this.updateAmountInputMaxValues(e)}),o.addEventListener("click",d),i.addEventListener("blur",()=>{!i.value.trim()&&!a.value&&setTimeout(()=>{e.parentElement&&!i.value.trim()&&t.removeChild(e)},100)}),e.appendChild(i),e.appendChild(a),e.appendChild(o),t.appendChild(e),i.focus()}addEquallyInput(t){const e=document.createElement("input");e.type="email",e.className="gait-modal-email-input",e.placeholder="Email address",e.setAttribute("data-email-input","");const i=()=>{const a=e.value.trim();a&&v(a)&&(this.convertInputToEmailItem(e),this.updateSplitCalculation())};e.addEventListener("blur",()=>{const a=e.value.trim();a&&v(a)?i():a||setTimeout(()=>{e.parentElement&&!e.value.trim()&&t.removeChild(e)},100)}),e.addEventListener("keydown",a=>{a.key==="Enter"&&(a.preventDefault(),i())}),t.appendChild(e),e.focus()}createEmailItem(t,e=0,i=!1){const a=document.createElement("div");a.className=`gait-modal-email-item${i?" sent":""}`,a.setAttribute("data-email-item",t);let n=e;if(this.currentSplitMethod==="equally"){const s=this.modalElement.querySelector("[data-email-inputs]"),m=s?z(s)+1:2;n=w(this.totalCost,m)}const o=i?`<div class="gait-modal-email-item-sent-check">${$}</div>`:"";a.innerHTML=`
941
- <span class="gait-modal-email-item-email">${t}</span>
1069
+ `;
1070
+ }
1071
+ function getDataAttributes(element) {
1072
+ const dataAttrs = {};
1073
+ Array.from(element.attributes).forEach((attr) => {
1074
+ if (attr.name.startsWith("data-")) {
1075
+ dataAttrs[attr.name] = attr.value;
1076
+ }
1077
+ });
1078
+ return dataAttrs;
1079
+ }
1080
+ function getAllAttributes(element) {
1081
+ const attrs = {};
1082
+ Array.from(element.attributes).forEach((attr) => {
1083
+ attrs[attr.name] = attr.value;
1084
+ });
1085
+ return attrs;
1086
+ }
1087
+ function createAttributeGetters(element) {
1088
+ return {
1089
+ get dataId() {
1090
+ return element.getAttribute("data-id") || null;
1091
+ },
1092
+ get disabled() {
1093
+ return element.hasAttribute("disabled") && element.getAttribute("disabled") !== "false";
1094
+ },
1095
+ get size() {
1096
+ return element.getAttribute("size") || "medium";
1097
+ },
1098
+ get items() {
1099
+ const itemsAttr = element.getAttribute("items");
1100
+ if (!itemsAttr) {
1101
+ return [];
1102
+ }
1103
+ try {
1104
+ return JSON.parse(itemsAttr);
1105
+ } catch (e) {
1106
+ console.warn("[GaitButton] Failed to parse items attribute:", e);
1107
+ return [];
1108
+ }
1109
+ },
1110
+ get totalCost() {
1111
+ const totalCostAttr = element.getAttribute("total-cost");
1112
+ if (!totalCostAttr) {
1113
+ return 0;
1114
+ }
1115
+ const parsed = parseFloat(totalCostAttr);
1116
+ const baseTotal = isNaN(parsed) ? 0 : parsed;
1117
+ return baseTotal + splitPaymentConfig.fee;
1118
+ },
1119
+ get priceBreakdown() {
1120
+ const totalCostAttr = element.getAttribute("total-cost");
1121
+ const parsed = parseFloat(totalCostAttr || "0");
1122
+ const baseTotal = isNaN(parsed) ? 0 : parsed;
1123
+ const allPriceBreakdown = [
1124
+ {
1125
+ name: "Subtotal",
1126
+ price: baseTotal
1127
+ },
1128
+ {
1129
+ name: "Split Payment Fee",
1130
+ price: splitPaymentConfig.fee
1131
+ }
1132
+ ];
1133
+ return allPriceBreakdown;
1134
+ },
1135
+ get customer() {
1136
+ const customerAttr = element.getAttribute("customer");
1137
+ if (!customerAttr) {
1138
+ return null;
1139
+ }
1140
+ try {
1141
+ return JSON.parse(customerAttr);
1142
+ } catch (e) {
1143
+ console.warn("[GaitButton] Failed to parse customer attribute:", e);
1144
+ return null;
1145
+ }
1146
+ },
1147
+ get webhook() {
1148
+ const webhookAttr = element.getAttribute("webhook");
1149
+ if (!webhookAttr) {
1150
+ return null;
1151
+ }
1152
+ try {
1153
+ return JSON.parse(webhookAttr);
1154
+ } catch (e) {
1155
+ console.warn("[GaitButton] Failed to parse webhook attribute:", e);
1156
+ return null;
1157
+ }
1158
+ },
1159
+ get merchantStoreUrl() {
1160
+ const url = element.getAttribute("merchant-store-url");
1161
+ if (url && url.trim() !== "") {
1162
+ return url.trim();
1163
+ }
1164
+ if (typeof window !== "undefined" && window.location) {
1165
+ return window.location.origin;
1166
+ }
1167
+ return "";
1168
+ }
1169
+ };
1170
+ }
1171
+ function isValidEmail(email) {
1172
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1173
+ return emailRegex.test(email);
1174
+ }
1175
+ function calculateSplit(totalCost, splitMethod, emailData) {
1176
+ if (emailData.length === 0) {
1177
+ return totalCost;
1178
+ }
1179
+ if (splitMethod === "equally") {
1180
+ const participantCount = emailData.length + 1;
1181
+ const perPerson = totalCost / participantCount;
1182
+ return Math.max(0, totalCost - perPerson * emailData.length);
1183
+ } else if (splitMethod === "by-amount") {
1184
+ let totalSplit = 0;
1185
+ emailData.forEach((item) => {
1186
+ const amount = item.amount || 0;
1187
+ totalSplit += amount;
1188
+ });
1189
+ return Math.max(0, totalCost - totalSplit);
1190
+ }
1191
+ return totalCost;
1192
+ }
1193
+ function calculateEqualSplit(totalCost, participantCount) {
1194
+ return totalCost / participantCount;
1195
+ }
1196
+ function getEmailData(container, splitMethod, totalCost) {
1197
+ const data = [];
1198
+ const items = container.querySelectorAll("[data-email-item]");
1199
+ items.forEach((item) => {
1200
+ const email = item.getAttribute("data-email-item") || "";
1201
+ if (email) {
1202
+ if (splitMethod === "by-amount") {
1203
+ const amountSpan = item.querySelector(".gait-modal-email-item-amount");
1204
+ const amount = amountSpan ? parseFloat(amountSpan.textContent?.replace(/[^\d.]/g, "") || "0") || 0 : 0;
1205
+ data.push({ email, amount });
1206
+ } else {
1207
+ const participantCount = items.length + 1;
1208
+ const amount = calculateEqualSplit(totalCost, participantCount);
1209
+ data.push({ email, amount });
1210
+ }
1211
+ }
1212
+ });
1213
+ return data;
1214
+ }
1215
+ function getEmailDataCount(container) {
1216
+ const items = container.querySelectorAll("[data-email-item]");
1217
+ const inputs = container.querySelectorAll("[data-email-input]");
1218
+ return items.length + inputs.length;
1219
+ }
1220
+ class SplitPaymentManager {
1221
+ modalElement;
1222
+ totalCost;
1223
+ currentSplitMethod = "equally";
1224
+ dispatchEventFn;
1225
+ isSplitSent = false;
1226
+ isSplitLoading = false;
1227
+ splitFeedbackElement = null;
1228
+ feedbackHandler = null;
1229
+ constructor(modalElement, totalCost, dispatchEventFn) {
1230
+ this.modalElement = modalElement;
1231
+ this.totalCost = totalCost;
1232
+ this.dispatchEventFn = dispatchEventFn;
1233
+ this.setup();
1234
+ this.setupFeedbackListener();
1235
+ }
1236
+ setup() {
1237
+ const splitOptions = this.modalElement.querySelectorAll("[data-split-method]");
1238
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1239
+ const addEmailButton = this.modalElement.querySelector("[data-add-email]");
1240
+ const sendSplitButton = this.modalElement.querySelector("[data-send-split]");
1241
+ if (!emailInputsContainer || !addEmailButton || !sendSplitButton) {
1242
+ return;
1243
+ }
1244
+ splitOptions.forEach((option) => {
1245
+ option.addEventListener("click", () => {
1246
+ if (this.isSplitSent) {
1247
+ return;
1248
+ }
1249
+ splitOptions.forEach((opt) => opt.classList.remove("selected"));
1250
+ option.classList.add("selected");
1251
+ const newSplitMethod = option.getAttribute("data-split-method") || "equally";
1252
+ const oldSplitMethod = this.currentSplitMethod;
1253
+ this.currentSplitMethod = newSplitMethod;
1254
+ if (oldSplitMethod !== newSplitMethod) {
1255
+ this.updateActiveInputsForSplitMethod(oldSplitMethod, newSplitMethod);
1256
+ }
1257
+ this.updateEmailItemsForSplitMethod();
1258
+ this.updateSplitCalculation();
1259
+ });
1260
+ });
1261
+ addEmailButton.addEventListener("click", () => this.addEmailField());
1262
+ emailInputsContainer.addEventListener("input", (e) => {
1263
+ const target = e.target;
1264
+ if (target.hasAttribute("data-email-input")) {
1265
+ this.updateSplitCalculation();
1266
+ }
1267
+ });
1268
+ sendSplitButton.addEventListener("click", () => this.handleSendSplit());
1269
+ this.updateSplitCalculation();
1270
+ }
1271
+ addEmailField() {
1272
+ if (this.isSplitSent) {
1273
+ return;
1274
+ }
1275
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1276
+ if (!emailInputsContainer) return;
1277
+ const existingEmptyInput = this.findEmptyInput(emailInputsContainer);
1278
+ if (existingEmptyInput) {
1279
+ if (existingEmptyInput instanceof HTMLInputElement) {
1280
+ existingEmptyInput.focus();
1281
+ } else {
1282
+ const emailInput = existingEmptyInput.querySelector("[data-email-input]");
1283
+ if (emailInput) {
1284
+ emailInput.focus();
1285
+ }
1286
+ }
1287
+ return;
1288
+ }
1289
+ if (this.currentSplitMethod === "by-amount") {
1290
+ this.addByAmountInput(emailInputsContainer);
1291
+ } else {
1292
+ this.addEquallyInput(emailInputsContainer);
1293
+ }
1294
+ }
1295
+ findEmptyInput(container) {
1296
+ if (this.currentSplitMethod === "by-amount") {
1297
+ const rows = container.querySelectorAll(".gait-modal-email-amount-row");
1298
+ for (const row of Array.from(rows)) {
1299
+ const emailInput = row.querySelector("[data-email-input]");
1300
+ if (emailInput && !emailInput.value.trim()) {
1301
+ return row;
1302
+ }
1303
+ }
1304
+ } else {
1305
+ const inputs = container.querySelectorAll("[data-email-input]");
1306
+ for (const input of Array.from(inputs)) {
1307
+ if (!input.parentElement?.classList.contains("gait-modal-email-amount-row")) {
1308
+ if (!input.value.trim()) {
1309
+ return input;
1310
+ }
1311
+ }
1312
+ }
1313
+ }
1314
+ return null;
1315
+ }
1316
+ removeEmptyInputs(container) {
1317
+ const rows = container.querySelectorAll(".gait-modal-email-amount-row");
1318
+ rows.forEach((row) => {
1319
+ const emailInput = row.querySelector("[data-email-input]");
1320
+ if (emailInput && !emailInput.value.trim()) {
1321
+ container.removeChild(row);
1322
+ }
1323
+ });
1324
+ const inputs = container.querySelectorAll("[data-email-input]");
1325
+ inputs.forEach((input) => {
1326
+ if (!input.parentElement?.classList.contains("gait-modal-email-amount-row")) {
1327
+ if (!input.value.trim()) {
1328
+ container.removeChild(input);
1329
+ }
1330
+ }
1331
+ });
1332
+ }
1333
+ /**
1334
+ * Calculate the remaining amount available for a new split
1335
+ * This is totalCost minus all amounts already assigned to other people
1336
+ */
1337
+ calculateRemainingAmount(excludeRow) {
1338
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1339
+ if (!emailInputsContainer) return this.totalCost;
1340
+ let totalAssigned = 0;
1341
+ const items = emailInputsContainer.querySelectorAll("[data-email-item]");
1342
+ items.forEach((item) => {
1343
+ const amountSpan = item.querySelector(".gait-modal-email-item-amount");
1344
+ if (amountSpan) {
1345
+ const amountText = amountSpan.textContent || "0.00";
1346
+ const amount = parseFloat(amountText.replace(/[^\d.]/g, "")) || 0;
1347
+ totalAssigned += amount;
1348
+ }
1349
+ });
1350
+ const rows = emailInputsContainer.querySelectorAll(".gait-modal-email-amount-row");
1351
+ rows.forEach((row) => {
1352
+ if (row === excludeRow) return;
1353
+ const amountInput = row.querySelector("[data-email-amount-input]");
1354
+ if (amountInput && amountInput.value) {
1355
+ const amount = parseFloat(amountInput.value) || 0;
1356
+ totalAssigned += amount;
1357
+ }
1358
+ });
1359
+ const remaining = Math.max(0, this.totalCost - totalAssigned);
1360
+ return remaining;
1361
+ }
1362
+ /**
1363
+ * Update max attribute on all amount inputs
1364
+ */
1365
+ updateAmountInputMaxValues(excludeRow) {
1366
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1367
+ if (!emailInputsContainer) return;
1368
+ const remaining = this.calculateRemainingAmount(excludeRow);
1369
+ const maxValue = remaining.toFixed(2);
1370
+ const amountInputs = emailInputsContainer.querySelectorAll("[data-email-amount-input]");
1371
+ amountInputs.forEach((input) => {
1372
+ const row = input.closest(".gait-modal-email-amount-row");
1373
+ if (row !== excludeRow) {
1374
+ input.max = maxValue;
1375
+ const currentValue = parseFloat(input.value) || 0;
1376
+ if (currentValue > remaining) {
1377
+ input.value = maxValue;
1378
+ input.style.borderColor = "#ef4444";
1379
+ setTimeout(() => {
1380
+ input.style.borderColor = "";
1381
+ }, 2e3);
1382
+ }
1383
+ }
1384
+ });
1385
+ }
1386
+ addByAmountInput(container) {
1387
+ const row = document.createElement("div");
1388
+ row.className = "gait-modal-email-amount-row";
1389
+ const emailInput = document.createElement("input");
1390
+ emailInput.type = "email";
1391
+ emailInput.className = "gait-modal-email-input";
1392
+ emailInput.placeholder = "Email address";
1393
+ emailInput.setAttribute("data-email-input", "");
1394
+ const amountInput = document.createElement("input");
1395
+ amountInput.type = "number";
1396
+ amountInput.className = "gait-modal-email-amount-input";
1397
+ amountInput.placeholder = "0.00";
1398
+ amountInput.step = "0.01";
1399
+ amountInput.min = "0";
1400
+ amountInput.setAttribute("data-email-amount-input", "");
1401
+ const remaining = this.calculateRemainingAmount();
1402
+ amountInput.max = remaining.toFixed(2);
1403
+ const doneButton = document.createElement("button");
1404
+ doneButton.type = "button";
1405
+ doneButton.className = "gait-modal-done-button";
1406
+ doneButton.textContent = "Done";
1407
+ doneButton.setAttribute("data-done-email", "");
1408
+ const handleDone = () => {
1409
+ const email = emailInput.value.trim();
1410
+ let amount = parseFloat(amountInput.value) || 0;
1411
+ const remaining2 = this.calculateRemainingAmount(row);
1412
+ if (amount > remaining2) {
1413
+ amount = remaining2;
1414
+ amountInput.value = remaining2.toFixed(2);
1415
+ amountInput.style.borderColor = "#ef4444";
1416
+ setTimeout(() => {
1417
+ amountInput.style.borderColor = "";
1418
+ }, 2e3);
1419
+ }
1420
+ if (email && isValidEmail(email)) {
1421
+ const item = this.createEmailItem(email, amount);
1422
+ container.replaceChild(item, row);
1423
+ this.updateSplitCalculation();
1424
+ this.updateAmountInputMaxValues();
1425
+ } else if (!email) {
1426
+ container.removeChild(row);
1427
+ this.updateAmountInputMaxValues();
1428
+ }
1429
+ };
1430
+ amountInput.addEventListener("input", () => {
1431
+ const remaining2 = this.calculateRemainingAmount(row);
1432
+ const currentValue = parseFloat(amountInput.value) || 0;
1433
+ if (currentValue > remaining2) {
1434
+ amountInput.value = remaining2.toFixed(2);
1435
+ amountInput.style.borderColor = "#ef4444";
1436
+ setTimeout(() => {
1437
+ amountInput.style.borderColor = "";
1438
+ }, 2e3);
1439
+ } else {
1440
+ amountInput.style.borderColor = "";
1441
+ }
1442
+ this.updateAmountInputMaxValues(row);
1443
+ });
1444
+ doneButton.addEventListener("click", handleDone);
1445
+ emailInput.addEventListener("blur", () => {
1446
+ if (!emailInput.value.trim() && !amountInput.value) {
1447
+ setTimeout(() => {
1448
+ if (row.parentElement && !emailInput.value.trim()) {
1449
+ container.removeChild(row);
1450
+ }
1451
+ }, 100);
1452
+ }
1453
+ });
1454
+ row.appendChild(emailInput);
1455
+ row.appendChild(amountInput);
1456
+ row.appendChild(doneButton);
1457
+ container.appendChild(row);
1458
+ emailInput.focus();
1459
+ }
1460
+ addEquallyInput(container) {
1461
+ const input = document.createElement("input");
1462
+ input.type = "email";
1463
+ input.className = "gait-modal-email-input";
1464
+ input.placeholder = "Email address";
1465
+ input.setAttribute("data-email-input", "");
1466
+ const handleEmailDone = () => {
1467
+ const email = input.value.trim();
1468
+ if (email && isValidEmail(email)) {
1469
+ this.convertInputToEmailItem(input);
1470
+ this.updateSplitCalculation();
1471
+ }
1472
+ };
1473
+ input.addEventListener("blur", () => {
1474
+ const email = input.value.trim();
1475
+ if (email && isValidEmail(email)) {
1476
+ handleEmailDone();
1477
+ } else if (!email) {
1478
+ setTimeout(() => {
1479
+ if (input.parentElement && !input.value.trim()) {
1480
+ container.removeChild(input);
1481
+ }
1482
+ }, 100);
1483
+ }
1484
+ });
1485
+ input.addEventListener("keydown", (e) => {
1486
+ if (e.key === "Enter") {
1487
+ e.preventDefault();
1488
+ handleEmailDone();
1489
+ }
1490
+ });
1491
+ container.appendChild(input);
1492
+ input.focus();
1493
+ }
1494
+ createEmailItem(email, amount = 0, isSent = false) {
1495
+ const item = document.createElement("div");
1496
+ item.className = `gait-modal-email-item${isSent ? " sent" : ""}`;
1497
+ item.setAttribute("data-email-item", email);
1498
+ let displayAmount = amount;
1499
+ if (this.currentSplitMethod === "equally") {
1500
+ const container = this.modalElement.querySelector("[data-email-inputs]");
1501
+ const participantCount = container ? getEmailDataCount(container) + 1 : 2;
1502
+ displayAmount = calculateEqualSplit(this.totalCost, participantCount);
1503
+ }
1504
+ const checkmark = isSent ? `<div class="gait-modal-email-item-sent-check">${checkIcon}</div>` : "";
1505
+ item.innerHTML = `
1506
+ <span class="gait-modal-email-item-email">${email}</span>
942
1507
  <div class="gait-modal-email-item-right">
943
1508
  <div class="gait-modal-email-item-amount-container">
944
- <span class="gait-modal-email-item-amount">R ${n.toFixed(2)}</span>
945
- ${o}
1509
+ <span class="gait-modal-email-item-amount">R ${displayAmount.toFixed(2)}</span>
1510
+ ${checkmark}
946
1511
  </div>
947
1512
  <div class="gait-modal-email-item-actions">
948
- <button class="gait-modal-email-item-edit" data-edit-email="${t}">Edit</button>
949
- <button class="gait-modal-email-item-remove" data-remove-email="${t}">Remove</button>
1513
+ <button class="gait-modal-email-item-edit" data-edit-email="${email}">Edit</button>
1514
+ <button class="gait-modal-email-item-remove" data-remove-email="${email}">Remove</button>
950
1515
  </div>
951
1516
  </div>
952
- `;const d=a.querySelector(`[data-edit-email="${t}"]`);d&&d.addEventListener("click",s=>{s.preventDefault(),s.stopPropagation(),this.convertEmailItemToInput(a)});const l=a.querySelector(`[data-remove-email="${t}"]`);return l&&l.addEventListener("click",s=>{s.preventDefault(),s.stopPropagation(),this.removeEmailItem(a)}),a}convertEmailItemToInput(t){if(!t.parentElement)return;const i=t.getAttribute("data-email-item")||"";if(this.currentSplitMethod==="by-amount"){const a=document.createElement("div");a.className="gait-modal-email-amount-row";const n=document.createElement("input");n.type="email",n.className="gait-modal-email-input",n.placeholder="Email address",n.setAttribute("data-email-input",""),n.value=i;const o=document.createElement("input");o.type="number",o.className="gait-modal-email-amount-input",o.placeholder="0.00",o.step="0.01",o.min="0",o.setAttribute("data-email-amount-input","");const d=t.querySelector(".gait-modal-email-item-amount");let l=0;if(d){const u=d.textContent||"0.00";l=parseFloat(u.replace(/[^\d.]/g,""))||0,o.value=l.toFixed(2)}const s=this.calculateRemainingAmount(a)+l;o.max=s.toFixed(2);const m=document.createElement("button");m.type="button",m.className="gait-modal-done-button",m.textContent="Done",m.setAttribute("data-done-email",""),m.addEventListener("click",()=>{const u=n.value.trim();let c=parseFloat(o.value)||0;const p=this.calculateRemainingAmount(a)+l;if(c>p&&(c=p,o.value=p.toFixed(2),o.style.borderColor="#ef4444",setTimeout(()=>{o.style.borderColor=""},2e3)),u&&v(u)){const b=this.createEmailItem(u,c);a.parentElement&&a.parentElement.replaceChild(b,a),this.updateSplitCalculation(),this.updateAmountInputMaxValues()}else u||(a.parentElement&&a.parentElement.removeChild(a),this.updateAmountInputMaxValues())}),o.addEventListener("input",()=>{const u=this.calculateRemainingAmount(a)+l;(parseFloat(o.value)||0)>u?(o.value=u.toFixed(2),o.style.borderColor="#ef4444",setTimeout(()=>{o.style.borderColor=""},2e3)):o.style.borderColor="",this.updateAmountInputMaxValues(a)}),a.appendChild(n),a.appendChild(o),a.appendChild(m),t.parentElement&&t.parentElement.replaceChild(a,t),n.focus(),n.select()}else{const a=document.createElement("input");a.type="email",a.className="gait-modal-email-input",a.placeholder="Email address",a.setAttribute("data-email-input",""),a.value=i;const n=()=>{const o=a.value.trim();o&&v(o)?(this.convertInputToEmailItem(a),this.updateSplitCalculation()):o||setTimeout(()=>{a.parentElement&&!a.value.trim()&&a.parentElement.removeChild(a)},100)};a.addEventListener("blur",n),a.addEventListener("keydown",o=>{o.key==="Enter"&&(o.preventDefault(),n())}),t.parentElement&&t.parentElement.replaceChild(a,t),a.focus(),a.select()}}convertInputToEmailItem(t){const e=t.value.trim();if(!e||!v(e))return;const i=t.parentElement;if(!i)return;const a=z(i)+1,n=this.currentSplitMethod==="equally"?w(this.totalCost,a):0,o=this.createEmailItem(e,n);i.replaceChild(o,t)}removeEmailItem(t){const e=t.parentElement;e&&(e.removeChild(t),this.updateSplitCalculation(),this.updateAmountInputMaxValues())}updateActiveInputsForSplitMethod(t,e){const i=this.modalElement.querySelector("[data-email-inputs]");i&&(this.removeEmptyInputs(i),t==="equally"&&e==="by-amount"&&Array.from(i.querySelectorAll("[data-email-input]")).filter(n=>!n.parentElement?.classList.contains("gait-modal-email-amount-row")).forEach(n=>{const o=n.value.trim(),d=n.parentElement;if(!d)return;const l=document.createElement("div");l.className="gait-modal-email-amount-row";const s=document.createElement("input");s.type="email",s.className="gait-modal-email-input",s.placeholder="Email address",s.setAttribute("data-email-input",""),s.value=o;const m=document.createElement("input");m.type="number",m.className="gait-modal-email-amount-input",m.placeholder="0.00",m.step="0.01",m.min="0",m.setAttribute("data-email-amount-input","");const u=this.calculateRemainingAmount(l);m.max=u.toFixed(2);const c=document.createElement("button");c.type="button",c.className="gait-modal-done-button",c.textContent="Done",c.setAttribute("data-done-email",""),c.addEventListener("click",()=>{const p=s.value.trim();let b=parseFloat(m.value)||0;const T=this.calculateRemainingAmount(l);if(b>T&&(b=T,m.value=T.toFixed(2),m.style.borderColor="#ef4444",setTimeout(()=>{m.style.borderColor=""},2e3)),p&&v(p)){const st=this.createEmailItem(p,b);d.replaceChild(st,l),this.updateSplitCalculation(),this.updateAmountInputMaxValues()}}),m.addEventListener("input",()=>{const p=this.calculateRemainingAmount(l);(parseFloat(m.value)||0)>p?(m.value=p.toFixed(2),m.style.borderColor="#ef4444",setTimeout(()=>{m.style.borderColor=""},2e3)):m.style.borderColor="",this.updateAmountInputMaxValues(l)}),l.appendChild(s),l.appendChild(m),l.appendChild(c),d.replaceChild(l,n),s.focus()}),t==="by-amount"&&e==="equally"&&i.querySelectorAll(".gait-modal-email-amount-row").forEach(n=>{const o=n.querySelector("[data-email-input]");if(!o)return;const d=o.value.trim(),l=n.parentElement;if(!l)return;const s=document.createElement("input");s.type="email",s.className="gait-modal-email-input",s.placeholder="Email address",s.setAttribute("data-email-input",""),s.value=d;const m=()=>{const u=s.value.trim();u&&v(u)&&(this.convertInputToEmailItem(s),this.updateSplitCalculation())};s.addEventListener("blur",m),s.addEventListener("keydown",u=>{u.key==="Enter"&&(u.preventDefault(),m())}),l.replaceChild(s,n),s.focus()}))}updateEmailItemsForSplitMethod(){const t=this.modalElement.querySelector("[data-email-inputs]");if(!t)return;const e=t.querySelectorAll("[data-email-item]"),i=e.length+1;e.forEach(a=>{const n=a.querySelector(".gait-modal-email-item-right");if(!n)return;const o=n.querySelector(".gait-modal-email-item-amount");if(o){if(this.currentSplitMethod==="equally"){const d=w(this.totalCost,i);o.textContent=`R ${d.toFixed(2)}`}else if(this.currentSplitMethod==="by-amount"){const d=o.textContent||"R 0.00",l=parseFloat(d.replace(/[^\d.]/g,""))||0;o.textContent=`R ${l.toFixed(2)}`}}})}updateSplitCalculation(){const t=this.modalElement.querySelector("[data-email-inputs]"),e=this.modalElement.querySelector("[data-confirm-amount]");if(!t||!e)return;const i=R(t,this.currentSplitMethod,this.totalCost),a=t.querySelectorAll("[data-email-input]");a.forEach(o=>{const d=o.value.trim();if(d&&v(d)){const l=i.length+a.length+1,s=this.currentSplitMethod==="equally"?w(this.totalCost,l):0;i.push({email:d,amount:s})}});const n=i.length>0?L(this.totalCost,this.currentSplitMethod,i):this.totalCost;e.textContent=`R ${n.toFixed(2)}`,this.currentSplitMethod==="by-amount"&&this.updateAmountInputMaxValues()}handleSendSplit(){const t=this.modalElement.querySelector("[data-email-inputs]"),e=this.modalElement.querySelector("[data-send-split]");if(!t||!e)return;const i=R(t,this.currentSplitMethod,this.totalCost);if(i.length===0){this.showFeedback("Please add at least one email address","error");return}if(this.isSplitSent||this.isSplitLoading)return;this.isSplitLoading=!0,e.disabled=!0,e.textContent="Sending...",this.showFeedback("Sending split payment...","loading");const a=L(this.totalCost,this.currentSplitMethod,i);this.dispatchEventFn(new CustomEvent("gait-split-sent",{detail:{splitMethod:this.currentSplitMethod,emails:i.map(n=>n.email),emailData:i,totalCost:this.totalCost,yourAmount:a,timestamp:new Date().toISOString()},bubbles:!0,composed:!0}))}setupFeedbackListener(){this.feedbackHandler=t=>{const e=t;e.detail&&this.handleSplitFeedback(e.detail)},document.addEventListener("gait-split-feedback",this.feedbackHandler)}cleanup(){this.feedbackHandler&&(document.removeEventListener("gait-split-feedback",this.feedbackHandler),this.feedbackHandler=null)}handleSplitFeedback(t){this.isSplitLoading=!1;const e=this.modalElement.querySelector("[data-send-split]");t.success?(this.isSplitSent=!0,this.markEmailsAsSent(),this.disableSplitOptions(),e&&(e.disabled=!0,e.textContent="Split sent!"),this.showFeedback(t.message||"Split payment sent successfully","success")):(e&&(e.disabled=!1,e.textContent="Send split"),this.showFeedback(t.message||t.error||"Failed to send split payment","error"))}markEmailsAsSent(){const t=this.modalElement.querySelector("[data-email-inputs]");if(!t)return;t.querySelectorAll("[data-email-item]").forEach(i=>{if(!i.classList.contains("sent")){i.classList.add("sent");const a=i.querySelector(".gait-modal-email-item-right");if(a){let o=a.querySelector(".gait-modal-email-item-amount-container");const d=a.querySelector(".gait-modal-email-item-amount");if(!o&&d&&(o=document.createElement("div"),o.className="gait-modal-email-item-amount-container",d.parentElement?.replaceChild(o,d),o.appendChild(d)),o&&!o.querySelector(".gait-modal-email-item-sent-check")){const l=document.createElement("div");l.className="gait-modal-email-item-sent-check",l.innerHTML=$,o.appendChild(l)}}const n=i.querySelector(".gait-modal-email-item-actions");n&&(n.style.display="none")}})}showFeedback(t,e){this.splitFeedbackElement&&(this.splitFeedbackElement.remove(),this.splitFeedbackElement=null);const i=document.createElement("div");i.className=`gait-modal-feedback gait-modal-feedback-${e}`,i.setAttribute("data-split-feedback","");const a=e==="success"?$:e==="error"?U:W;i.innerHTML=`
953
- <span class="gait-modal-feedback-icon">${a}</span>
954
- <span class="gait-modal-feedback-message">${t}</span>
955
- `;const n=this.modalElement.querySelector(".gait-modal-split-section");n&&(n.insertBefore(i,n.firstChild),this.splitFeedbackElement=i,e!=="loading"&&setTimeout(()=>{this.splitFeedbackElement===i&&(i.style.opacity="0",setTimeout(()=>{i.parentElement&&i.remove(),this.splitFeedbackElement===i&&(this.splitFeedbackElement=null)},300))},5e3))}disableSplitOptions(){this.modalElement.querySelectorAll("[data-split-method]").forEach(i=>{const a=i;a.style.pointerEvents="none",a.style.opacity="0.5",a.style.cursor="not-allowed",a.setAttribute("aria-disabled","true")});const e=this.modalElement.querySelector("[data-add-email]");e&&(e.style.pointerEvents="none",e.style.opacity="0.5",e.style.cursor="not-allowed",e.setAttribute("aria-disabled","true"))}}async function et(r,t=2e3){console.log("[SplitPaymentAPI] Sending split payment request:",r);const e="https://api.usegait.com/checkout";try{const a=await(await fetch(`${e}/v1/payments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),signal:AbortSignal.timeout(t)})).json().catch(()=>({success:!1,error:"Failed to parse API response"}));if(a.success){const n={success:!0,message:a.message,data:a.data};return console.log("[SplitPaymentAPI] Split payment sent successfully:",n),n}else{const n={success:!1,message:a.message,error:a.error};return console.error("[SplitPaymentAPI] Split payment failed:",n),n}}catch(i){const a={success:!1,message:"Failed to send split payment",error:i instanceof Error?i.message:"Network error or server unavailable"};return console.error("[SplitPaymentAPI] Split payment failed:",a,i),a}}let at=r=>crypto.getRandomValues(new Uint8Array(r)),it=(r,t,e)=>{let i=(2<<Math.log2(r.length-1))-1,a=-~(1.6*i*t/r.length);return(n=t)=>{let o="";for(;;){let d=e(a),l=a|0;for(;l--;)if(o+=r[d[l]&i]||"",o.length>=n)return o}}},ot=(r,t=21)=>it(r,t|0,at);const M={apiGateway:{MERCHANT_SERVICE_API:"https://api.usegait.com/merchant",CHECKOUT_SERVICE_API:"https://api.usegait.com/checkout"},paylink:{DOMAIN:"https://checkout.usegait.com"}},nt=M.apiGateway.MERCHANT_SERVICE_API;class rt{static async getMerchant(t){try{return await(await fetch(`${nt}/v1/merchant/identity/${t}`,{method:"GET",headers:{"Content-Type":"application/json"}})).json()}catch(e){return e}}}const k=M.apiGateway.CHECKOUT_SERVICE_API;class lt{static async getPayment(t){try{return await(await fetch(`${k}/v1/payments/${t}`,{method:"GET",headers:{"Content-Type":"application/json"}})).json()}catch(e){return e}}static async updatePaymentStatus(t,e,i){try{return await(await fetch(`${k}/v1/payments/merchants/${t}/${e}/status`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:i})})).json()}catch(a){return a}}static async createWebhook(t,e,i){try{return await(await fetch(`${k}/v1/webhooks/${t}/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})).json()}catch(a){return a}}static async updatePayment(t,e,i){try{return await(await fetch(`${k}/v1/payments/merchants/${t}/${i}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentId:e})})).json()}catch(a){return a}}}const S=(typeof process<"u"&&process.env?"0.1.0":void 0)||"0.0.0";class x extends HTMLElement{buttonElement=null;hasRendered=!1;mutationObserver=null;modalElement=null;modalId;splitPaymentManager=null;attributeGetters;storedSplitPaymentRequest=null;merchantId=null;paymentProvider="stripe";static version=S;version=S;static get observedAttributes(){return["data-id","disabled","size","style","items","price-breakdown","total-cost","webhook","merchant-store-url"]}constructor(){super(),this.attachShadow({mode:"open"}),this.modalId=`gait-modal-${Math.random().toString(36).substr(2,9)}`,this.attributeGetters=X(this)}connectedCallback(){!this.hasRendered&&this.shadowRoot&&this.render(),this.setupEventListeners(),this.setupMutationObserver(),this.setupApiListeners(),setTimeout(()=>this.processData(),0)}disconnectedCallback(){this.buttonElement&&this.buttonElement.removeEventListener("click",this.handleClick),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.closeModal(),this.splitPaymentManager&&(this.splitPaymentManager=null),this.removeEventListener("gait-split-sent",this.handleSplitSent)}attributeChangedCallback(t,e,i){if(e!==i&&!(!this.isConnected||!this.shadowRoot)){if(t==="style"&&this.buttonElement&&this.hasRendered){const a=(i||"").replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");this.buttonElement.setAttribute("style",a);return}this.hasRendered&&(this.render(),this.setupEventListeners()),(t==="data-id"||t.startsWith("data-"))&&(t==="data-id"&&(this.merchantId=null),setTimeout(()=>this.processData(),0))}}get dataId(){return this.attributeGetters.dataId}get disabled(){return this.attributeGetters.disabled}get size(){return this.attributeGetters.size}get items(){return this.attributeGetters.items}get priceBreakdown(){return this.attributeGetters.priceBreakdown}get totalCost(){return this.attributeGetters.totalCost}get customer(){return this.attributeGetters.customer}get webhook(){return this.attributeGetters.webhook}get merchantStoreUrl(){return this.attributeGetters.merchantStoreUrl}getDataAttributes(){return Z(this)}async fetchMerchantId(){const t=this.dataId;if(!t)return console.warn("[GaitButton] No checkoutId (data-id) provided, cannot fetch merchantId"),this.showMerchantIdError(),!1;try{const e=await rt.getMerchant(t);return e.success&&e.data?.merchantId?(this.merchantId=e.data.merchantId,this.paymentProvider=e.data.paymentProvider,!0):(console.error("[GaitButton] Failed to fetch merchantId:",e),this.showMerchantIdError(),!1)}catch(e){return console.error("[GaitButton] Error fetching merchantId:",e),this.showMerchantIdError(),!1}}showMerchantIdError(){const t="Unable to identify your account. Please go to your dashboard and copy your checkout identity.";alert(t),this.dispatchEvent(new CustomEvent("gait-merchant-id-error",{detail:{message:t,timestamp:new Date().toISOString()},bubbles:!0,composed:!0}))}async processData(){const t=this.dataId,e=this.getDataAttributes();if(t&&!this.merchantId&&await this.fetchMerchantId(),t||Object.keys(e).length>0){const i={id:t,...e,timestamp:new Date().toISOString()};this.dispatchEvent(new CustomEvent("gait-data-processed",{detail:i,bubbles:!0,composed:!0}))}}handleClick=async t=>{if(this.disabled){t.preventDefault(),t.stopPropagation();return}const e={label:"Gait",dataId:this.dataId,dataAttributes:this.getDataAttributes(),timestamp:new Date().toISOString()};this.dispatchEvent(new CustomEvent("gait-click",{detail:e,bubbles:!0,composed:!0})),this.dispatchEvent(new CustomEvent("click",{detail:e,bubbles:!0,composed:!0})),!(!this.merchantId&&(!await this.fetchMerchantId()||!this.merchantId))&&this.openModal()};setupEventListeners(){this.shadowRoot&&(this.buttonElement&&this.buttonElement.removeEventListener("click",this.handleClick),this.buttonElement=this.shadowRoot.querySelector("button"),this.buttonElement&&this.buttonElement.addEventListener("click",this.handleClick))}setupMutationObserver(){this.mutationObserver&&this.mutationObserver.disconnect(),this.mutationObserver=new MutationObserver(t=>{let e=!1;for(const i of t)if(i.type==="attributes"){const a=i.attributeName;if(a&&a.startsWith("data-")&&!x.observedAttributes.includes(a)){e=!0;break}}e&&this.isConnected&&this.processData()}),this.mutationObserver.observe(this,{attributes:!0,attributeFilter:void 0})}setupApiListeners(){this.addEventListener("gait-split-sent",this.handleSplitSent)}handleConfirmPayment=async()=>{if(console.log("[GaitButton] Pay remaining button clicked"),!this.storedSplitPaymentRequest){console.error("[GaitButton] Split payment must be sent first before paying remaining amount");return}if(!this.merchantId&&(!await this.fetchMerchantId()||!this.merchantId))return;const t={merchantId:this.merchantId,splitId:this.storedSplitPaymentRequest.splitId,paymentId:this.storedSplitPaymentRequest.paymentSplits.find(a=>a.initiator)?.paymentId},i=`${M.paylink.DOMAIN}/payment/${t.paymentId}`;window.open(i,"_blank"),this.dispatchEvent(new CustomEvent("gait-confirm",{detail:t,bubbles:!0,composed:!0})),this.closeModal()};handleSplitSent=async t=>{const i=t.detail;if(!this.merchantId&&(!await this.fetchMerchantId()||!this.merchantId))return;const a=this.merchantId,n=this.customer;if(!n||!n.email){console.error("[GaitButton] Customer email is required for split payment");return}const o=this.webhook;if(!o||!o.url||o.body==null){console.error("[GaitButton] Webhook with url and body is required");return}const l=ot("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",6),s=l(),m=[];m.push({paymentId:l(),email:n.email,amount:i.yourAmount,isPaid:!1,datePaid:null,initiator:!0}),i.emailData.forEach(c=>{m.push({paymentId:l(),email:c.email,amount:c.amount||0,isPaid:!1,datePaid:null,initiator:!1})});const u={merchantId:a,splitId:s,paymentSplits:m,splitMethod:i.splitMethod,timestamp:i.timestamp,totalCost:i.totalCost,items:this.items,priceBreakdown:this.priceBreakdown,brandColor:g,merchantStoreUrl:this.merchantStoreUrl,subTotal:this.priceBreakdown.find(c=>c.name==="Subtotal")?.price||0,paymentProvider:this.paymentProvider};console.log("[GaitButton] Split payment request body:",JSON.stringify(u,null,2));try{const c=await et(u,2e3);if(c.success){const p=c.data?.splitId||s;this.storedSplitPaymentRequest={...u,splitId:p};try{const b=await lt.createWebhook(a,p,{url:o.url,body:o.body});console.log("[GaitButton] Webhook created:",b)}catch(b){console.error("[GaitButton] Failed to create webhook:",b)}}if(this.modalElement){const p=this.modalElement.querySelector("[data-gait-modal-confirm]");p&&(p.disabled=!1,p.style.opacity="1",p.style.cursor="pointer")}this.dispatchEvent(new CustomEvent("gait-split-feedback",{detail:{success:c.success,message:c.message,data:c.success?this.storedSplitPaymentRequest:c.data,error:c.error,timestamp:new Date().toISOString()},bubbles:!0,composed:!0})),console.log("[GaitButton] Split payment API response:",c)}catch(c){console.error("[GaitButton] Split payment API error:",c),this.dispatchEvent(new CustomEvent("gait-split-feedback",{detail:{success:!1,message:"Failed to send split payment",error:c instanceof Error?c.message:"Unknown error",timestamp:new Date().toISOString()},bubbles:!0,composed:!0}))}};openModal(){V(),this.closeModal(),this.modalElement=document.createElement("div"),this.modalElement.className="gait-modal-backdrop",this.modalElement.id=this.modalId,this.modalElement&&(this.modalElement.style.setProperty("--gait-modal-brand-color",g),this.modalElement.style.setProperty("--gait-modal-button-bg",g),this.modalElement.style.setProperty("--gait-modal-button-bg-hover",F(g,.15)),this.modalElement.style.setProperty("--gait-modal-button-color",q(g)?"#ffffff":"#000000")),this.modalElement.innerHTML=K(this.items,this.priceBreakdown,this.totalCost);const t=this.modalElement.querySelector("[data-gait-modal-close]");t&&t.addEventListener("click",this.closeModal);const e=this.modalElement.querySelector("[data-gait-modal-confirm]");e&&(e.disabled=!0,e.style.opacity="0.5",e.style.cursor="not-allowed",e.addEventListener("click",this.handleConfirmPayment)),this.splitPaymentManager=new tt(this.modalElement,this.totalCost,a=>this.dispatchEvent(a)),this.modalElement._splitPaymentManager=this.splitPaymentManager,this.modalElement.addEventListener("click",a=>{a.target===this.modalElement&&this.closeModal()});const i=a=>{a.key==="Escape"&&this.modalElement&&(this.closeModal(),document.removeEventListener("keydown",i))};document.addEventListener("keydown",i),document.body.appendChild(this.modalElement),requestAnimationFrame(()=>{this.modalElement&&this.modalElement.classList.add("gait-modal-open")})}closeModal=()=>{this.modalElement&&(this.splitPaymentManager&&this.splitPaymentManager.cleanup(),this.modalElement.classList.remove("gait-modal-open"),setTimeout(()=>{this.modalElement&&this.modalElement.parentNode&&this.modalElement.parentNode.removeChild(this.modalElement),this.modalElement=null,this.splitPaymentManager=null},250))};render(){const t=this.shadowRoot;if(!t)return;const e=!this.hasRendered,i=D(this.size,F,q),n=(this.getAttribute("style")||"").replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");if(t.innerHTML=`
956
- ${i}
957
- ${H(this.disabled,n)}
958
- `,this.hasRendered=!0,this.setupEventListeners(),e){const o=Q(this);console.log("[GaitButton] rendered",o),this.dispatchEvent(new CustomEvent("gait-loaded",{detail:{attributes:o,dataId:this.dataId,dataAttributes:this.getDataAttributes(),label:"Gait",size:this.size,disabled:this.disabled,timestamp:new Date().toISOString()},bubbles:!0,composed:!0}))}}}customElements.get("gait-button")||customElements.define("gait-button",x),customElements.get("gait-button")||customElements.define("gait-button",x),typeof window<"u"&&(window.GaitButton=x,window.GaitButtonVersion=S,console.log(`[GaitButton] Version: ${S}`)),I.GAIT_BUTTON_VERSION=S,I.GaitButton=x,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"})})(this.GaitButton=this.GaitButton||{});
1517
+ `;
1518
+ const editButton = item.querySelector(`[data-edit-email="${email}"]`);
1519
+ if (editButton) {
1520
+ editButton.addEventListener("click", (e) => {
1521
+ e.preventDefault();
1522
+ e.stopPropagation();
1523
+ this.convertEmailItemToInput(item);
1524
+ });
1525
+ }
1526
+ const removeButton = item.querySelector(`[data-remove-email="${email}"]`);
1527
+ if (removeButton) {
1528
+ removeButton.addEventListener("click", (e) => {
1529
+ e.preventDefault();
1530
+ e.stopPropagation();
1531
+ this.removeEmailItem(item);
1532
+ });
1533
+ }
1534
+ return item;
1535
+ }
1536
+ convertEmailItemToInput(item) {
1537
+ const container = item.parentElement;
1538
+ if (!container) return;
1539
+ const email = item.getAttribute("data-email-item") || "";
1540
+ if (this.currentSplitMethod === "by-amount") {
1541
+ const row = document.createElement("div");
1542
+ row.className = "gait-modal-email-amount-row";
1543
+ const emailInput = document.createElement("input");
1544
+ emailInput.type = "email";
1545
+ emailInput.className = "gait-modal-email-input";
1546
+ emailInput.placeholder = "Email address";
1547
+ emailInput.setAttribute("data-email-input", "");
1548
+ emailInput.value = email;
1549
+ const amountInput = document.createElement("input");
1550
+ amountInput.type = "number";
1551
+ amountInput.className = "gait-modal-email-amount-input";
1552
+ amountInput.placeholder = "0.00";
1553
+ amountInput.step = "0.01";
1554
+ amountInput.min = "0";
1555
+ amountInput.setAttribute("data-email-amount-input", "");
1556
+ const amountSpan = item.querySelector(".gait-modal-email-item-amount");
1557
+ let initialAmount = 0;
1558
+ if (amountSpan) {
1559
+ const amountText = amountSpan.textContent || "0.00";
1560
+ initialAmount = parseFloat(amountText.replace(/[^\d.]/g, "")) || 0;
1561
+ amountInput.value = initialAmount.toFixed(2);
1562
+ }
1563
+ const remaining = this.calculateRemainingAmount(row) + initialAmount;
1564
+ amountInput.max = remaining.toFixed(2);
1565
+ const doneButton = document.createElement("button");
1566
+ doneButton.type = "button";
1567
+ doneButton.className = "gait-modal-done-button";
1568
+ doneButton.textContent = "Done";
1569
+ doneButton.setAttribute("data-done-email", "");
1570
+ doneButton.addEventListener("click", () => {
1571
+ const emailVal = emailInput.value.trim();
1572
+ let amountVal = parseFloat(amountInput.value) || 0;
1573
+ const remaining2 = this.calculateRemainingAmount(row) + initialAmount;
1574
+ if (amountVal > remaining2) {
1575
+ amountVal = remaining2;
1576
+ amountInput.value = remaining2.toFixed(2);
1577
+ amountInput.style.borderColor = "#ef4444";
1578
+ setTimeout(() => {
1579
+ amountInput.style.borderColor = "";
1580
+ }, 2e3);
1581
+ }
1582
+ if (emailVal && isValidEmail(emailVal)) {
1583
+ const newItem = this.createEmailItem(emailVal, amountVal);
1584
+ if (row.parentElement) {
1585
+ row.parentElement.replaceChild(newItem, row);
1586
+ }
1587
+ this.updateSplitCalculation();
1588
+ this.updateAmountInputMaxValues();
1589
+ } else if (!emailVal) {
1590
+ if (row.parentElement) {
1591
+ row.parentElement.removeChild(row);
1592
+ }
1593
+ this.updateAmountInputMaxValues();
1594
+ }
1595
+ });
1596
+ amountInput.addEventListener("input", () => {
1597
+ const remaining2 = this.calculateRemainingAmount(row) + initialAmount;
1598
+ const currentValue = parseFloat(amountInput.value) || 0;
1599
+ if (currentValue > remaining2) {
1600
+ amountInput.value = remaining2.toFixed(2);
1601
+ amountInput.style.borderColor = "#ef4444";
1602
+ setTimeout(() => {
1603
+ amountInput.style.borderColor = "";
1604
+ }, 2e3);
1605
+ } else {
1606
+ amountInput.style.borderColor = "";
1607
+ }
1608
+ this.updateAmountInputMaxValues(row);
1609
+ });
1610
+ row.appendChild(emailInput);
1611
+ row.appendChild(amountInput);
1612
+ row.appendChild(doneButton);
1613
+ if (item.parentElement) {
1614
+ item.parentElement.replaceChild(row, item);
1615
+ }
1616
+ emailInput.focus();
1617
+ emailInput.select();
1618
+ } else {
1619
+ const input = document.createElement("input");
1620
+ input.type = "email";
1621
+ input.className = "gait-modal-email-input";
1622
+ input.placeholder = "Email address";
1623
+ input.setAttribute("data-email-input", "");
1624
+ input.value = email;
1625
+ const handleEmailDone = () => {
1626
+ const emailVal = input.value.trim();
1627
+ if (emailVal && isValidEmail(emailVal)) {
1628
+ this.convertInputToEmailItem(input);
1629
+ this.updateSplitCalculation();
1630
+ } else if (!emailVal) {
1631
+ setTimeout(() => {
1632
+ if (input.parentElement && !input.value.trim()) {
1633
+ input.parentElement.removeChild(input);
1634
+ }
1635
+ }, 100);
1636
+ }
1637
+ };
1638
+ input.addEventListener("blur", handleEmailDone);
1639
+ input.addEventListener("keydown", (e) => {
1640
+ if (e.key === "Enter") {
1641
+ e.preventDefault();
1642
+ handleEmailDone();
1643
+ }
1644
+ });
1645
+ if (item.parentElement) {
1646
+ item.parentElement.replaceChild(input, item);
1647
+ }
1648
+ input.focus();
1649
+ input.select();
1650
+ }
1651
+ }
1652
+ convertInputToEmailItem(input) {
1653
+ const email = input.value.trim();
1654
+ if (!email || !isValidEmail(email)) {
1655
+ return;
1656
+ }
1657
+ const container = input.parentElement;
1658
+ if (!container) return;
1659
+ const participantCount = getEmailDataCount(container) + 1;
1660
+ const perPersonAmount = this.currentSplitMethod === "equally" ? calculateEqualSplit(this.totalCost, participantCount) : 0;
1661
+ const item = this.createEmailItem(email, perPersonAmount);
1662
+ container.replaceChild(item, input);
1663
+ }
1664
+ removeEmailItem(item) {
1665
+ const container = item.parentElement;
1666
+ if (container) {
1667
+ container.removeChild(item);
1668
+ this.updateSplitCalculation();
1669
+ this.updateAmountInputMaxValues();
1670
+ }
1671
+ }
1672
+ updateActiveInputsForSplitMethod(oldMethod, newMethod) {
1673
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1674
+ if (!emailInputsContainer) return;
1675
+ this.removeEmptyInputs(emailInputsContainer);
1676
+ if (oldMethod === "equally" && newMethod === "by-amount") {
1677
+ const emailInputs = Array.from(emailInputsContainer.querySelectorAll("[data-email-input]")).filter((input) => !input.parentElement?.classList.contains("gait-modal-email-amount-row"));
1678
+ emailInputs.forEach((input) => {
1679
+ const email = input.value.trim();
1680
+ const container = input.parentElement;
1681
+ if (!container) return;
1682
+ const row = document.createElement("div");
1683
+ row.className = "gait-modal-email-amount-row";
1684
+ const emailInput = document.createElement("input");
1685
+ emailInput.type = "email";
1686
+ emailInput.className = "gait-modal-email-input";
1687
+ emailInput.placeholder = "Email address";
1688
+ emailInput.setAttribute("data-email-input", "");
1689
+ emailInput.value = email;
1690
+ const amountInput = document.createElement("input");
1691
+ amountInput.type = "number";
1692
+ amountInput.className = "gait-modal-email-amount-input";
1693
+ amountInput.placeholder = "0.00";
1694
+ amountInput.step = "0.01";
1695
+ amountInput.min = "0";
1696
+ amountInput.setAttribute("data-email-amount-input", "");
1697
+ const remaining = this.calculateRemainingAmount(row);
1698
+ amountInput.max = remaining.toFixed(2);
1699
+ const doneButton = document.createElement("button");
1700
+ doneButton.type = "button";
1701
+ doneButton.className = "gait-modal-done-button";
1702
+ doneButton.textContent = "Done";
1703
+ doneButton.setAttribute("data-done-email", "");
1704
+ doneButton.addEventListener("click", () => {
1705
+ const emailVal = emailInput.value.trim();
1706
+ let amountVal = parseFloat(amountInput.value) || 0;
1707
+ const remaining2 = this.calculateRemainingAmount(row);
1708
+ if (amountVal > remaining2) {
1709
+ amountVal = remaining2;
1710
+ amountInput.value = remaining2.toFixed(2);
1711
+ amountInput.style.borderColor = "#ef4444";
1712
+ setTimeout(() => {
1713
+ amountInput.style.borderColor = "";
1714
+ }, 2e3);
1715
+ }
1716
+ if (emailVal && isValidEmail(emailVal)) {
1717
+ const item = this.createEmailItem(emailVal, amountVal);
1718
+ container.replaceChild(item, row);
1719
+ this.updateSplitCalculation();
1720
+ this.updateAmountInputMaxValues();
1721
+ }
1722
+ });
1723
+ amountInput.addEventListener("input", () => {
1724
+ const remaining2 = this.calculateRemainingAmount(row);
1725
+ const currentValue = parseFloat(amountInput.value) || 0;
1726
+ if (currentValue > remaining2) {
1727
+ amountInput.value = remaining2.toFixed(2);
1728
+ amountInput.style.borderColor = "#ef4444";
1729
+ setTimeout(() => {
1730
+ amountInput.style.borderColor = "";
1731
+ }, 2e3);
1732
+ } else {
1733
+ amountInput.style.borderColor = "";
1734
+ }
1735
+ this.updateAmountInputMaxValues(row);
1736
+ });
1737
+ row.appendChild(emailInput);
1738
+ row.appendChild(amountInput);
1739
+ row.appendChild(doneButton);
1740
+ container.replaceChild(row, input);
1741
+ emailInput.focus();
1742
+ });
1743
+ }
1744
+ if (oldMethod === "by-amount" && newMethod === "equally") {
1745
+ const rows = emailInputsContainer.querySelectorAll(".gait-modal-email-amount-row");
1746
+ rows.forEach((row) => {
1747
+ const emailInput = row.querySelector("[data-email-input]");
1748
+ if (!emailInput) return;
1749
+ const email = emailInput.value.trim();
1750
+ const container = row.parentElement;
1751
+ if (!container) return;
1752
+ const input = document.createElement("input");
1753
+ input.type = "email";
1754
+ input.className = "gait-modal-email-input";
1755
+ input.placeholder = "Email address";
1756
+ input.setAttribute("data-email-input", "");
1757
+ input.value = email;
1758
+ const handleEmailDone = () => {
1759
+ const emailVal = input.value.trim();
1760
+ if (emailVal && isValidEmail(emailVal)) {
1761
+ this.convertInputToEmailItem(input);
1762
+ this.updateSplitCalculation();
1763
+ }
1764
+ };
1765
+ input.addEventListener("blur", handleEmailDone);
1766
+ input.addEventListener("keydown", (e) => {
1767
+ if (e.key === "Enter") {
1768
+ e.preventDefault();
1769
+ handleEmailDone();
1770
+ }
1771
+ });
1772
+ container.replaceChild(input, row);
1773
+ input.focus();
1774
+ });
1775
+ }
1776
+ }
1777
+ updateEmailItemsForSplitMethod() {
1778
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1779
+ if (!emailInputsContainer) return;
1780
+ const items = emailInputsContainer.querySelectorAll("[data-email-item]");
1781
+ const participantCount = items.length + 1;
1782
+ items.forEach((item) => {
1783
+ const rightColumn = item.querySelector(".gait-modal-email-item-right");
1784
+ if (!rightColumn) return;
1785
+ const amountSpan = rightColumn.querySelector(".gait-modal-email-item-amount");
1786
+ if (!amountSpan) return;
1787
+ if (this.currentSplitMethod === "equally") {
1788
+ const perPerson = calculateEqualSplit(this.totalCost, participantCount);
1789
+ amountSpan.textContent = `R ${perPerson.toFixed(2)}`;
1790
+ } else if (this.currentSplitMethod === "by-amount") {
1791
+ const currentAmountText = amountSpan.textContent || "R 0.00";
1792
+ const currentAmount = parseFloat(currentAmountText.replace(/[^\d.]/g, "")) || 0;
1793
+ amountSpan.textContent = `R ${currentAmount.toFixed(2)}`;
1794
+ }
1795
+ });
1796
+ }
1797
+ updateSplitCalculation() {
1798
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1799
+ const confirmAmountDisplay = this.modalElement.querySelector("[data-confirm-amount]");
1800
+ if (!emailInputsContainer || !confirmAmountDisplay) {
1801
+ return;
1802
+ }
1803
+ const emailData = getEmailData(emailInputsContainer, this.currentSplitMethod, this.totalCost);
1804
+ const emailInputs = emailInputsContainer.querySelectorAll("[data-email-input]");
1805
+ emailInputs.forEach((input) => {
1806
+ const email = input.value.trim();
1807
+ if (email && isValidEmail(email)) {
1808
+ const participantCount = emailData.length + emailInputs.length + 1;
1809
+ const amount = this.currentSplitMethod === "equally" ? calculateEqualSplit(this.totalCost, participantCount) : 0;
1810
+ emailData.push({ email, amount });
1811
+ }
1812
+ });
1813
+ const yourAmount = emailData.length > 0 ? calculateSplit(this.totalCost, this.currentSplitMethod, emailData) : this.totalCost;
1814
+ confirmAmountDisplay.textContent = `R ${yourAmount.toFixed(2)}`;
1815
+ if (this.currentSplitMethod === "by-amount") {
1816
+ this.updateAmountInputMaxValues();
1817
+ }
1818
+ }
1819
+ handleSendSplit() {
1820
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1821
+ const sendSplitButton = this.modalElement.querySelector("[data-send-split]");
1822
+ if (!emailInputsContainer || !sendSplitButton) return;
1823
+ const emailData = getEmailData(emailInputsContainer, this.currentSplitMethod, this.totalCost);
1824
+ if (emailData.length === 0) {
1825
+ this.showFeedback("Please add at least one email address", "error");
1826
+ return;
1827
+ }
1828
+ if (this.isSplitSent || this.isSplitLoading) {
1829
+ return;
1830
+ }
1831
+ this.isSplitLoading = true;
1832
+ sendSplitButton.disabled = true;
1833
+ sendSplitButton.textContent = "Sending...";
1834
+ this.showFeedback("Sending split payment...", "loading");
1835
+ const yourAmount = calculateSplit(this.totalCost, this.currentSplitMethod, emailData);
1836
+ this.dispatchEventFn(new CustomEvent("gait-split-sent", {
1837
+ detail: {
1838
+ splitMethod: this.currentSplitMethod,
1839
+ emails: emailData.map((d) => d.email),
1840
+ emailData,
1841
+ totalCost: this.totalCost,
1842
+ yourAmount,
1843
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1844
+ },
1845
+ bubbles: true,
1846
+ composed: true
1847
+ }));
1848
+ }
1849
+ setupFeedbackListener() {
1850
+ this.feedbackHandler = (event) => {
1851
+ const customEvent = event;
1852
+ if (customEvent.detail) {
1853
+ this.handleSplitFeedback(customEvent.detail);
1854
+ }
1855
+ };
1856
+ document.addEventListener("gait-split-feedback", this.feedbackHandler);
1857
+ }
1858
+ // Cleanup method (can be called when modal is closed)
1859
+ cleanup() {
1860
+ if (this.feedbackHandler) {
1861
+ document.removeEventListener("gait-split-feedback", this.feedbackHandler);
1862
+ this.feedbackHandler = null;
1863
+ }
1864
+ }
1865
+ handleSplitFeedback(feedback) {
1866
+ this.isSplitLoading = false;
1867
+ const sendSplitButton = this.modalElement.querySelector("[data-send-split]");
1868
+ if (feedback.success) {
1869
+ this.isSplitSent = true;
1870
+ this.markEmailsAsSent();
1871
+ this.disableSplitOptions();
1872
+ if (sendSplitButton) {
1873
+ sendSplitButton.disabled = true;
1874
+ sendSplitButton.textContent = "Split sent!";
1875
+ }
1876
+ this.showFeedback(feedback.message || "Split payment sent successfully", "success");
1877
+ } else {
1878
+ if (sendSplitButton) {
1879
+ sendSplitButton.disabled = false;
1880
+ sendSplitButton.textContent = "Send split";
1881
+ }
1882
+ this.showFeedback(feedback.message || feedback.error || "Failed to send split payment", "error");
1883
+ }
1884
+ }
1885
+ markEmailsAsSent() {
1886
+ const emailInputsContainer = this.modalElement.querySelector("[data-email-inputs]");
1887
+ if (!emailInputsContainer) return;
1888
+ const emailItems = emailInputsContainer.querySelectorAll("[data-email-item]");
1889
+ emailItems.forEach((item) => {
1890
+ if (!item.classList.contains("sent")) {
1891
+ item.classList.add("sent");
1892
+ const rightColumn = item.querySelector(".gait-modal-email-item-right");
1893
+ if (rightColumn) {
1894
+ let amountContainer = rightColumn.querySelector(".gait-modal-email-item-amount-container");
1895
+ const amountSpan = rightColumn.querySelector(".gait-modal-email-item-amount");
1896
+ if (!amountContainer && amountSpan) {
1897
+ amountContainer = document.createElement("div");
1898
+ amountContainer.className = "gait-modal-email-item-amount-container";
1899
+ amountSpan.parentElement?.replaceChild(amountContainer, amountSpan);
1900
+ amountContainer.appendChild(amountSpan);
1901
+ }
1902
+ if (amountContainer && !amountContainer.querySelector(".gait-modal-email-item-sent-check")) {
1903
+ const checkmark = document.createElement("div");
1904
+ checkmark.className = "gait-modal-email-item-sent-check";
1905
+ checkmark.innerHTML = checkIcon;
1906
+ amountContainer.appendChild(checkmark);
1907
+ }
1908
+ }
1909
+ const actions = item.querySelector(".gait-modal-email-item-actions");
1910
+ if (actions) {
1911
+ actions.style.display = "none";
1912
+ }
1913
+ }
1914
+ });
1915
+ }
1916
+ showFeedback(message, type) {
1917
+ if (this.splitFeedbackElement) {
1918
+ this.splitFeedbackElement.remove();
1919
+ this.splitFeedbackElement = null;
1920
+ }
1921
+ const feedback = document.createElement("div");
1922
+ feedback.className = `gait-modal-feedback gait-modal-feedback-${type}`;
1923
+ feedback.setAttribute("data-split-feedback", "");
1924
+ const icon = type === "success" ? checkIcon : type === "error" ? crossIcon : spinnerIcon;
1925
+ feedback.innerHTML = `
1926
+ <span class="gait-modal-feedback-icon">${icon}</span>
1927
+ <span class="gait-modal-feedback-message">${message}</span>
1928
+ `;
1929
+ const splitSection = this.modalElement.querySelector(".gait-modal-split-section");
1930
+ if (splitSection) {
1931
+ splitSection.insertBefore(feedback, splitSection.firstChild);
1932
+ this.splitFeedbackElement = feedback;
1933
+ if (type !== "loading") {
1934
+ setTimeout(() => {
1935
+ if (this.splitFeedbackElement === feedback) {
1936
+ feedback.style.opacity = "0";
1937
+ setTimeout(() => {
1938
+ if (feedback.parentElement) {
1939
+ feedback.remove();
1940
+ }
1941
+ if (this.splitFeedbackElement === feedback) {
1942
+ this.splitFeedbackElement = null;
1943
+ }
1944
+ }, 300);
1945
+ }
1946
+ }, 5e3);
1947
+ }
1948
+ }
1949
+ }
1950
+ disableSplitOptions() {
1951
+ const splitOptions = this.modalElement.querySelectorAll("[data-split-method]");
1952
+ splitOptions.forEach((option) => {
1953
+ const optionElement = option;
1954
+ optionElement.style.pointerEvents = "none";
1955
+ optionElement.style.opacity = "0.5";
1956
+ optionElement.style.cursor = "not-allowed";
1957
+ optionElement.setAttribute("aria-disabled", "true");
1958
+ });
1959
+ const addEmailButton = this.modalElement.querySelector("[data-add-email]");
1960
+ if (addEmailButton) {
1961
+ addEmailButton.style.pointerEvents = "none";
1962
+ addEmailButton.style.opacity = "0.5";
1963
+ addEmailButton.style.cursor = "not-allowed";
1964
+ addEmailButton.setAttribute("aria-disabled", "true");
1965
+ }
1966
+ }
1967
+ }
1968
+ async function sendSplitPayment(request, timeout = 2e3) {
1969
+ console.log("[SplitPaymentAPI] Sending split payment request:", request);
1970
+ const apiUrl = "https://api.usegait.cloud/checkout";
1971
+ try {
1972
+ const response = await fetch(`${apiUrl}/v1/payments`, {
1973
+ method: "POST",
1974
+ headers: {
1975
+ "Content-Type": "application/json"
1976
+ },
1977
+ body: JSON.stringify(request),
1978
+ signal: AbortSignal.timeout(timeout)
1979
+ });
1980
+ const apiResponse = await response.json().catch(() => ({
1981
+ success: false,
1982
+ error: "Failed to parse API response"
1983
+ }));
1984
+ if (apiResponse.success) {
1985
+ const successResponse = {
1986
+ success: true,
1987
+ message: apiResponse.message,
1988
+ data: apiResponse.data
1989
+ };
1990
+ console.log("[SplitPaymentAPI] Split payment sent successfully:", successResponse);
1991
+ return successResponse;
1992
+ } else {
1993
+ const errorResponse = {
1994
+ success: false,
1995
+ message: apiResponse.message,
1996
+ error: apiResponse.error
1997
+ };
1998
+ console.error("[SplitPaymentAPI] Split payment failed:", errorResponse);
1999
+ return errorResponse;
2000
+ }
2001
+ } catch (error) {
2002
+ const errorResponse = {
2003
+ success: false,
2004
+ message: "Failed to send split payment",
2005
+ error: error instanceof Error ? error.message : "Network error or server unavailable"
2006
+ };
2007
+ console.error("[SplitPaymentAPI] Split payment failed:", errorResponse, error);
2008
+ return errorResponse;
2009
+ }
2010
+ }
2011
+ let random = (bytes) => crypto.getRandomValues(new Uint8Array(bytes));
2012
+ let customRandom = (alphabet, defaultSize, getRandom) => {
2013
+ let mask = (2 << Math.log2(alphabet.length - 1)) - 1;
2014
+ let step = -~(1.6 * mask * defaultSize / alphabet.length);
2015
+ return (size = defaultSize) => {
2016
+ let id = "";
2017
+ while (true) {
2018
+ let bytes = getRandom(step);
2019
+ let j = step | 0;
2020
+ while (j--) {
2021
+ id += alphabet[bytes[j] & mask] || "";
2022
+ if (id.length >= size) return id;
2023
+ }
2024
+ }
2025
+ };
2026
+ };
2027
+ let customAlphabet = (alphabet, size = 21) => customRandom(alphabet, size | 0, random);
2028
+ const config = {
2029
+ apiGateway: {
2030
+ MERCHANT_SERVICE_API: "https://api.usegait.cloud/merchant",
2031
+ CHECKOUT_SERVICE_API: "https://api.usegait.cloud/checkout"
2032
+ },
2033
+ paylink: {
2034
+ DOMAIN: "https://checkout.usegait.cloud"
2035
+ }
2036
+ };
2037
+ const domain$1 = config.apiGateway.MERCHANT_SERVICE_API;
2038
+ class MerchantService {
2039
+ static async getMerchant(checkoutId) {
2040
+ try {
2041
+ const resp = await fetch(`${domain$1}/v1/merchant/identity/${checkoutId}`, {
2042
+ "method": "GET",
2043
+ headers: {
2044
+ "Content-Type": "application/json"
2045
+ }
2046
+ });
2047
+ return await resp.json();
2048
+ } catch (error) {
2049
+ return error;
2050
+ }
2051
+ }
2052
+ }
2053
+ const domain = config.apiGateway.CHECKOUT_SERVICE_API;
2054
+ class PaymentsService {
2055
+ static async getPayment(paymentId) {
2056
+ try {
2057
+ const resp = await fetch(`${domain}/v1/payments/${paymentId}`, {
2058
+ "method": "GET",
2059
+ headers: {
2060
+ "Content-Type": "application/json"
2061
+ }
2062
+ });
2063
+ return await resp.json();
2064
+ } catch (error) {
2065
+ return error;
2066
+ }
2067
+ }
2068
+ static async updatePaymentStatus(merchantId, splitId, status) {
2069
+ try {
2070
+ const resp = await fetch(`${domain}/v1/payments/merchants/${merchantId}/${splitId}/status`, {
2071
+ "method": "PUT",
2072
+ headers: {
2073
+ "Content-Type": "application/json"
2074
+ },
2075
+ body: JSON.stringify({
2076
+ status
2077
+ })
2078
+ });
2079
+ return await resp.json();
2080
+ } catch (error) {
2081
+ return error;
2082
+ }
2083
+ }
2084
+ static async createWebhook(merchantId, splitId, webhook) {
2085
+ try {
2086
+ const resp = await fetch(`${domain}/v1/webhooks/${merchantId}/${splitId}`, {
2087
+ "method": "POST",
2088
+ headers: {
2089
+ "Content-Type": "application/json"
2090
+ },
2091
+ body: JSON.stringify(webhook)
2092
+ });
2093
+ return await resp.json();
2094
+ } catch (error) {
2095
+ return error;
2096
+ }
2097
+ }
2098
+ static async updatePayment(merchantId, paymentId, splitId) {
2099
+ try {
2100
+ const resp = await fetch(`${domain}/v1/payments/merchants/${merchantId}/${splitId}`, {
2101
+ "method": "PUT",
2102
+ headers: {
2103
+ "Content-Type": "application/json"
2104
+ },
2105
+ body: JSON.stringify({
2106
+ paymentId
2107
+ })
2108
+ });
2109
+ return await resp.json();
2110
+ } catch (error) {
2111
+ return error;
2112
+ }
2113
+ }
2114
+ }
2115
+ function devLog(...args) {
2116
+ {
2117
+ console.log(...args);
2118
+ }
2119
+ }
2120
+ const _GAIT_BUTTON_VERSION_ENV = typeof process !== "undefined" && process.env ? "0.1.0" : void 0;
2121
+ const GAIT_BUTTON_VERSION = _GAIT_BUTTON_VERSION_ENV || "0.1.4";
2122
+ class GaitButton extends HTMLElement {
2123
+ buttonElement = null;
2124
+ hasRendered = false;
2125
+ mutationObserver = null;
2126
+ modalElement = null;
2127
+ modalId;
2128
+ splitPaymentManager = null;
2129
+ attributeGetters;
2130
+ storedSplitPaymentRequest = null;
2131
+ merchantId = null;
2132
+ paymentProvider = "stripe";
2133
+ // Expose version as static and instance properties for easy access
2134
+ static version = GAIT_BUTTON_VERSION;
2135
+ version = GAIT_BUTTON_VERSION;
2136
+ // Observed attributes for reactivity (label, theme, brand-color removed - fixed to Gait / #4147BF)
2137
+ static get observedAttributes() {
2138
+ return ["data-id", "disabled", "size", "style", "items", "price-breakdown", "total-cost", "webhook", "merchant-store-url"];
2139
+ }
2140
+ constructor() {
2141
+ super();
2142
+ this.attachShadow({ mode: "open" });
2143
+ this.modalId = `gait-modal-${Math.random().toString(36).substr(2, 9)}`;
2144
+ this.attributeGetters = createAttributeGetters(this);
2145
+ }
2146
+ // Lifecycle: Called when element is connected to DOM
2147
+ connectedCallback() {
2148
+ if (!this.hasRendered && this.shadowRoot) {
2149
+ this.render();
2150
+ }
2151
+ this.setupEventListeners();
2152
+ this.setupMutationObserver();
2153
+ this.setupApiListeners();
2154
+ setTimeout(() => this.processData(), 0);
2155
+ }
2156
+ // Lifecycle: Called when element is disconnected from DOM
2157
+ disconnectedCallback() {
2158
+ if (this.buttonElement) {
2159
+ this.buttonElement.removeEventListener("click", this.handleClick);
2160
+ }
2161
+ if (this.mutationObserver) {
2162
+ this.mutationObserver.disconnect();
2163
+ this.mutationObserver = null;
2164
+ }
2165
+ this.closeModal();
2166
+ if (this.splitPaymentManager) {
2167
+ this.splitPaymentManager = null;
2168
+ }
2169
+ this.removeEventListener("gait-split-sent", this.handleSplitSent);
2170
+ }
2171
+ // Lifecycle: Called when observed attributes change
2172
+ attributeChangedCallback(name, oldValue, newValue) {
2173
+ if (oldValue === newValue) {
2174
+ return;
2175
+ }
2176
+ if (!this.isConnected || !this.shadowRoot) {
2177
+ return;
2178
+ }
2179
+ if (name === "style" && this.buttonElement && this.hasRendered) {
2180
+ const sanitizedStyle = (newValue || "").replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
2181
+ this.buttonElement.setAttribute("style", sanitizedStyle);
2182
+ return;
2183
+ }
2184
+ if (this.hasRendered) {
2185
+ this.render();
2186
+ this.setupEventListeners();
2187
+ }
2188
+ if (name === "data-id" || name.startsWith("data-")) {
2189
+ if (name === "data-id") {
2190
+ this.merchantId = null;
2191
+ }
2192
+ setTimeout(() => this.processData(), 0);
2193
+ }
2194
+ }
2195
+ // Getters for attributes with defaults (using attribute getters)
2196
+ get dataId() {
2197
+ return this.attributeGetters.dataId;
2198
+ }
2199
+ get disabled() {
2200
+ return this.attributeGetters.disabled;
2201
+ }
2202
+ get size() {
2203
+ return this.attributeGetters.size;
2204
+ }
2205
+ get items() {
2206
+ return this.attributeGetters.items;
2207
+ }
2208
+ get priceBreakdown() {
2209
+ return this.attributeGetters.priceBreakdown;
2210
+ }
2211
+ get totalCost() {
2212
+ return this.attributeGetters.totalCost;
2213
+ }
2214
+ get customer() {
2215
+ return this.attributeGetters.customer;
2216
+ }
2217
+ get webhook() {
2218
+ return this.attributeGetters.webhook;
2219
+ }
2220
+ get merchantStoreUrl() {
2221
+ return this.attributeGetters.merchantStoreUrl;
2222
+ }
2223
+ // Get all data-* attributes
2224
+ getDataAttributes() {
2225
+ return getDataAttributes(this);
2226
+ }
2227
+ // Fetch merchantId from API using checkoutId (data-id)
2228
+ async fetchMerchantId() {
2229
+ const checkoutId = this.dataId;
2230
+ if (!checkoutId) {
2231
+ console.warn("[GaitButton] No checkoutId (data-id) provided, cannot fetch merchantId");
2232
+ this.showMerchantIdError();
2233
+ return false;
2234
+ }
2235
+ try {
2236
+ const response = await MerchantService.getMerchant(checkoutId);
2237
+ if (response.success && response.data?.merchantId) {
2238
+ this.merchantId = response.data.merchantId;
2239
+ this.paymentProvider = response.data.paymentProvider;
2240
+ return true;
2241
+ } else {
2242
+ console.error("[GaitButton] Failed to fetch merchantId:", response);
2243
+ this.showMerchantIdError();
2244
+ return false;
2245
+ }
2246
+ } catch (error) {
2247
+ console.error("[GaitButton] Error fetching merchantId:", error);
2248
+ this.showMerchantIdError();
2249
+ return false;
2250
+ }
2251
+ }
2252
+ // Show error message when merchantId cannot be identified
2253
+ showMerchantIdError() {
2254
+ const errorMessage = "Unable to identify your account. Please go to your dashboard and copy your checkout identity.";
2255
+ alert(errorMessage);
2256
+ this.dispatchEvent(new CustomEvent("gait-merchant-id-error", {
2257
+ detail: {
2258
+ message: errorMessage,
2259
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2260
+ },
2261
+ bubbles: true,
2262
+ composed: true
2263
+ }));
2264
+ }
2265
+ // Process data from attributes and do something (like console.log)
2266
+ async processData() {
2267
+ const dataId = this.dataId;
2268
+ const allDataAttrs = this.getDataAttributes();
2269
+ if (dataId && !this.merchantId) {
2270
+ await this.fetchMerchantId();
2271
+ }
2272
+ if (dataId || Object.keys(allDataAttrs).length > 0) {
2273
+ const data = {
2274
+ id: dataId,
2275
+ ...allDataAttrs,
2276
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2277
+ };
2278
+ devLog("[GaitButton] Processing data v0.0.16:", data);
2279
+ this.dispatchEvent(new CustomEvent("gait-data-processed", {
2280
+ detail: data,
2281
+ bubbles: true,
2282
+ composed: true
2283
+ }));
2284
+ }
2285
+ }
2286
+ // Handle click events
2287
+ handleClick = async (event) => {
2288
+ if (this.disabled) {
2289
+ event.preventDefault();
2290
+ event.stopPropagation();
2291
+ return;
2292
+ }
2293
+ const clickData = {
2294
+ label: "Gait",
2295
+ dataId: this.dataId,
2296
+ dataAttributes: this.getDataAttributes(),
2297
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2298
+ };
2299
+ this.dispatchEvent(new CustomEvent("gait-click", {
2300
+ detail: clickData,
2301
+ bubbles: true,
2302
+ composed: true
2303
+ }));
2304
+ this.dispatchEvent(new CustomEvent("click", {
2305
+ detail: clickData,
2306
+ bubbles: true,
2307
+ composed: true
2308
+ }));
2309
+ if (!this.merchantId) {
2310
+ const fetched = await this.fetchMerchantId();
2311
+ if (!fetched || !this.merchantId) {
2312
+ return;
2313
+ }
2314
+ }
2315
+ this.openModal();
2316
+ };
2317
+ // Setup event listeners
2318
+ setupEventListeners() {
2319
+ if (!this.shadowRoot) {
2320
+ return;
2321
+ }
2322
+ if (this.buttonElement) {
2323
+ this.buttonElement.removeEventListener("click", this.handleClick);
2324
+ }
2325
+ this.buttonElement = this.shadowRoot.querySelector("button");
2326
+ if (this.buttonElement) {
2327
+ this.buttonElement.addEventListener("click", this.handleClick);
2328
+ }
2329
+ }
2330
+ // Setup MutationObserver to watch for data-* attribute changes
2331
+ setupMutationObserver() {
2332
+ if (this.mutationObserver) {
2333
+ this.mutationObserver.disconnect();
2334
+ }
2335
+ this.mutationObserver = new MutationObserver((mutations) => {
2336
+ let shouldProcessData = false;
2337
+ for (const mutation of mutations) {
2338
+ if (mutation.type === "attributes") {
2339
+ const attrName = mutation.attributeName;
2340
+ if (attrName && attrName.startsWith("data-") && !GaitButton.observedAttributes.includes(attrName)) {
2341
+ shouldProcessData = true;
2342
+ break;
2343
+ }
2344
+ }
2345
+ }
2346
+ if (shouldProcessData && this.isConnected) {
2347
+ this.processData();
2348
+ }
2349
+ });
2350
+ this.mutationObserver.observe(this, {
2351
+ attributes: true,
2352
+ attributeFilter: void 0
2353
+ // Observe all attributes
2354
+ });
2355
+ }
2356
+ // Setup API event listeners
2357
+ setupApiListeners() {
2358
+ this.addEventListener("gait-split-sent", this.handleSplitSent);
2359
+ }
2360
+ // Handle confirm payment (Pay remaining button)
2361
+ handleConfirmPayment = async () => {
2362
+ console.log("[GaitButton] Pay remaining button clicked");
2363
+ if (!this.storedSplitPaymentRequest) {
2364
+ console.error("[GaitButton] Split payment must be sent first before paying remaining amount");
2365
+ return;
2366
+ }
2367
+ if (!this.merchantId) {
2368
+ const fetched = await this.fetchMerchantId();
2369
+ if (!fetched || !this.merchantId) {
2370
+ return;
2371
+ }
2372
+ }
2373
+ const initiatorObject = {
2374
+ merchantId: this.merchantId,
2375
+ splitId: this.storedSplitPaymentRequest.splitId,
2376
+ paymentId: this.storedSplitPaymentRequest.paymentSplits.find((payment) => payment.initiator)?.paymentId
2377
+ };
2378
+ const paylinkDomain = config.paylink.DOMAIN;
2379
+ const paylink = `${paylinkDomain}/payment/${initiatorObject.paymentId}`;
2380
+ window.open(paylink, "_blank");
2381
+ this.dispatchEvent(new CustomEvent("gait-confirm", {
2382
+ detail: initiatorObject,
2383
+ bubbles: true,
2384
+ composed: true
2385
+ }));
2386
+ this.closeModal();
2387
+ };
2388
+ // Handle split payment sent event and make API call
2389
+ handleSplitSent = async (event) => {
2390
+ const customEvent = event;
2391
+ const splitData = customEvent.detail;
2392
+ if (!this.merchantId) {
2393
+ const fetched = await this.fetchMerchantId();
2394
+ if (!fetched || !this.merchantId) {
2395
+ return;
2396
+ }
2397
+ }
2398
+ const merchantId = this.merchantId;
2399
+ const customer = this.customer;
2400
+ if (!customer || !customer.email) {
2401
+ console.error("[GaitButton] Customer email is required for split payment");
2402
+ return;
2403
+ }
2404
+ const webhook = this.webhook;
2405
+ if (!webhook || !webhook.url || webhook.body == null) {
2406
+ console.error("[GaitButton] Webhook with url and body is required");
2407
+ return;
2408
+ }
2409
+ const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2410
+ const generateId = customAlphabet(alphabet, 6);
2411
+ const splitId = generateId();
2412
+ const paymentSplits = [];
2413
+ paymentSplits.push({
2414
+ paymentId: generateId(),
2415
+ email: customer.email,
2416
+ amount: splitData.yourAmount,
2417
+ isPaid: false,
2418
+ datePaid: null,
2419
+ initiator: true
2420
+ });
2421
+ splitData.emailData.forEach((emailData) => {
2422
+ paymentSplits.push({
2423
+ paymentId: generateId(),
2424
+ email: emailData.email,
2425
+ amount: emailData.amount || 0,
2426
+ isPaid: false,
2427
+ datePaid: null,
2428
+ initiator: false
2429
+ });
2430
+ });
2431
+ const id = {
2432
+ merchantId,
2433
+ splitId,
2434
+ paymentSplits,
2435
+ splitMethod: splitData.splitMethod,
2436
+ timestamp: splitData.timestamp,
2437
+ totalCost: splitData.totalCost,
2438
+ items: this.items,
2439
+ priceBreakdown: this.priceBreakdown,
2440
+ brandColor: GAIT_BRAND_COLOR,
2441
+ merchantStoreUrl: this.merchantStoreUrl,
2442
+ subTotal: this.priceBreakdown.find((item) => item.name === "Subtotal")?.price || 0,
2443
+ paymentProvider: this.paymentProvider
2444
+ };
2445
+ console.log("[GaitButton] Split payment request body:", JSON.stringify(id, null, 2));
2446
+ try {
2447
+ const response = await sendSplitPayment(id, 2e3);
2448
+ if (response.success) {
2449
+ const finalSplitId = response.data?.splitId || splitId;
2450
+ this.storedSplitPaymentRequest = {
2451
+ ...id,
2452
+ splitId: finalSplitId
2453
+ };
2454
+ try {
2455
+ const webhookResponse = await PaymentsService.createWebhook(
2456
+ merchantId,
2457
+ finalSplitId,
2458
+ {
2459
+ url: webhook.url,
2460
+ body: webhook.body
2461
+ }
2462
+ );
2463
+ console.log("[GaitButton] Webhook created:", webhookResponse);
2464
+ } catch (webhookError) {
2465
+ console.error("[GaitButton] Failed to create webhook:", webhookError);
2466
+ }
2467
+ }
2468
+ if (this.modalElement) {
2469
+ const confirmButton = this.modalElement.querySelector("[data-gait-modal-confirm]");
2470
+ if (confirmButton) {
2471
+ confirmButton.disabled = false;
2472
+ confirmButton.style.opacity = "1";
2473
+ confirmButton.style.cursor = "pointer";
2474
+ }
2475
+ }
2476
+ this.dispatchEvent(new CustomEvent("gait-split-feedback", {
2477
+ detail: {
2478
+ success: response.success,
2479
+ message: response.message,
2480
+ data: response.success ? this.storedSplitPaymentRequest : response.data,
2481
+ error: response.error,
2482
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2483
+ },
2484
+ bubbles: true,
2485
+ composed: true
2486
+ }));
2487
+ console.log("[GaitButton] Split payment API response:", response);
2488
+ } catch (error) {
2489
+ console.error("[GaitButton] Split payment API error:", error);
2490
+ this.dispatchEvent(new CustomEvent("gait-split-feedback", {
2491
+ detail: {
2492
+ success: false,
2493
+ message: "Failed to send split payment",
2494
+ error: error instanceof Error ? error.message : "Unknown error",
2495
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2496
+ },
2497
+ bubbles: true,
2498
+ composed: true
2499
+ }));
2500
+ }
2501
+ };
2502
+ // Open modal
2503
+ openModal() {
2504
+ injectModalStyles();
2505
+ this.closeModal();
2506
+ this.modalElement = document.createElement("div");
2507
+ this.modalElement.className = "gait-modal-backdrop";
2508
+ this.modalElement.id = this.modalId;
2509
+ if (this.modalElement) {
2510
+ this.modalElement.style.setProperty("--gait-modal-brand-color", GAIT_BRAND_COLOR);
2511
+ this.modalElement.style.setProperty("--gait-modal-button-bg", GAIT_BRAND_COLOR);
2512
+ this.modalElement.style.setProperty("--gait-modal-button-bg-hover", darkenColor(GAIT_BRAND_COLOR, 0.15));
2513
+ this.modalElement.style.setProperty("--gait-modal-button-color", isColorDark(GAIT_BRAND_COLOR) ? "#ffffff" : "#000000");
2514
+ }
2515
+ this.modalElement.innerHTML = generateModalTemplate(
2516
+ this.items,
2517
+ this.priceBreakdown,
2518
+ this.totalCost
2519
+ );
2520
+ const closeButton = this.modalElement.querySelector("[data-gait-modal-close]");
2521
+ if (closeButton) {
2522
+ closeButton.addEventListener("click", this.closeModal);
2523
+ }
2524
+ const confirmButton = this.modalElement.querySelector("[data-gait-modal-confirm]");
2525
+ if (confirmButton) {
2526
+ confirmButton.disabled = true;
2527
+ confirmButton.style.opacity = "0.5";
2528
+ confirmButton.style.cursor = "not-allowed";
2529
+ confirmButton.addEventListener("click", this.handleConfirmPayment);
2530
+ }
2531
+ this.splitPaymentManager = new SplitPaymentManager(
2532
+ this.modalElement,
2533
+ this.totalCost,
2534
+ (event) => this.dispatchEvent(event)
2535
+ );
2536
+ this.modalElement._splitPaymentManager = this.splitPaymentManager;
2537
+ this.modalElement.addEventListener("click", (e) => {
2538
+ if (e.target === this.modalElement) {
2539
+ this.closeModal();
2540
+ }
2541
+ });
2542
+ const handleEscape = (e) => {
2543
+ if (e.key === "Escape" && this.modalElement) {
2544
+ this.closeModal();
2545
+ document.removeEventListener("keydown", handleEscape);
2546
+ }
2547
+ };
2548
+ document.addEventListener("keydown", handleEscape);
2549
+ document.body.appendChild(this.modalElement);
2550
+ requestAnimationFrame(() => {
2551
+ if (this.modalElement) {
2552
+ this.modalElement.classList.add("gait-modal-open");
2553
+ }
2554
+ });
2555
+ }
2556
+ // Close modal
2557
+ closeModal = () => {
2558
+ if (this.modalElement) {
2559
+ if (this.splitPaymentManager) {
2560
+ this.splitPaymentManager.cleanup();
2561
+ }
2562
+ this.modalElement.classList.remove("gait-modal-open");
2563
+ setTimeout(() => {
2564
+ if (this.modalElement && this.modalElement.parentNode) {
2565
+ this.modalElement.parentNode.removeChild(this.modalElement);
2566
+ }
2567
+ this.modalElement = null;
2568
+ this.splitPaymentManager = null;
2569
+ }, 250);
2570
+ }
2571
+ };
2572
+ // Render the component
2573
+ render() {
2574
+ const shadow = this.shadowRoot;
2575
+ if (!shadow) {
2576
+ return;
2577
+ }
2578
+ const wasFirstRender = !this.hasRendered;
2579
+ const styles = generateButtonStyles(
2580
+ this.size,
2581
+ darkenColor,
2582
+ isColorDark
2583
+ );
2584
+ const hostStyle = this.getAttribute("style") || "";
2585
+ const sanitizedStyle = hostStyle.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
2586
+ shadow.innerHTML = `
2587
+ ${styles}
2588
+ ${generateButtonTemplate(this.disabled, sanitizedStyle)}
2589
+ `;
2590
+ this.hasRendered = true;
2591
+ this.setupEventListeners();
2592
+ if (wasFirstRender) {
2593
+ const allAttributes = getAllAttributes(this);
2594
+ console.log("[GaitButton] rendered", allAttributes);
2595
+ this.dispatchEvent(new CustomEvent("gait-loaded", {
2596
+ detail: {
2597
+ attributes: allAttributes,
2598
+ dataId: this.dataId,
2599
+ dataAttributes: this.getDataAttributes(),
2600
+ label: "Gait",
2601
+ size: this.size,
2602
+ disabled: this.disabled,
2603
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2604
+ },
2605
+ bubbles: true,
2606
+ composed: true
2607
+ }));
2608
+ }
2609
+ }
2610
+ }
2611
+ if (!customElements.get("gait-button")) {
2612
+ customElements.define("gait-button", GaitButton);
2613
+ }
2614
+ if (!customElements.get("gait-button")) {
2615
+ customElements.define("gait-button", GaitButton);
2616
+ }
2617
+ if (typeof window !== "undefined") {
2618
+ window.GaitButton = GaitButton;
2619
+ window.GaitButtonVersion = GAIT_BUTTON_VERSION;
2620
+ console.log(`[GaitButton] Version: ${GAIT_BUTTON_VERSION}`);
2621
+ }
2622
+ exports.GAIT_BUTTON_VERSION = GAIT_BUTTON_VERSION;
2623
+ exports.GaitButton = GaitButton;
2624
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2625
+ })(this.GaitButton = this.GaitButton || {});