@aglyn/plugins-commerce 1.0.0-beta.290 → 1.0.0-beta.292

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 (183) hide show
  1. package/README.md +4 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/cart-fulfillment.d.ts +3 -0
  4. package/src/lib/components/cart-fulfillment.js.map +1 -1
  5. package/src/lib/components/cart.js +14 -4
  6. package/src/lib/components/cart.js.map +1 -1
  7. package/src/lib/components/commerce-console-page.js +2 -1
  8. package/src/lib/components/commerce-console-page.js.map +1 -1
  9. package/src/lib/components/console/host-orders-card.component.d.ts +6 -0
  10. package/src/lib/components/console/host-orders-card.component.js +3 -2
  11. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  12. package/src/lib/components/console/invoice-send.component.d.ts +44 -0
  13. package/src/lib/components/console/invoice-send.component.js +237 -0
  14. package/src/lib/components/console/invoice-send.component.js.map +1 -0
  15. package/src/lib/components/console/order-detail-dialog.component.d.ts +5 -0
  16. package/src/lib/components/console/order-detail-dialog.component.js +9 -2
  17. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  18. package/src/lib/components/console/order-invoice.component.d.ts +9 -0
  19. package/src/lib/components/console/order-invoice.component.js +27 -2
  20. package/src/lib/components/console/order-invoice.component.js.map +1 -1
  21. package/src/lib/components/console/pos/pos-item-dialog.component.js +3 -2
  22. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  23. package/src/lib/components/console/pos-kiosk-page.component.js +2 -1
  24. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -1
  25. package/src/lib/components/console/pos-page.component.js +1 -1
  26. package/src/lib/components/console/pos-page.component.js.map +1 -1
  27. package/src/lib/components/console/product-add-ons-fields.component.d.ts +41 -0
  28. package/src/lib/components/console/product-add-ons-fields.component.js +356 -0
  29. package/src/lib/components/console/product-add-ons-fields.component.js.map +1 -0
  30. package/src/lib/components/console/product-editor-dialog.component.js +31 -5
  31. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  32. package/src/lib/components/console/product-register-fields.component.d.ts +4 -5
  33. package/src/lib/components/console/product-register-fields.component.js +8 -197
  34. package/src/lib/components/console/product-register-fields.component.js.map +1 -1
  35. package/src/lib/components/console/products-hub-zone.component.js +6 -0
  36. package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
  37. package/src/lib/components/console/quote-editor-dialog.component.d.ts +29 -0
  38. package/src/lib/components/console/quote-editor-dialog.component.js +102 -4
  39. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -1
  40. package/src/lib/components/console/quote-pay-link.component.d.ts +8 -1
  41. package/src/lib/components/console/quote-pay-link.component.js +29 -3
  42. package/src/lib/components/console/quote-pay-link.component.js.map +1 -1
  43. package/src/lib/components/console/quote-proofs.component.d.ts +11 -0
  44. package/src/lib/components/console/quote-proofs.component.js +68 -0
  45. package/src/lib/components/console/quote-proofs.component.js.map +1 -1
  46. package/src/lib/components/console/quote-send.component.d.ts +42 -0
  47. package/src/lib/components/console/quote-send.component.js +304 -0
  48. package/src/lib/components/console/quote-send.component.js.map +1 -0
  49. package/src/lib/components/console/quote-start.component.d.ts +45 -0
  50. package/src/lib/components/console/quote-start.component.js +182 -0
  51. package/src/lib/components/console/quote-start.component.js.map +1 -0
  52. package/src/lib/components/product-add-ons.d.ts +28 -0
  53. package/src/lib/components/product-add-ons.js +136 -0
  54. package/src/lib/components/product-add-ons.js.map +1 -0
  55. package/src/lib/components/product-detail.d.ts +16 -0
  56. package/src/lib/components/product-detail.js +112 -19
  57. package/src/lib/components/product-detail.js.map +1 -1
  58. package/src/lib/components/product-grid.d.ts +8 -2
  59. package/src/lib/components/product-grid.js +6 -1
  60. package/src/lib/components/product-grid.js.map +1 -1
  61. package/src/lib/components/product-options-field-body.d.ts +44 -0
  62. package/src/lib/components/product-options-field-body.js +260 -0
  63. package/src/lib/components/product-options-field-body.js.map +1 -0
  64. package/src/lib/components/product-options-field.d.ts +32 -0
  65. package/src/lib/components/product-options-field.js +128 -0
  66. package/src/lib/components/product-options-field.js.map +1 -0
  67. package/src/lib/components/quote-page-body.js +39 -20
  68. package/src/lib/components/quote-page-body.js.map +1 -1
  69. package/src/lib/model/commerce-cart.d.ts +15 -3
  70. package/src/lib/model/commerce-cart.js +10 -3
  71. package/src/lib/model/commerce-cart.js.map +1 -1
  72. package/src/lib/model/commerce-invoices.d.ts +139 -0
  73. package/src/lib/model/commerce-invoices.js +343 -0
  74. package/src/lib/model/commerce-invoices.js.map +1 -0
  75. package/src/lib/model/commerce-orders.d.ts +35 -5
  76. package/src/lib/model/commerce-orders.js +3 -0
  77. package/src/lib/model/commerce-orders.js.map +1 -1
  78. package/src/lib/model/commerce-pos-kiosk.d.ts +1 -1
  79. package/src/lib/model/commerce-pos-kiosk.js +3 -2
  80. package/src/lib/model/commerce-pos-kiosk.js.map +1 -1
  81. package/src/lib/model/commerce-product-field.d.ts +23 -0
  82. package/src/lib/model/commerce-product-field.js +26 -0
  83. package/src/lib/model/commerce-product-field.js.map +1 -0
  84. package/src/lib/model/commerce-quote-email.d.ts +81 -0
  85. package/src/lib/model/commerce-quote-email.js +170 -0
  86. package/src/lib/model/commerce-quote-email.js.map +1 -0
  87. package/src/lib/model/commerce-quote-pay.d.ts +49 -6
  88. package/src/lib/model/commerce-quote-pay.js +69 -36
  89. package/src/lib/model/commerce-quote-pay.js.map +1 -1
  90. package/src/lib/model/commerce-quote-request.d.ts +93 -0
  91. package/src/lib/model/commerce-quote-request.js +207 -0
  92. package/src/lib/model/commerce-quote-request.js.map +1 -0
  93. package/src/lib/model/commerce-quotes.d.ts +81 -0
  94. package/src/lib/model/commerce-quotes.js +1 -1
  95. package/src/lib/model/commerce-quotes.js.map +1 -1
  96. package/src/lib/model/commerce.d.ts +18 -0
  97. package/src/lib/model/commerce.js +26 -0
  98. package/src/lib/model/commerce.js.map +1 -1
  99. package/src/lib/model/index.d.ts +3 -0
  100. package/src/lib/model/index.js +3 -0
  101. package/src/lib/model/index.js.map +1 -1
  102. package/src/lib/model/product-modifiers.d.ts +74 -4
  103. package/src/lib/model/product-modifiers.js +131 -10
  104. package/src/lib/model/product-modifiers.js.map +1 -1
  105. package/src/lib/plugin.js +19 -0
  106. package/src/lib/plugin.js.map +1 -1
  107. package/src/lib/server/billing-webhook.js +164 -98
  108. package/src/lib/server/billing-webhook.js.map +1 -1
  109. package/src/lib/server/cart-checkout.js +14 -2
  110. package/src/lib/server/cart-checkout.js.map +1 -1
  111. package/src/lib/server/cart.d.ts +5 -0
  112. package/src/lib/server/cart.js +41 -4
  113. package/src/lib/server/cart.js.map +1 -1
  114. package/src/lib/server/catalog.d.ts +6 -0
  115. package/src/lib/server/catalog.js +2 -0
  116. package/src/lib/server/catalog.js.map +1 -1
  117. package/src/lib/server/checkout-extras.js +3 -1
  118. package/src/lib/server/checkout-extras.js.map +1 -1
  119. package/src/lib/server/checkout.js +28 -3
  120. package/src/lib/server/checkout.js.map +1 -1
  121. package/src/lib/server/commerce-pdf.d.ts +5 -1
  122. package/src/lib/server/commerce-pdf.js +37 -10
  123. package/src/lib/server/commerce-pdf.js.map +1 -1
  124. package/src/lib/server/draft-order.js +23 -3
  125. package/src/lib/server/draft-order.js.map +1 -1
  126. package/src/lib/server/invoice-email.d.ts +76 -0
  127. package/src/lib/server/invoice-email.js +183 -0
  128. package/src/lib/server/invoice-email.js.map +1 -0
  129. package/src/lib/server/local-fulfillment.js +5 -1
  130. package/src/lib/server/local-fulfillment.js.map +1 -1
  131. package/src/lib/server/order-invoice-send.d.ts +43 -0
  132. package/src/lib/server/order-invoice-send.js +218 -0
  133. package/src/lib/server/order-invoice-send.js.map +1 -0
  134. package/src/lib/server/order-status.d.ts +11 -0
  135. package/src/lib/server/order-status.js +44 -8
  136. package/src/lib/server/order-status.js.map +1 -1
  137. package/src/lib/server/person-eraser.d.ts +3 -2
  138. package/src/lib/server/person-eraser.js +25 -6
  139. package/src/lib/server/person-eraser.js.map +1 -1
  140. package/src/lib/server/pos-offline-sync.js +1 -1
  141. package/src/lib/server/pos-offline-sync.js.map +1 -1
  142. package/src/lib/server/pos-order.js +1 -1
  143. package/src/lib/server/pos-order.js.map +1 -1
  144. package/src/lib/server/product.d.ts +26 -0
  145. package/src/lib/server/product.js +18 -0
  146. package/src/lib/server/product.js.map +1 -1
  147. package/src/lib/server/products-write.js +5 -2
  148. package/src/lib/server/products-write.js.map +1 -1
  149. package/src/lib/server/quote-email.d.ts +85 -0
  150. package/src/lib/server/quote-email.js +211 -0
  151. package/src/lib/server/quote-email.js.map +1 -0
  152. package/src/lib/server/quote-link-token.d.ts +11 -0
  153. package/src/lib/server/quote-link-token.js +21 -0
  154. package/src/lib/server/quote-link-token.js.map +1 -1
  155. package/src/lib/server/quote-pay.d.ts +8 -3
  156. package/src/lib/server/quote-pay.js +105 -43
  157. package/src/lib/server/quote-pay.js.map +1 -1
  158. package/src/lib/server/quote.d.ts +11 -0
  159. package/src/lib/server/quote.js +309 -12
  160. package/src/lib/server/quote.js.map +1 -1
  161. package/src/lib/server/site-page-resolver.js +2 -1
  162. package/src/lib/server/site-page-resolver.js.map +1 -1
  163. package/src/lib/server.js +5 -0
  164. package/src/lib/server.js.map +1 -1
  165. package/src/lib/site.js +8 -0
  166. package/src/lib/site.js.map +1 -1
  167. package/src/lib/tenant-emails.js +243 -0
  168. package/src/lib/tenant-emails.js.map +1 -1
  169. package/src/lib/utils/add-to-cart.d.ts +8 -0
  170. package/src/lib/utils/add-to-cart.js +10 -2
  171. package/src/lib/utils/add-to-cart.js.map +1 -1
  172. package/src/lib/utils/commerce-document-pdf.d.ts +5 -0
  173. package/src/lib/utils/commerce-document-pdf.js +6 -1
  174. package/src/lib/utils/commerce-document-pdf.js.map +1 -1
  175. package/src/lib/utils/invoice-email-content.d.ts +45 -0
  176. package/src/lib/utils/invoice-email-content.js +126 -0
  177. package/src/lib/utils/invoice-email-content.js.map +1 -0
  178. package/src/lib/utils/order-invoice.d.ts +1 -1
  179. package/src/lib/utils/order-invoice.js +14 -6
  180. package/src/lib/utils/order-invoice.js.map +1 -1
  181. package/src/lib/utils/quote-email-content.d.ts +63 -0
  182. package/src/lib/utils/quote-email-content.js +157 -0
  183. package/src/lib/utils/quote-email-content.js.map +1 -0
@@ -33,6 +33,12 @@ import { StorefrontPaymentElementFallback } from "./storefront-payment-element-f
33
33
  /** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */ const StorefrontPaymentElement = /*#__PURE__*/ lazy(()=>import("./storefront-payment-element.js").then((module)=>({
34
34
  default: module.StorefrontPaymentElement
35
35
  })));
36
+ /** `quote` or `invoice`, as the page says it (AGL-4099). */ const nounOf = (kind)=>kind === 'invoice' ? 'invoice' : 'quote';
37
+ /** What is added when the customer pays: `shipping`, `tax`, `shipping and tax`, or nothing. */ function addedAtPayment(view) {
38
+ if (view.shippingAtPayment && view.taxAtPayment) return 'shipping and tax';
39
+ if (view.shippingAtPayment) return 'shipping';
40
+ return view.taxAtPayment ? 'tax' : '';
41
+ }
36
42
  /** After a payment returns here, how often and how long the page asks whether it landed. */ const CONFIRM_POLL_MS = 2000;
37
43
  const CONFIRM_POLLS = 15;
38
44
  function dateLabel(atMs) {
@@ -151,20 +157,23 @@ function TotalRow({ label, value, strong }) {
151
157
  const load = useCallback(async ()=>{
152
158
  const { quoteId, token } = link.current;
153
159
  try {
154
- var _payload_storeName;
155
160
  const response = await siteFetch(`/api/commerce/quote-view?hostId=${encodeURIComponent(hostId != null ? hostId : '')}` + `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`);
156
161
  const payload = await response.json().catch(()=>({}));
157
162
  if (!response.ok) {
158
163
  var _ref;
159
164
  return {
160
165
  kind: 'missing',
161
- message: String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'We could not find that quote.')
166
+ message: String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'We could not find that quote or invoice.')
167
+ };
168
+ }
169
+ if ((payload == null ? void 0 : payload.state) === 'replaced') {
170
+ var _payload_storeName;
171
+ return {
172
+ kind: 'replaced',
173
+ storeName: String((_payload_storeName = payload.storeName) != null ? _payload_storeName : ''),
174
+ noun: nounOf(payload.kind)
162
175
  };
163
176
  }
164
- if ((payload == null ? void 0 : payload.state) === 'replaced') return {
165
- kind: 'replaced',
166
- storeName: String((_payload_storeName = payload.storeName) != null ? _payload_storeName : '')
167
- };
168
177
  return {
169
178
  kind: 'ready',
170
179
  view: payload
@@ -172,7 +181,7 @@ function TotalRow({ label, value, strong }) {
172
181
  } catch (unused) {
173
182
  return {
174
183
  kind: 'missing',
175
- message: 'This quote could not be loaded. Check your connection and try again.'
184
+ message: 'This page could not be loaded. Check your connection and try again.'
176
185
  };
177
186
  }
178
187
  }, [
@@ -191,7 +200,7 @@ function TotalRow({ label, value, strong }) {
191
200
  if (!link.current.quoteId || !link.current.token) {
192
201
  setState({
193
202
  kind: 'missing',
194
- message: 'Open this page from the link you were sent with your quote.'
203
+ message: 'Open this page from the link you were sent with your quote or invoice.'
195
204
  });
196
205
  return;
197
206
  }
@@ -276,7 +285,8 @@ function TotalRow({ label, value, strong }) {
276
285
  if (payload == null ? void 0 : payload.replaced) {
277
286
  setState({
278
287
  kind: 'replaced',
279
- storeName: view.storeName
288
+ storeName: view.storeName,
289
+ noun: nounOf(view.kind)
280
290
  });
281
291
  return;
282
292
  }
@@ -330,7 +340,7 @@ function TotalRow({ label, value, strong }) {
330
340
  ],
331
341
  children: /*#__PURE__*/ _jsx(CircularProgress, {
332
342
  size: 28,
333
- "aria-label": "Loading your quote"
343
+ "aria-label": "Loading"
334
344
  })
335
345
  }));
336
346
  }
@@ -345,7 +355,7 @@ function TotalRow({ label, value, strong }) {
345
355
  /*#__PURE__*/ _jsx(Typography, {
346
356
  variant: "h4",
347
357
  component: "h1",
348
- children: heading || 'Your quote'
358
+ children: heading || 'Your quote or invoice'
349
359
  }),
350
360
  /*#__PURE__*/ _jsx(Alert, {
351
361
  severity: "info",
@@ -372,12 +382,12 @@ function TotalRow({ label, value, strong }) {
372
382
  /*#__PURE__*/ _jsx(Typography, {
373
383
  variant: "h4",
374
384
  component: "h1",
375
- children: 'This quote was updated'
385
+ children: `This ${state.noun} was updated`
376
386
  }),
377
387
  /*#__PURE__*/ _jsx(Typography, {
378
388
  variant: "body1",
379
389
  color: "text.secondary",
380
- children: `${business} updated this quote and sent you a newer link. Open their most recent message to see it.`
390
+ children: `${business} updated this ${state.noun} and sent you a newer link. Open their most recent message to see it.`
381
391
  })
382
392
  ]
383
393
  })
@@ -388,6 +398,8 @@ function TotalRow({ label, value, strong }) {
388
398
  // The same signed link as the page's data; the server makes the PDF from the same view.
389
399
  const pdfHref = `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` + `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`;
390
400
  const unpaid = quote.status === 'unpaid';
401
+ const noun = nounOf(quote.kind);
402
+ const later = addedAtPayment(quote);
391
403
  const addresses = [
392
404
  quote.customerName || quote.company ? {
393
405
  label: 'Prepared for',
@@ -426,6 +438,12 @@ function TotalRow({ label, value, strong }) {
426
438
  money(quote.totals.taxCents),
427
439
  quote.totals.taxCents > 0
428
440
  ],
441
+ // The rate an invoiced draft's customer picks when they pay (AGL-4099).
442
+ [
443
+ 'Shipping is chosen when you pay',
444
+ '',
445
+ quote.shippingAtPayment === true
446
+ ],
429
447
  // `Tax is added at payment`, with no figure: Stripe works it out from the address.
430
448
  [
431
449
  quote.taxLabel,
@@ -460,7 +478,7 @@ function TotalRow({ label, value, strong }) {
460
478
  /*#__PURE__*/ _jsx(Typography, {
461
479
  variant: "h4",
462
480
  component: "h1",
463
- children: heading || quote.number
481
+ children: quote.kind !== 'invoice' && heading || quote.number
464
482
  }),
465
483
  /*#__PURE__*/ _jsx(Chip, {
466
484
  label: quote.statusLabel,
@@ -614,7 +632,8 @@ function TotalRow({ label, value, strong }) {
614
632
  onReload: ()=>void load().then(setState),
615
633
  onReplaced: ()=>setState({
616
634
  kind: 'replaced',
617
- storeName: quote.storeName
635
+ storeName: quote.storeName,
636
+ noun
618
637
  })
619
638
  }),
620
639
  unpaid ? /*#__PURE__*/ _jsx(Paper, {
@@ -651,7 +670,7 @@ function TotalRow({ label, value, strong }) {
651
670
  clientSecret: nativeCheckout.clientSecret,
652
671
  publishableKey: nativeCheckout.publishableKey,
653
672
  wallets: nativeCheckout.wallets,
654
- payLabel: quote.taxAtPayment ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`,
673
+ payLabel: later ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`,
655
674
  defaultShippingAddress: stripeContact(quote.shipTo),
656
675
  // An expired or unloadable session is replaced by a new press.
657
676
  onRestart: ()=>{
@@ -671,7 +690,7 @@ function TotalRow({ label, value, strong }) {
671
690
  sm: 'flex-start'
672
691
  }
673
692
  },
674
- children: paying ? 'Opening…' : quote.taxAtPayment ? `Pay ${money(quote.totals.totalCents)} plus tax` : `Pay ${money(quote.totals.totalCents)}`
693
+ children: paying ? 'Opening…' : later ? `Pay ${money(quote.totals.totalCents)} plus ${later}` : `Pay ${money(quote.totals.totalCents)}`
675
694
  }),
676
695
  payError ? /*#__PURE__*/ _jsx(Alert, {
677
696
  severity: "error",
@@ -680,7 +699,7 @@ function TotalRow({ label, value, strong }) {
680
699
  ]
681
700
  }) : /*#__PURE__*/ _jsx(Alert, {
682
701
  severity: "info",
683
- children: `Contact ${quote.storeName || 'the business'} to pay this quote.`
702
+ children: `Contact ${quote.storeName || 'the business'} to pay this ${noun}.`
684
703
  })
685
704
  })
686
705
  }) : /*#__PURE__*/ _jsx(Paper, {
@@ -699,7 +718,7 @@ function TotalRow({ label, value, strong }) {
699
718
  children: [
700
719
  /*#__PURE__*/ _jsx(Typography, {
701
720
  variant: "body1",
702
- children: quote.status === 'paid' ? quote.paidAtMs ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.` : 'Paid. Thank you.' : `This quote is ${quote.statusLabel.toLowerCase()}.`
721
+ children: quote.status === 'paid' ? quote.paidAtMs ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.` : 'Paid. Thank you.' : `This ${noun} is ${quote.statusLabel.toLowerCase()}.`
703
722
  }),
704
723
  quote.receiptUrl ? /*#__PURE__*/ _jsx(Button, {
705
724
  variant: "outlined",
@@ -712,7 +731,7 @@ function TotalRow({ label, value, strong }) {
712
731
  /*#__PURE__*/ _jsx(Typography, {
713
732
  variant: "body2",
714
733
  color: "text.secondary",
715
- children: `Questions about this quote? Contact ${quote.storeName || 'the business'}.`
734
+ children: `Questions about this ${noun}? Contact ${quote.storeName || 'the business'}.`
716
735
  })
717
736
  ]
718
737
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/quote-page-body.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport type { StripeCheckoutContact } from '@stripe/stripe-js'\nimport { forwardRef, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'\nimport {\n formatOrderMoney,\n readStorefrontCheckoutWallets,\n type QuotePageAddress,\n type QuotePageView,\n type StorefrontCheckoutWallets,\n} from '../model'\nimport type { QuotePageProps } from './quote-page'\nimport { QuoteProofPanel } from './quote-proof-panel'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\n\n/** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'replaced'; storeName: string }\n | { kind: 'ready'; view: QuotePageView }\n\n/** After a payment returns here, how often and how long the page asks whether it landed. */\nconst CONFIRM_POLL_MS = 2_000\nconst CONFIRM_POLLS = 15\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nfunction addressLines(address: QuotePageAddress): string[] {\n const cityLine = [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')]\n .filter(Boolean)\n .join(', ')\n return [address.name, address.line1, address.line2, cityLine, address.country].filter(\n (line): line is string => Boolean(line),\n )\n}\n\nfunction stripeContact(address: QuotePageAddress | null): StripeCheckoutContact | undefined {\n if (!address?.country) return undefined\n return {\n name: address.name,\n address: {\n country: address.country,\n line1: address.line1,\n line2: address.line2,\n city: address.city,\n state: address.state,\n postal_code: address.postalCode,\n },\n }\n}\n\nfunction AddressBlock({ label, lines }: { label: string; lines: string[] }) {\n return (\n <Stack spacing={0.25} sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n {lines.map((line, index) => (\n <Typography key={index} variant=\"body2\">\n {line}\n </Typography>\n ))}\n </Stack>\n )\n}\n\nfunction TotalRow({ label, value, strong }: { label: string; value: string; strong?: boolean }) {\n return (\n <Stack direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Typography variant={strong ? 'subtitle1' : 'body2'} color={strong ? 'text.primary' : 'text.secondary'}>\n {label}\n </Typography>\n <Typography variant={strong ? 'subtitle1' : 'body2'} color={strong ? 'text.primary' : 'text.secondary'}>\n {value}\n </Typography>\n </Stack>\n )\n}\n\n/**\n * The customer's quote page (AGL-4094), loaded when the page draws it (see\n * `quote-page.tsx`): what a customer sees when they open\n * the pay link a business sent them. The commerce page resolver serves it at\n * `/pay-quote` inside the site's own header and footer; a business can also\n * place it on a page of their own design at that address.\n *\n * The quote is read AFTER hydration from `?q=&t=`, so the page itself is the\n * same for every customer and may be cached, and the quote never is. Pay asks\n * the server for a fresh payment for the quote as the page shows it: Stripe's\n * own page, or the payment form here when in-page payments are on. Nothing\n * here decides a quote is paid; after paying, the page reads that from the\n * server like any other visit.\n */\nconst QuotePageBody = forwardRef<HTMLDivElement, QuotePageProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n const [paying, setPaying] = useState(false)\n const [payError, setPayError] = useState('')\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n wallets?: StorefrontCheckoutWallets\n } | null>(null)\n /** What a return from paying turned out to be: still being confirmed, or not paid. */\n const [returned, setReturned] = useState<'confirming' | 'unconfirmed' | 'failed' | null>(null)\n const link = useRef({ quoteId: '', token: '', sessionId: '' })\n\n const load = useCallback(async (): Promise<LoadState> => {\n const { quoteId, token } = link.current\n try {\n const response = await siteFetch(\n `/api/commerce/quote-view?hostId=${encodeURIComponent(hostId ?? '')}` +\n `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return { kind: 'missing', message: String(payload?.error ?? 'We could not find that quote.') }\n }\n if (payload?.state === 'replaced') return { kind: 'replaced', storeName: String(payload.storeName ?? '') }\n return { kind: 'ready', view: payload as QuotePageView }\n } catch {\n return { kind: 'missing', message: 'This quote could not be loaded. Check your connection and try again.' }\n }\n }, [hostId, siteFetch])\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n link.current = {\n quoteId: params.get('q') ?? '',\n token: params.get('t') ?? '',\n sessionId: params.get('session_id') ?? '',\n }\n if (!link.current.quoteId || !link.current.token) {\n setState({ kind: 'missing', message: 'Open this page from the link you were sent with your quote.' })\n return\n }\n let live = true\n void (async () => {\n const first = await load()\n if (!live) return\n setState(first)\n const sessionId = link.current.sessionId\n if (first.kind !== 'ready' || first.view.status !== 'unpaid' || !sessionId) return\n // Back from paying: the payment may have landed before the record of it.\n const status = await siteFetch(\n `/api/commerce/checkout-status?hostId=${encodeURIComponent(hostId)}` +\n `&sessionId=${encodeURIComponent(sessionId)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .catch(() => null)\n if (!live) return\n if (status?.status === 'open') {\n setReturned('failed')\n return\n }\n if (status?.status !== 'complete') return\n setReturned('confirming')\n for (let poll = 0; poll < CONFIRM_POLLS && live; poll++) {\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS))\n if (!live) return\n const next = await load()\n if (!live) return\n if (next.kind === 'ready' && next.view.status !== 'unpaid') {\n setState(next)\n setReturned(null)\n return\n }\n }\n if (live) setReturned('unconfirmed')\n })()\n return () => {\n live = false\n }\n }, [hostId, load, siteFetch])\n\n const view = state.kind === 'ready' ? state.view : null\n\n const pay = useCallback(async () => {\n if (!view || paying) return\n setPaying(true)\n setPayError('')\n setReturned(null)\n // One key per press: a press is one attempt, and a retry after a failure is a new one.\n const attemptKey =\n globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n try {\n const response = await siteFetch('/api/commerce/quote-pay', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Idempotency-Key': attemptKey },\n body: JSON.stringify({\n hostId,\n q: link.current.quoteId,\n t: link.current.token,\n v: view.version,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // A session with a client secret is the in-page form; checked before the\n // redirect, so a form is never navigated away from.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: readStorefrontCheckoutWallets(payload.wallets),\n })\n setPaying(false)\n return\n }\n if (response.ok && payload?.url) {\n window.location.assign(String(payload.url))\n return\n }\n if (payload?.replaced) {\n setState({ kind: 'replaced', storeName: view.storeName })\n return\n }\n if (payload?.reason === 'paid' || payload?.reason === 'updated') {\n const next = await load()\n setState(next)\n }\n setPayError(String(payload?.error ?? 'Your payment could not be set up. Try again.'))\n setPaying(false)\n } catch {\n setPayError('Your payment could not be set up. Check your connection and try again.')\n setPaying(false)\n }\n }, [view, paying, siteFetch, hostId, load])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[{ p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 }, ...nodeSx]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Quote — a customer’s quote and its Pay button render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading your quote\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || 'Your quote'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Stack>\n </Box>\n )\n }\n\n if (state.kind === 'replaced') {\n const business = state.storeName || 'The business'\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n {state.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {state.storeName}\n </Typography>\n ) : null}\n <Typography variant=\"h4\" component=\"h1\">\n {'This quote was updated'}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {`${business} updated this quote and sent you a newer link. Open their most recent message to see it.`}\n </Typography>\n </Stack>\n </Box>\n )\n }\n\n const quote = state.view\n const money = (cents: number) => formatOrderMoney(cents, quote.currency)\n // The same signed link as the page's data; the server makes the PDF from the same view.\n const pdfHref =\n `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` +\n `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`\n const unpaid = quote.status === 'unpaid'\n const addresses = [\n quote.customerName || quote.company\n ? { label: 'Prepared for', lines: [quote.customerName, quote.company].filter((line): line is string => Boolean(line)) }\n : null,\n quote.billTo ? { label: 'Bill to', lines: addressLines(quote.billTo) } : null,\n quote.shipTo ? { label: 'Ship to', lines: addressLines(quote.shipTo) } : null,\n ].filter((block): block is { label: string; lines: string[] } => Boolean(block && block.lines.length))\n const totalRows = (\n [\n ['Subtotal', money(quote.totals.itemsCents), true],\n [\n quote.discountLabel ? `Discount (${quote.discountLabel})` : 'Discount',\n `−${money(quote.totals.discountCents)}`,\n quote.totals.discountCents > 0,\n ],\n ['Shipping', money(quote.totals.shippingCents), quote.totals.shippingCents > 0],\n [quote.taxLabel, money(quote.totals.taxCents), quote.totals.taxCents > 0],\n // `Tax is added at payment`, with no figure: Stripe works it out from the address.\n [quote.taxLabel, '', quote.taxAtPayment],\n ] as Array<[string, string, boolean]>\n ).filter(([, , shown]) => shown)\n\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {quote.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {quote.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || quote.number}\n </Typography>\n <Chip\n label={quote.statusLabel}\n color={quote.status === 'paid' ? 'success' : unpaid ? 'primary' : 'default'}\n size=\"small\"\n />\n </Stack>\n {quote.dateMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Dated ${dateLabel(quote.dateMs)}`}\n </Typography>\n ) : null}\n <Box>\n <Button variant=\"outlined\" size=\"small\" href={pdfHref} download>\n {'Download PDF'}\n </Button>\n </Box>\n </Stack>\n\n {addresses.length ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 2, sm: 3 }}>\n {addresses.map((block) => (\n <AddressBlock key={block.label} label={block.label} lines={block.lines} />\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {quote.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Stack spacing={0.25} sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\">\n {line.name}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.description ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {line.description}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n line.included ? `${line.quantity} included` : `${line.quantity} × ${money(line.unitAmountCents)}`,\n line.sku ? `SKU ${line.sku}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n </Stack>\n <Typography variant=\"body2\" sx={{ flexShrink: 0 }}>\n {line.included ? 'Included' : money(line.amountCents)}\n </Typography>\n </Stack>\n ))}\n <Divider />\n {totalRows.map(([label, value]) => (\n <TotalRow key={`${label}-${value}`} label={label} value={value} />\n ))}\n <TotalRow label=\"Total\" value={money(quote.totals.totalCents)} strong />\n </Stack>\n\n {quote.notes ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Notes'}\n </Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.notes}\n </Typography>\n </Stack>\n ) : null}\n {quote.terms ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Terms'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.terms}\n </Typography>\n </Stack>\n ) : null}\n\n <QuoteProofPanel\n view={quote}\n hostId={hostId}\n quoteId={link.current.quoteId}\n token={link.current.token}\n siteFetch={siteFetch}\n onView={(next) => setState({ kind: 'ready', view: next })}\n onReload={() => void load().then(setState)}\n onReplaced={() => setState({ kind: 'replaced', storeName: quote.storeName })}\n />\n\n {unpaid ? (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={2}>\n {returned === 'confirming' ? (\n <Alert severity=\"info\" icon={<CircularProgress size={20} />}>\n {'Thank you. We’re confirming your payment.'}\n </Alert>\n ) : returned === 'unconfirmed' ? (\n <Alert severity=\"info\">\n {'Your payment is still being confirmed. Your receipt will arrive by email.'}\n </Alert>\n ) : quote.approvalRequired ? (\n <Alert severity=\"info\">\n {`${quote.storeName || 'The business'} asks you to approve the proof before you pay.`}\n </Alert>\n ) : quote.payable ? (\n <>\n {returned === 'failed' ? (\n <Alert severity=\"warning\">{'Your payment did not go through. Nothing was charged.'}</Alert>\n ) : null}\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={quote.taxAtPayment ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`}\n defaultShippingAddress={stripeContact(quote.shipTo)}\n // An expired or unloadable session is replaced by a new press.\n onRestart={() => {\n setNativeCheckout(null)\n void pay()\n }}\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : (\n <Button\n variant=\"contained\"\n size=\"large\"\n onClick={() => void pay()}\n disabled={paying}\n sx={{ alignSelf: { xs: 'stretch', sm: 'flex-start' } }}\n >\n {paying\n ? 'Opening…'\n : quote.taxAtPayment\n ? `Pay ${money(quote.totals.totalCents)} plus tax`\n : `Pay ${money(quote.totals.totalCents)}`}\n </Button>\n )}\n {payError ? <Alert severity=\"error\">{payError}</Alert> : null}\n </>\n ) : (\n <Alert severity=\"info\">\n {`Contact ${quote.storeName || 'the business'} to pay this quote.`}\n </Alert>\n )}\n </Stack>\n </Paper>\n ) : (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={1.5} sx={{ alignItems: 'flex-start' }}>\n <Typography variant=\"body1\">\n {quote.status === 'paid'\n ? quote.paidAtMs\n ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.`\n : 'Paid. Thank you.'\n : `This quote is ${quote.statusLabel.toLowerCase()}.`}\n </Typography>\n {quote.receiptUrl ? (\n <Button variant=\"outlined\" href={quote.receiptUrl}>\n {'View your order'}\n </Button>\n ) : null}\n </Stack>\n </Paper>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Questions about this quote? Contact ${quote.storeName || 'the business'}.`}\n </Typography>\n </Stack>\n </Box>\n )\n})\nQuotePageBody.displayName = 'QuotePageBody'\n\nexport default QuotePageBody\n\n"],"names":["Aglyn","Alert","Box","Button","Chip","CircularProgress","Divider","Paper","Stack","Typography","forwardRef","lazy","Suspense","useCallback","useEffect","useRef","useState","formatOrderMoney","readStorefrontCheckoutWallets","QuoteProofPanel","StorefrontPaymentElementFallback","StorefrontPaymentElement","then","module","default","CONFIRM_POLL_MS","CONFIRM_POLLS","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","addressLines","address","cityLine","city","state","postalCode","filter","Boolean","join","name","line1","line2","country","line","stripeContact","postal_code","AddressBlock","label","lines","spacing","sx","minWidth","flex","variant","color","map","index","TotalRow","value","strong","direction","justifyContent","QuotePageBody","props","ref","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","setState","kind","paying","setPaying","payError","setPayError","nativeCheckout","setNativeCheckout","returned","setReturned","link","quoteId","token","sessionId","load","current","payload","response","encodeURIComponent","json","catch","ok","message","String","error","storeName","view","params","URLSearchParams","window","location","search","get","live","first","status","poll","Promise","resolve","setTimeout","next","pay","globalThis","attemptKey","crypto","randomUUID","now","Math","random","toString","slice","method","headers","body","JSON","stringify","q","t","v","version","clientSecret","publishableKey","wallets","url","assign","replaced","reason","p","border","borderColor","borderRadius","py","textAlign","size","aria-label","component","severity","business","quote","money","cents","currency","pdfHref","unpaid","addresses","customerName","company","billTo","shipTo","block","length","totalRows","totals","itemsCents","discountLabel","discountCents","shippingCents","taxLabel","taxCents","taxAtPayment","shown","alignItems","flexWrap","rowGap","number","statusLabel","dateMs","href","download","xs","sm","variantLabel","description","whiteSpace","included","quantity","unitAmountCents","sku","flexShrink","amountCents","totalCents","notes","terms","onView","onReload","onReplaced","icon","approvalRequired","payable","fallback","payLabel","defaultShippingAddress","onRestart","onCancel","onClick","disabled","alignSelf","paidAtMs","toLowerCase","receiptUrl","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/quote-page-body.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport type { StripeCheckoutContact } from '@stripe/stripe-js'\nimport { forwardRef, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'\nimport {\n formatOrderMoney,\n readStorefrontCheckoutWallets,\n type QuotePageAddress,\n type QuotePageView,\n type StorefrontCheckoutWallets,\n} from '../model'\nimport type { QuotePageProps } from './quote-page'\nimport { QuoteProofPanel } from './quote-proof-panel'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\n\n/** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'replaced'; storeName: string; noun: string }\n | { kind: 'ready'; view: QuotePageView }\n\n/** `quote` or `invoice`, as the page says it (AGL-4099). */\nconst nounOf = (kind: unknown) => (kind === 'invoice' ? 'invoice' : 'quote')\n\n/** What is added when the customer pays: `shipping`, `tax`, `shipping and tax`, or nothing. */\nfunction addedAtPayment(view: Pick<QuotePageView, 'shippingAtPayment' | 'taxAtPayment'>): string {\n if (view.shippingAtPayment && view.taxAtPayment) return 'shipping and tax'\n if (view.shippingAtPayment) return 'shipping'\n return view.taxAtPayment ? 'tax' : ''\n}\n\n/** After a payment returns here, how often and how long the page asks whether it landed. */\nconst CONFIRM_POLL_MS = 2_000\nconst CONFIRM_POLLS = 15\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nfunction addressLines(address: QuotePageAddress): string[] {\n const cityLine = [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')]\n .filter(Boolean)\n .join(', ')\n return [address.name, address.line1, address.line2, cityLine, address.country].filter(\n (line): line is string => Boolean(line),\n )\n}\n\nfunction stripeContact(address: QuotePageAddress | null): StripeCheckoutContact | undefined {\n if (!address?.country) return undefined\n return {\n name: address.name,\n address: {\n country: address.country,\n line1: address.line1,\n line2: address.line2,\n city: address.city,\n state: address.state,\n postal_code: address.postalCode,\n },\n }\n}\n\nfunction AddressBlock({ label, lines }: { label: string; lines: string[] }) {\n return (\n <Stack spacing={0.25} sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n {lines.map((line, index) => (\n <Typography key={index} variant=\"body2\">\n {line}\n </Typography>\n ))}\n </Stack>\n )\n}\n\nfunction TotalRow({ label, value, strong }: { label: string; value: string; strong?: boolean }) {\n return (\n <Stack direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Typography variant={strong ? 'subtitle1' : 'body2'} color={strong ? 'text.primary' : 'text.secondary'}>\n {label}\n </Typography>\n <Typography variant={strong ? 'subtitle1' : 'body2'} color={strong ? 'text.primary' : 'text.secondary'}>\n {value}\n </Typography>\n </Stack>\n )\n}\n\n/**\n * The customer's quote page (AGL-4094), loaded when the page draws it (see\n * `quote-page.tsx`): what a customer sees when they open\n * the pay link a business sent them. The commerce page resolver serves it at\n * `/pay-quote` inside the site's own header and footer; a business can also\n * place it on a page of their own design at that address.\n *\n * The quote is read AFTER hydration from `?q=&t=`, so the page itself is the\n * same for every customer and may be cached, and the quote never is. Pay asks\n * the server for a fresh payment for the quote as the page shows it: Stripe's\n * own page, or the payment form here when in-page payments are on. Nothing\n * here decides a quote is paid; after paying, the page reads that from the\n * server like any other visit.\n */\nconst QuotePageBody = forwardRef<HTMLDivElement, QuotePageProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n const [paying, setPaying] = useState(false)\n const [payError, setPayError] = useState('')\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n wallets?: StorefrontCheckoutWallets\n } | null>(null)\n /** What a return from paying turned out to be: still being confirmed, or not paid. */\n const [returned, setReturned] = useState<'confirming' | 'unconfirmed' | 'failed' | null>(null)\n const link = useRef({ quoteId: '', token: '', sessionId: '' })\n\n const load = useCallback(async (): Promise<LoadState> => {\n const { quoteId, token } = link.current\n try {\n const response = await siteFetch(\n `/api/commerce/quote-view?hostId=${encodeURIComponent(hostId ?? '')}` +\n `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return { kind: 'missing', message: String(payload?.error ?? 'We could not find that quote or invoice.') }\n }\n if (payload?.state === 'replaced') {\n return { kind: 'replaced', storeName: String(payload.storeName ?? ''), noun: nounOf(payload.kind) }\n }\n return { kind: 'ready', view: payload as QuotePageView }\n } catch {\n return { kind: 'missing', message: 'This page could not be loaded. Check your connection and try again.' }\n }\n }, [hostId, siteFetch])\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n link.current = {\n quoteId: params.get('q') ?? '',\n token: params.get('t') ?? '',\n sessionId: params.get('session_id') ?? '',\n }\n if (!link.current.quoteId || !link.current.token) {\n setState({ kind: 'missing', message: 'Open this page from the link you were sent with your quote or invoice.' })\n return\n }\n let live = true\n void (async () => {\n const first = await load()\n if (!live) return\n setState(first)\n const sessionId = link.current.sessionId\n if (first.kind !== 'ready' || first.view.status !== 'unpaid' || !sessionId) return\n // Back from paying: the payment may have landed before the record of it.\n const status = await siteFetch(\n `/api/commerce/checkout-status?hostId=${encodeURIComponent(hostId)}` +\n `&sessionId=${encodeURIComponent(sessionId)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .catch(() => null)\n if (!live) return\n if (status?.status === 'open') {\n setReturned('failed')\n return\n }\n if (status?.status !== 'complete') return\n setReturned('confirming')\n for (let poll = 0; poll < CONFIRM_POLLS && live; poll++) {\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS))\n if (!live) return\n const next = await load()\n if (!live) return\n if (next.kind === 'ready' && next.view.status !== 'unpaid') {\n setState(next)\n setReturned(null)\n return\n }\n }\n if (live) setReturned('unconfirmed')\n })()\n return () => {\n live = false\n }\n }, [hostId, load, siteFetch])\n\n const view = state.kind === 'ready' ? state.view : null\n\n const pay = useCallback(async () => {\n if (!view || paying) return\n setPaying(true)\n setPayError('')\n setReturned(null)\n // One key per press: a press is one attempt, and a retry after a failure is a new one.\n const attemptKey =\n globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n try {\n const response = await siteFetch('/api/commerce/quote-pay', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Idempotency-Key': attemptKey },\n body: JSON.stringify({\n hostId,\n q: link.current.quoteId,\n t: link.current.token,\n v: view.version,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // A session with a client secret is the in-page form; checked before the\n // redirect, so a form is never navigated away from.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: readStorefrontCheckoutWallets(payload.wallets),\n })\n setPaying(false)\n return\n }\n if (response.ok && payload?.url) {\n window.location.assign(String(payload.url))\n return\n }\n if (payload?.replaced) {\n setState({ kind: 'replaced', storeName: view.storeName, noun: nounOf(view.kind) })\n return\n }\n if (payload?.reason === 'paid' || payload?.reason === 'updated') {\n const next = await load()\n setState(next)\n }\n setPayError(String(payload?.error ?? 'Your payment could not be set up. Try again.'))\n setPaying(false)\n } catch {\n setPayError('Your payment could not be set up. Check your connection and try again.')\n setPaying(false)\n }\n }, [view, paying, siteFetch, hostId, load])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[{ p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 }, ...nodeSx]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Quote — a customer’s quote and its Pay button render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || 'Your quote or invoice'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Stack>\n </Box>\n )\n }\n\n if (state.kind === 'replaced') {\n const business = state.storeName || 'The business'\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n {state.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {state.storeName}\n </Typography>\n ) : null}\n <Typography variant=\"h4\" component=\"h1\">\n {`This ${state.noun} was updated`}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {`${business} updated this ${state.noun} and sent you a newer link. Open their most recent message to see it.`}\n </Typography>\n </Stack>\n </Box>\n )\n }\n\n const quote = state.view\n const money = (cents: number) => formatOrderMoney(cents, quote.currency)\n // The same signed link as the page's data; the server makes the PDF from the same view.\n const pdfHref =\n `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` +\n `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`\n const unpaid = quote.status === 'unpaid'\n const noun = nounOf(quote.kind)\n const later = addedAtPayment(quote)\n const addresses = [\n quote.customerName || quote.company\n ? { label: 'Prepared for', lines: [quote.customerName, quote.company].filter((line): line is string => Boolean(line)) }\n : null,\n quote.billTo ? { label: 'Bill to', lines: addressLines(quote.billTo) } : null,\n quote.shipTo ? { label: 'Ship to', lines: addressLines(quote.shipTo) } : null,\n ].filter((block): block is { label: string; lines: string[] } => Boolean(block && block.lines.length))\n const totalRows = (\n [\n ['Subtotal', money(quote.totals.itemsCents), true],\n [\n quote.discountLabel ? `Discount (${quote.discountLabel})` : 'Discount',\n `−${money(quote.totals.discountCents)}`,\n quote.totals.discountCents > 0,\n ],\n ['Shipping', money(quote.totals.shippingCents), quote.totals.shippingCents > 0],\n [quote.taxLabel, money(quote.totals.taxCents), quote.totals.taxCents > 0],\n // The rate an invoiced draft's customer picks when they pay (AGL-4099).\n ['Shipping is chosen when you pay', '', quote.shippingAtPayment === true],\n // `Tax is added at payment`, with no figure: Stripe works it out from the address.\n [quote.taxLabel, '', quote.taxAtPayment],\n ] as Array<[string, string, boolean]>\n ).filter(([, , shown]) => shown)\n\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {quote.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {quote.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"h4\" component=\"h1\">\n {/* The element's own heading is a quote's; an invoice always says its number. */}\n {(quote.kind !== 'invoice' && heading) || quote.number}\n </Typography>\n <Chip\n label={quote.statusLabel}\n color={quote.status === 'paid' ? 'success' : unpaid ? 'primary' : 'default'}\n size=\"small\"\n />\n </Stack>\n {quote.dateMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Dated ${dateLabel(quote.dateMs)}`}\n </Typography>\n ) : null}\n <Box>\n <Button variant=\"outlined\" size=\"small\" href={pdfHref} download>\n {'Download PDF'}\n </Button>\n </Box>\n </Stack>\n\n {addresses.length ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 2, sm: 3 }}>\n {addresses.map((block) => (\n <AddressBlock key={block.label} label={block.label} lines={block.lines} />\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {quote.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Stack spacing={0.25} sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\">\n {line.name}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.description ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {line.description}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n line.included ? `${line.quantity} included` : `${line.quantity} × ${money(line.unitAmountCents)}`,\n line.sku ? `SKU ${line.sku}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n </Stack>\n <Typography variant=\"body2\" sx={{ flexShrink: 0 }}>\n {line.included ? 'Included' : money(line.amountCents)}\n </Typography>\n </Stack>\n ))}\n <Divider />\n {totalRows.map(([label, value]) => (\n <TotalRow key={`${label}-${value}`} label={label} value={value} />\n ))}\n <TotalRow label=\"Total\" value={money(quote.totals.totalCents)} strong />\n </Stack>\n\n {quote.notes ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Notes'}\n </Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.notes}\n </Typography>\n </Stack>\n ) : null}\n {quote.terms ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Terms'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.terms}\n </Typography>\n </Stack>\n ) : null}\n\n <QuoteProofPanel\n view={quote}\n hostId={hostId}\n quoteId={link.current.quoteId}\n token={link.current.token}\n siteFetch={siteFetch}\n onView={(next) => setState({ kind: 'ready', view: next })}\n onReload={() => void load().then(setState)}\n onReplaced={() => setState({ kind: 'replaced', storeName: quote.storeName, noun })}\n />\n\n {unpaid ? (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={2}>\n {returned === 'confirming' ? (\n <Alert severity=\"info\" icon={<CircularProgress size={20} />}>\n {'Thank you. We’re confirming your payment.'}\n </Alert>\n ) : returned === 'unconfirmed' ? (\n <Alert severity=\"info\">\n {'Your payment is still being confirmed. Your receipt will arrive by email.'}\n </Alert>\n ) : quote.approvalRequired ? (\n <Alert severity=\"info\">\n {`${quote.storeName || 'The business'} asks you to approve the proof before you pay.`}\n </Alert>\n ) : quote.payable ? (\n <>\n {returned === 'failed' ? (\n <Alert severity=\"warning\">{'Your payment did not go through. Nothing was charged.'}</Alert>\n ) : null}\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={later ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`}\n defaultShippingAddress={stripeContact(quote.shipTo)}\n // An expired or unloadable session is replaced by a new press.\n onRestart={() => {\n setNativeCheckout(null)\n void pay()\n }}\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : (\n <Button\n variant=\"contained\"\n size=\"large\"\n onClick={() => void pay()}\n disabled={paying}\n sx={{ alignSelf: { xs: 'stretch', sm: 'flex-start' } }}\n >\n {paying\n ? 'Opening…'\n : later\n ? `Pay ${money(quote.totals.totalCents)} plus ${later}`\n : `Pay ${money(quote.totals.totalCents)}`}\n </Button>\n )}\n {payError ? <Alert severity=\"error\">{payError}</Alert> : null}\n </>\n ) : (\n <Alert severity=\"info\">\n {`Contact ${quote.storeName || 'the business'} to pay this ${noun}.`}\n </Alert>\n )}\n </Stack>\n </Paper>\n ) : (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={1.5} sx={{ alignItems: 'flex-start' }}>\n <Typography variant=\"body1\">\n {quote.status === 'paid'\n ? quote.paidAtMs\n ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.`\n : 'Paid. Thank you.'\n : `This ${noun} is ${quote.statusLabel.toLowerCase()}.`}\n </Typography>\n {quote.receiptUrl ? (\n <Button variant=\"outlined\" href={quote.receiptUrl}>\n {'View your order'}\n </Button>\n ) : null}\n </Stack>\n </Paper>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Questions about this ${noun}? Contact ${quote.storeName || 'the business'}.`}\n </Typography>\n </Stack>\n </Box>\n )\n})\nQuotePageBody.displayName = 'QuotePageBody'\n\nexport default QuotePageBody\n\n"],"names":["Aglyn","Alert","Box","Button","Chip","CircularProgress","Divider","Paper","Stack","Typography","forwardRef","lazy","Suspense","useCallback","useEffect","useRef","useState","formatOrderMoney","readStorefrontCheckoutWallets","QuoteProofPanel","StorefrontPaymentElementFallback","StorefrontPaymentElement","then","module","default","nounOf","kind","addedAtPayment","view","shippingAtPayment","taxAtPayment","CONFIRM_POLL_MS","CONFIRM_POLLS","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","addressLines","address","cityLine","city","state","postalCode","filter","Boolean","join","name","line1","line2","country","line","stripeContact","postal_code","AddressBlock","label","lines","spacing","sx","minWidth","flex","variant","color","map","index","TotalRow","value","strong","direction","justifyContent","QuotePageBody","props","ref","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","setState","paying","setPaying","payError","setPayError","nativeCheckout","setNativeCheckout","returned","setReturned","link","quoteId","token","sessionId","load","current","response","encodeURIComponent","payload","json","catch","ok","message","String","error","storeName","noun","params","URLSearchParams","window","location","search","get","live","first","status","poll","Promise","resolve","setTimeout","next","pay","globalThis","attemptKey","crypto","randomUUID","now","Math","random","toString","slice","method","headers","body","JSON","stringify","q","t","v","version","clientSecret","publishableKey","wallets","url","assign","replaced","reason","p","border","borderColor","borderRadius","py","textAlign","size","aria-label","component","severity","business","quote","money","cents","currency","pdfHref","unpaid","later","addresses","customerName","company","billTo","shipTo","block","length","totalRows","totals","itemsCents","discountLabel","discountCents","shippingCents","taxLabel","taxCents","shown","alignItems","flexWrap","rowGap","number","statusLabel","dateMs","href","download","xs","sm","variantLabel","description","whiteSpace","included","quantity","unitAmountCents","sku","flexShrink","amountCents","totalCents","notes","terms","onView","onReload","onReplaced","icon","approvalRequired","payable","fallback","payLabel","defaultShippingAddress","onRestart","onCancel","onClick","disabled","alignSelf","paidAtMs","toLowerCase","receiptUrl","displayName"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,SAAS,oBAAmB;AACnC,OAAOC,YAAY,uBAAsB;AACzC,OAAOC,UAAU,qBAAoB;AACrC,OAAOC,sBAAsB,iCAAgC;AAC7D,OAAOC,aAAa,wBAAuB;AAC3C,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,gBAAgB,2BAA0B;AAEjD,SAASC,UAAU,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAC5F,SACEC,gBAAgB,EAChBC,6BAA6B,QAIxB,oBAAU;AAEjB,SAASC,eAAe,QAAQ,yBAAqB;AACrD,SAASC,gCAAgC,QAAQ,2CAAuC;AAExF,mFAAmF,GACnF,MAAMC,yCAA2BV,KAAK,IACpC,MAAM,CAAC,mCAAgCW,IAAI,CAAC,CAACC,SAAY,CAAA;YACvDC,SAASD,OAAOF,wBAAwB;QAC1C,CAAA;AASF,0DAA0D,GAC1D,MAAMI,SAAS,CAACC,OAAmBA,SAAS,YAAY,YAAY;AAEpE,6FAA6F,GAC7F,SAASC,eAAeC,IAA+D;IACrF,IAAIA,KAAKC,iBAAiB,IAAID,KAAKE,YAAY,EAAE,OAAO;IACxD,IAAIF,KAAKC,iBAAiB,EAAE,OAAO;IACnC,OAAOD,KAAKE,YAAY,GAAG,QAAQ;AACrC;AAEA,0FAA0F,GAC1F,MAAMC,kBAAkB;AACxB,MAAMC,gBAAgB;AAEtB,SAASC,UAAUC,IAAmB;IACpC,IAAI,CAACA,MAAM,OAAO;IAClB,OAAO,IAAIC,KAAKD,MAAME,kBAAkB,CAACC,WAAW;QAAEC,OAAO;QAASC,KAAK;QAAWC,MAAM;IAAU;AACxG;AAEA,SAASC,aAAaC,OAAyB;IAC7C,MAAMC,WAAW;QAACD,QAAQE,IAAI;QAAE;YAACF,QAAQG,KAAK;YAAEH,QAAQI,UAAU;SAAC,CAACC,MAAM,CAACC,SAASC,IAAI,CAAC;KAAK,CAC3FF,MAAM,CAACC,SACPC,IAAI,CAAC;IACR,OAAO;QAACP,QAAQQ,IAAI;QAAER,QAAQS,KAAK;QAAET,QAAQU,KAAK;QAAET;QAAUD,QAAQW,OAAO;KAAC,CAACN,MAAM,CACnF,CAACO,OAAyBN,QAAQM;AAEtC;AAEA,SAASC,cAAcb,OAAgC;IACrD,IAAI,EAACA,2BAAAA,QAASW,OAAO,GAAE,OAAOhB;IAC9B,OAAO;QACLa,MAAMR,QAAQQ,IAAI;QAClBR,SAAS;YACPW,SAASX,QAAQW,OAAO;YACxBF,OAAOT,QAAQS,KAAK;YACpBC,OAAOV,QAAQU,KAAK;YACpBR,MAAMF,QAAQE,IAAI;YAClBC,OAAOH,QAAQG,KAAK;YACpBW,aAAad,QAAQI,UAAU;QACjC;IACF;AACF;AAEA,SAASW,aAAa,EAAEC,KAAK,EAAEC,KAAK,EAAsC;IACxE,qBACE,MAACnD;QAAMoD,SAAS;QAAMC,IAAI;YAAEC,UAAU;YAAGC,MAAM;QAAE;;0BAC/C,KAACtD;gBAAWuD,SAAQ;gBAAWC,OAAM;0BAClCP;;YAEFC,MAAMO,GAAG,CAAC,CAACZ,MAAMa,sBAChB,KAAC1D;oBAAuBuD,SAAQ;8BAC7BV;mBADca;;;AAMzB;AAEA,SAASC,SAAS,EAAEV,KAAK,EAAEW,KAAK,EAAEC,MAAM,EAAsD;IAC5F,qBACE,MAAC9D;QAAM+D,WAAU;QAAMX,SAAS;QAAGC,IAAI;YAAEW,gBAAgB;QAAgB;;0BACvE,KAAC/D;gBAAWuD,SAASM,SAAS,cAAc;gBAASL,OAAOK,SAAS,iBAAiB;0BACnFZ;;0BAEH,KAACjD;gBAAWuD,SAASM,SAAS,cAAc;gBAASL,OAAOK,SAAS,iBAAiB;0BACnFD;;;;AAIT;AAEA;;;;;;;;;;;;;CAaC,GACD,MAAMI,8BAAgB/D,WAA2C,CAACgE,OAAOC;IACvE,MAAM,EAAEC,OAAO,EAAW,GAAGF,OAATG,wCAASH;;;IAC7B,MAAMI,SAASC,MAAMC,OAAO,CAACN,KAAK,CAAC,KAAK,IAAIA,KAAK,CAAC,KAAK,GAAG;QAACA,KAAK,CAAC,KAAK;KAAC;IACvE,MAAM,EAAEO,MAAM,EAAE,GAAGjF,MAAMkF,OAAO;IAChC,MAAMC,YAAYnF,MAAMoF,YAAY;IACpC,MAAM,CAACvC,OAAOwC,SAAS,GAAGrE,SAAoB;QAAEU,MAAM;IAAU;IAChE,MAAM,CAAC4D,QAAQC,UAAU,GAAGvE,SAAS;IACrC,MAAM,CAACwE,UAAUC,YAAY,GAAGzE,SAAS;IACzC,MAAM,CAAC0E,gBAAgBC,kBAAkB,GAAG3E,SAIlC;IACV,oFAAoF,GACpF,MAAM,CAAC4E,UAAUC,YAAY,GAAG7E,SAAyD;IACzF,MAAM8E,OAAO/E,OAAO;QAAEgF,SAAS;QAAIC,OAAO;QAAIC,WAAW;IAAG;IAE5D,MAAMC,OAAOrF,YAAY;QACvB,MAAM,EAAEkF,OAAO,EAAEC,KAAK,EAAE,GAAGF,KAAKK,OAAO;QACvC,IAAI;YACF,MAAMC,WAAW,MAAMjB,UACrB,CAAC,gCAAgC,EAAEkB,mBAAmBpB,iBAAAA,SAAU,KAAK,GACnE,CAAC,GAAG,EAAEoB,mBAAmBN,SAAS,GAAG,EAAEM,mBAAmBL,QAAQ;YAEtE,MAAMM,UAAU,MAAMF,SAASG,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACpD,IAAI,CAACJ,SAASK,EAAE,EAAE;;gBAChB,OAAO;oBAAE/E,MAAM;oBAAWgF,SAASC,eAAOL,2BAAAA,QAASM,KAAK,mBAAI;gBAA4C;YAC1G;YACA,IAAIN,CAAAA,2BAAAA,QAASzD,KAAK,MAAK,YAAY;oBACYyD;gBAA7C,OAAO;oBAAE5E,MAAM;oBAAYmF,WAAWF,QAAOL,qBAAAA,QAAQO,SAAS,YAAjBP,qBAAqB;oBAAKQ,MAAMrF,OAAO6E,QAAQ5E,IAAI;gBAAE;YACpG;YACA,OAAO;gBAAEA,MAAM;gBAASE,MAAM0E;YAAyB;QACzD,EAAE,eAAM;YACN,OAAO;gBAAE5E,MAAM;gBAAWgF,SAAS;YAAsE;QAC3G;IACF,GAAG;QAACzB;QAAQE;KAAU;IAEtBrE,UAAU;YAIGiG,aACFA,cACIA;QALb,IAAI,CAAC9B,QAAQ;QACb,MAAM8B,SAAS,IAAIC,gBAAgBC,OAAOC,QAAQ,CAACC,MAAM;QACzDrB,KAAKK,OAAO,GAAG;YACbJ,OAAO,GAAEgB,cAAAA,OAAOK,GAAG,CAAC,gBAAXL,cAAmB;YAC5Bf,KAAK,GAAEe,eAAAA,OAAOK,GAAG,CAAC,gBAAXL,eAAmB;YAC1Bd,SAAS,GAAEc,eAAAA,OAAOK,GAAG,CAAC,yBAAXL,eAA4B;QACzC;QACA,IAAI,CAACjB,KAAKK,OAAO,CAACJ,OAAO,IAAI,CAACD,KAAKK,OAAO,CAACH,KAAK,EAAE;YAChDX,SAAS;gBAAE3D,MAAM;gBAAWgF,SAAS;YAAyE;YAC9G;QACF;QACA,IAAIW,OAAO;QACX,KAAK,AAAC,CAAA;YACJ,MAAMC,QAAQ,MAAMpB;YACpB,IAAI,CAACmB,MAAM;YACXhC,SAASiC;YACT,MAAMrB,YAAYH,KAAKK,OAAO,CAACF,SAAS;YACxC,IAAIqB,MAAM5F,IAAI,KAAK,WAAW4F,MAAM1F,IAAI,CAAC2F,MAAM,KAAK,YAAY,CAACtB,WAAW;YAC5E,yEAAyE;YACzE,MAAMsB,SAAS,MAAMpC,UACnB,CAAC,qCAAqC,EAAEkB,mBAAmBpB,SAAS,GAClE,CAAC,WAAW,EAAEoB,mBAAmBJ,YAAY,EAE9C3E,IAAI,CAAC,CAAC8E,WAAcA,SAASK,EAAE,GAAGL,SAASG,IAAI,KAAK,MACpDC,KAAK,CAAC,IAAM;YACf,IAAI,CAACa,MAAM;YACX,IAAIE,CAAAA,0BAAAA,OAAQA,MAAM,MAAK,QAAQ;gBAC7B1B,YAAY;gBACZ;YACF;YACA,IAAI0B,CAAAA,0BAAAA,OAAQA,MAAM,MAAK,YAAY;YACnC1B,YAAY;YACZ,IAAK,IAAI2B,OAAO,GAAGA,OAAOxF,iBAAiBqF,MAAMG,OAAQ;gBACvD,MAAM,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAAS3F;gBACnD,IAAI,CAACsF,MAAM;gBACX,MAAMO,OAAO,MAAM1B;gBACnB,IAAI,CAACmB,MAAM;gBACX,IAAIO,KAAKlG,IAAI,KAAK,WAAWkG,KAAKhG,IAAI,CAAC2F,MAAM,KAAK,UAAU;oBAC1DlC,SAASuC;oBACT/B,YAAY;oBACZ;gBACF;YACF;YACA,IAAIwB,MAAMxB,YAAY;QACxB,CAAA;QACA,OAAO;YACLwB,OAAO;QACT;IACF,GAAG;QAACpC;QAAQiB;QAAMf;KAAU;IAE5B,MAAMvD,OAAOiB,MAAMnB,IAAI,KAAK,UAAUmB,MAAMjB,IAAI,GAAG;IAEnD,MAAMiG,MAAMhH,YAAY;;YAOpBiH,+BAAAA;QANF,IAAI,CAAClG,QAAQ0D,QAAQ;QACrBC,UAAU;QACVE,YAAY;QACZI,YAAY;QACZ,uFAAuF;QACvF,MAAMkC,sBACJD,qBAAAA,WAAWE,MAAM,sBAAjBF,gCAAAA,mBAAmBG,UAAU,qBAA7BH,mCAAAA,sCAAqC,GAAG3F,KAAK+F,GAAG,GAAG,CAAC,EAAEC,KAAKC,MAAM,GAAGC,QAAQ,CAAC,IAAIC,KAAK,CAAC,IAAI;QAC7F,IAAI;;YACF,MAAMlC,WAAW,MAAMjB,UAAU,2BAA2B;gBAC1DoD,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;oBAAoB,mBAAmBT;gBAAW;gBAC7EU,MAAMC,KAAKC,SAAS,CAAC;oBACnB1D;oBACA2D,GAAG9C,KAAKK,OAAO,CAACJ,OAAO;oBACvB8C,GAAG/C,KAAKK,OAAO,CAACH,KAAK;oBACrB8C,GAAGlH,KAAKmH,OAAO;gBACjB;YACF;YACA,MAAMzC,UAAU,MAAMF,SAASG,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACpD,yEAAyE;YACzE,oDAAoD;YACpD,IAAIJ,SAASK,EAAE,KAAIH,2BAAAA,QAAS0C,YAAY,MAAI1C,2BAAAA,QAAS2C,cAAc,GAAE;gBACnEtD,kBAAkB;oBAChBqD,cAAcrC,OAAOL,QAAQ0C,YAAY;oBACzCC,gBAAgBtC,OAAOL,QAAQ2C,cAAc;oBAC7CC,SAAShI,8BAA8BoF,QAAQ4C,OAAO;gBACxD;gBACA3D,UAAU;gBACV;YACF;YACA,IAAIa,SAASK,EAAE,KAAIH,2BAAAA,QAAS6C,GAAG,GAAE;gBAC/BlC,OAAOC,QAAQ,CAACkC,MAAM,CAACzC,OAAOL,QAAQ6C,GAAG;gBACzC;YACF;YACA,IAAI7C,2BAAAA,QAAS+C,QAAQ,EAAE;gBACrBhE,SAAS;oBAAE3D,MAAM;oBAAYmF,WAAWjF,KAAKiF,SAAS;oBAAEC,MAAMrF,OAAOG,KAAKF,IAAI;gBAAE;gBAChF;YACF;YACA,IAAI4E,CAAAA,2BAAAA,QAASgD,MAAM,MAAK,UAAUhD,CAAAA,2BAAAA,QAASgD,MAAM,MAAK,WAAW;gBAC/D,MAAM1B,OAAO,MAAM1B;gBACnBb,SAASuC;YACX;YACAnC,YAAYkB,gBAAOL,2BAAAA,QAASM,KAAK,oBAAI;YACrCrB,UAAU;QACZ,EAAE,eAAM;YACNE,YAAY;YACZF,UAAU;QACZ;IACF,GAAG;QAAC3D;QAAM0D;QAAQH;QAAWF;QAAQiB;KAAK;IAE1C,IAAI,CAACjB,QAAQ;QACX,qBACE,KAAC/E;YACCyE,KAAKA;WACDE;YACJhB,IAAI;gBAAC;oBAAE0F,GAAG;oBAAGC,QAAQ;oBAAcC,aAAa;oBAAWC,cAAc;gBAAE;mBAAM5E;aAAO;sBAExF,cAAA,KAACrE;gBAAWuD,SAAQ;gBAAQC,OAAM;0BAC/B;;;IAIT;IAEA,IAAIpB,MAAMnB,IAAI,KAAK,WAAW;QAC5B,qBACE,KAACxB;YAAIyE,KAAKA;WAASE;YAAMhB,IAAI;gBAAC;oBAAE8F,IAAI;oBAAGC,WAAW;gBAAS;mBAAM9E;aAAO;sBACtE,cAAA,KAACzE;gBAAiBwJ,MAAM;gBAAIC,cAAW;;;IAG7C;IAEA,IAAIjH,MAAMnB,IAAI,KAAK,WAAW;QAC5B,qBACE,KAACxB;YAAIyE,KAAKA;WAASE;YAAMhB,IAAIiB;sBAC3B,cAAA,MAACtE;gBAAMoD,SAAS;;kCACd,KAACnD;wBAAWuD,SAAQ;wBAAK+F,WAAU;kCAChCnF,WAAW;;kCAEd,KAAC3E;wBAAM+J,UAAS;kCAAQnH,MAAM6D,OAAO;;;;;IAI7C;IAEA,IAAI7D,MAAMnB,IAAI,KAAK,YAAY;QAC7B,MAAMuI,WAAWpH,MAAMgE,SAAS,IAAI;QACpC,qBACE,KAAC3G;YAAIyE,KAAKA;WAASE;YAAMhB,IAAIiB;sBAC3B,cAAA,MAACtE;gBAAMoD,SAAS;;oBACbf,MAAMgE,SAAS,iBACd,KAACpG;wBAAWuD,SAAQ;wBAAWC,OAAM;kCAClCpB,MAAMgE,SAAS;yBAEhB;kCACJ,KAACpG;wBAAWuD,SAAQ;wBAAK+F,WAAU;kCAChC,CAAC,KAAK,EAAElH,MAAMiE,IAAI,CAAC,YAAY,CAAC;;kCAEnC,KAACrG;wBAAWuD,SAAQ;wBAAQC,OAAM;kCAC/B,GAAGgG,SAAS,cAAc,EAAEpH,MAAMiE,IAAI,CAAC,qEAAqE,CAAC;;;;;IAKxH;IAEA,MAAMoD,QAAQrH,MAAMjB,IAAI;IACxB,MAAMuI,QAAQ,CAACC,QAAkBnJ,iBAAiBmJ,OAAOF,MAAMG,QAAQ;IACvE,wFAAwF;IACxF,MAAMC,UACJ,CAAC,+BAA+B,EAAEjE,mBAAmBpB,SAAS,GAC9D,CAAC,GAAG,EAAEoB,mBAAmBP,KAAKK,OAAO,CAACJ,OAAO,EAAE,GAAG,EAAEM,mBAAmBP,KAAKK,OAAO,CAACH,KAAK,GAAG;IAC9F,MAAMuE,SAASL,MAAM3C,MAAM,KAAK;IAChC,MAAMT,OAAOrF,OAAOyI,MAAMxI,IAAI;IAC9B,MAAM8I,QAAQ7I,eAAeuI;IAC7B,MAAMO,YAAY;QAChBP,MAAMQ,YAAY,IAAIR,MAAMS,OAAO,GAC/B;YAAEjH,OAAO;YAAgBC,OAAO;gBAACuG,MAAMQ,YAAY;gBAAER,MAAMS,OAAO;aAAC,CAAC5H,MAAM,CAAC,CAACO,OAAyBN,QAAQM;QAAO,IACpH;QACJ4G,MAAMU,MAAM,GAAG;YAAElH,OAAO;YAAWC,OAAOlB,aAAayH,MAAMU,MAAM;QAAE,IAAI;QACzEV,MAAMW,MAAM,GAAG;YAAEnH,OAAO;YAAWC,OAAOlB,aAAayH,MAAMW,MAAM;QAAE,IAAI;KAC1E,CAAC9H,MAAM,CAAC,CAAC+H,QAAuD9H,QAAQ8H,SAASA,MAAMnH,KAAK,CAACoH,MAAM;IACpG,MAAMC,YAAY,AAChB;QACE;YAAC;YAAYb,MAAMD,MAAMe,MAAM,CAACC,UAAU;YAAG;SAAK;QAClD;YACEhB,MAAMiB,aAAa,GAAG,CAAC,UAAU,EAAEjB,MAAMiB,aAAa,CAAC,CAAC,CAAC,GAAG;YAC5D,CAAC,CAAC,EAAEhB,MAAMD,MAAMe,MAAM,CAACG,aAAa,GAAG;YACvClB,MAAMe,MAAM,CAACG,aAAa,GAAG;SAC9B;QACD;YAAC;YAAYjB,MAAMD,MAAMe,MAAM,CAACI,aAAa;YAAGnB,MAAMe,MAAM,CAACI,aAAa,GAAG;SAAE;QAC/E;YAACnB,MAAMoB,QAAQ;YAAEnB,MAAMD,MAAMe,MAAM,CAACM,QAAQ;YAAGrB,MAAMe,MAAM,CAACM,QAAQ,GAAG;SAAE;QACzE,wEAAwE;QACxE;YAAC;YAAmC;YAAIrB,MAAMrI,iBAAiB,KAAK;SAAK;QACzE,mFAAmF;QACnF;YAACqI,MAAMoB,QAAQ;YAAE;YAAIpB,MAAMpI,YAAY;SAAC;KACzC,CACDiB,MAAM,CAAC,CAAC,KAAKyI,MAAM,GAAKA;IAE1B,qBACE,KAACtL;QAAIyE,KAAKA;OAASE;QAAMhB,IAAIiB;kBAC3B,cAAA,MAACtE;YAAMoD,SAAS;;8BACd,MAACpD;oBAAMoD,SAAS;;wBACbsG,MAAMrD,SAAS,iBACd,KAACpG;4BAAWuD,SAAQ;4BAAWC,OAAM;sCAClCiG,MAAMrD,SAAS;6BAEhB;sCACJ,MAACrG;4BAAM+D,WAAU;4BAAMX,SAAS;4BAAKC,IAAI;gCAAE4H,YAAY;gCAAUC,UAAU;gCAAQC,QAAQ;4BAAE;;8CAC3F,KAAClL;oCAAWuD,SAAQ;oCAAK+F,WAAU;8CAEhC,AAACG,MAAMxI,IAAI,KAAK,aAAakD,WAAYsF,MAAM0B,MAAM;;8CAExD,KAACxL;oCACCsD,OAAOwG,MAAM2B,WAAW;oCACxB5H,OAAOiG,MAAM3C,MAAM,KAAK,SAAS,YAAYgD,SAAS,YAAY;oCAClEV,MAAK;;;;wBAGRK,MAAM4B,MAAM,iBACX,KAACrL;4BAAWuD,SAAQ;4BAAQC,OAAM;sCAC/B,CAAC,MAAM,EAAEhC,UAAUiI,MAAM4B,MAAM,GAAG;6BAEnC;sCACJ,KAAC5L;sCACC,cAAA,KAACC;gCAAO6D,SAAQ;gCAAW6F,MAAK;gCAAQkC,MAAMzB;gCAAS0B,QAAQ;0CAC5D;;;;;gBAKNvB,UAAUM,MAAM,iBACf,KAACvK;oBAAM+D,WAAW;wBAAE0H,IAAI;wBAAUC,IAAI;oBAAM;oBAAGtI,SAAS;wBAAEqI,IAAI;wBAAGC,IAAI;oBAAE;8BACpEzB,UAAUvG,GAAG,CAAC,CAAC4G,sBACd,KAACrH;4BAA+BC,OAAOoH,MAAMpH,KAAK;4BAAEC,OAAOmH,MAAMnH,KAAK;2BAAnDmH,MAAMpH,KAAK;qBAGhC;8BAEJ,MAAClD;oBAAMoD,SAAS;;sCACd,KAACnD;4BAAWuD,SAAQ;4BAAK+F,WAAU;sCAChC;;wBAEFG,MAAMvG,KAAK,CAACO,GAAG,CAAC,CAACZ,MAAMa,sBACtB,MAAC3D;gCAAkB+D,WAAU;gCAAMX,SAAS;gCAAGC,IAAI;oCAAEW,gBAAgB;gCAAgB;;kDACnF,MAAChE;wCAAMoD,SAAS;wCAAMC,IAAI;4CAAEC,UAAU;wCAAE;;0DACtC,MAACrD;gDAAWuD,SAAQ;;oDACjBV,KAAKJ,IAAI;oDACTI,KAAK6I,YAAY,GAAG,CAAC,EAAE,EAAE7I,KAAK6I,YAAY,CAAC,CAAC,CAAC,GAAG;;;4CAElD7I,KAAK8I,WAAW,iBACf,KAAC3L;gDAAWuD,SAAQ;gDAAQC,OAAM;gDAAiBJ,IAAI;oDAAEwI,YAAY;gDAAW;0DAC7E/I,KAAK8I,WAAW;iDAEjB;0DACJ,KAAC3L;gDAAWuD,SAAQ;gDAAUC,OAAM;0DACjC;oDACCX,KAAKgJ,QAAQ,GAAG,GAAGhJ,KAAKiJ,QAAQ,CAAC,SAAS,CAAC,GAAG,GAAGjJ,KAAKiJ,QAAQ,CAAC,GAAG,EAAEpC,MAAM7G,KAAKkJ,eAAe,GAAG;oDACjGlJ,KAAKmJ,GAAG,GAAG,CAAC,IAAI,EAAEnJ,KAAKmJ,GAAG,EAAE,GAAG;iDAChC,CACE1J,MAAM,CAACC,SACPC,IAAI,CAAC;;;;kDAGZ,KAACxC;wCAAWuD,SAAQ;wCAAQH,IAAI;4CAAE6I,YAAY;wCAAE;kDAC7CpJ,KAAKgJ,QAAQ,GAAG,aAAanC,MAAM7G,KAAKqJ,WAAW;;;+BArB5CxI;sCAyBd,KAAC7D;wBACA0K,UAAU9G,GAAG,CAAC,CAAC,CAACR,OAAOW,MAAM,iBAC5B,KAACD;gCAAmCV,OAAOA;gCAAOW,OAAOA;+BAA1C,GAAGX,MAAM,CAAC,EAAEW,OAAO;sCAEpC,KAACD;4BAASV,OAAM;4BAAQW,OAAO8F,MAAMD,MAAMe,MAAM,CAAC2B,UAAU;4BAAGtI,MAAM;;;;gBAGtE4F,MAAM2C,KAAK,iBACV,MAACrM;oBAAMoD,SAAS;;sCACd,KAACnD;4BAAWuD,SAAQ;4BAAK+F,WAAU;sCAChC;;sCAEH,KAACtJ;4BAAWuD,SAAQ;4BAAQH,IAAI;gCAAEwI,YAAY;4BAAW;sCACtDnC,MAAM2C,KAAK;;;qBAGd;gBACH3C,MAAM4C,KAAK,iBACV,MAACtM;oBAAMoD,SAAS;;sCACd,KAACnD;4BAAWuD,SAAQ;4BAAK+F,WAAU;sCAChC;;sCAEH,KAACtJ;4BAAWuD,SAAQ;4BAAQC,OAAM;4BAAiBJ,IAAI;gCAAEwI,YAAY;4BAAW;sCAC7EnC,MAAM4C,KAAK;;;qBAGd;8BAEJ,KAAC3L;oBACCS,MAAMsI;oBACNjF,QAAQA;oBACRc,SAASD,KAAKK,OAAO,CAACJ,OAAO;oBAC7BC,OAAOF,KAAKK,OAAO,CAACH,KAAK;oBACzBb,WAAWA;oBACX4H,QAAQ,CAACnF,OAASvC,SAAS;4BAAE3D,MAAM;4BAASE,MAAMgG;wBAAK;oBACvDoF,UAAU,IAAM,KAAK9G,OAAO5E,IAAI,CAAC+D;oBACjC4H,YAAY,IAAM5H,SAAS;4BAAE3D,MAAM;4BAAYmF,WAAWqD,MAAMrD,SAAS;4BAAEC;wBAAK;;gBAGjFyD,uBACC,KAAChK;oBAAMyD,SAAQ;oBAAWH,IAAI;wBAAE0F,GAAG;4BAAE0C,IAAI;4BAAGC,IAAI;wBAAE;oBAAE;8BAClD,cAAA,KAAC1L;wBAAMoD,SAAS;kCACbgC,aAAa,6BACZ,KAAC3F;4BAAM+J,UAAS;4BAAOkD,oBAAM,KAAC7M;gCAAiBwJ,MAAM;;sCAClD;6BAEDjE,aAAa,8BACf,KAAC3F;4BAAM+J,UAAS;sCACb;6BAEDE,MAAMiD,gBAAgB,iBACxB,KAAClN;4BAAM+J,UAAS;sCACb,GAAGE,MAAMrD,SAAS,IAAI,eAAe,8CAA8C,CAAC;6BAErFqD,MAAMkD,OAAO,iBACf;;gCACGxH,aAAa,yBACZ,KAAC3F;oCAAM+J,UAAS;8CAAW;qCACzB;gCACHtE,+BACC,KAAC9E;oCAASyM,wBAAU,KAACjM;8CACnB,cAAA,KAACC;wCACC2H,cAActD,eAAesD,YAAY;wCACzCC,gBAAgBvD,eAAeuD,cAAc;wCAC7CC,SAASxD,eAAewD,OAAO;wCAC/BoE,UAAU9C,QAAQ,YAAY,CAAC,IAAI,EAAEL,MAAMD,MAAMe,MAAM,CAAC2B,UAAU,GAAG;wCACrEW,wBAAwBhK,cAAc2G,MAAMW,MAAM;wCAClD,+DAA+D;wCAC/D2C,WAAW;4CACT7H,kBAAkB;4CAClB,KAAKkC;wCACP;wCACA4F,UAAU,IAAM9H,kBAAkB;;mDAItC,KAACxF;oCACC6D,SAAQ;oCACR6F,MAAK;oCACL6D,SAAS,IAAM,KAAK7F;oCACpB8F,UAAUrI;oCACVzB,IAAI;wCAAE+J,WAAW;4CAAE3B,IAAI;4CAAWC,IAAI;wCAAa;oCAAE;8CAEpD5G,SACG,aACAkF,QACE,CAAC,IAAI,EAAEL,MAAMD,MAAMe,MAAM,CAAC2B,UAAU,EAAE,MAAM,EAAEpC,OAAO,GACrD,CAAC,IAAI,EAAEL,MAAMD,MAAMe,MAAM,CAAC2B,UAAU,GAAG;;gCAGhDpH,yBAAW,KAACvF;oCAAM+J,UAAS;8CAASxE;qCAAoB;;2CAG3D,KAACvF;4BAAM+J,UAAS;sCACb,CAAC,QAAQ,EAAEE,MAAMrD,SAAS,IAAI,eAAe,aAAa,EAAEC,KAAK,CAAC,CAAC;;;mCAM5E,KAACvG;oBAAMyD,SAAQ;oBAAWH,IAAI;wBAAE0F,GAAG;4BAAE0C,IAAI;4BAAGC,IAAI;wBAAE;oBAAE;8BAClD,cAAA,MAAC1L;wBAAMoD,SAAS;wBAAKC,IAAI;4BAAE4H,YAAY;wBAAa;;0CAClD,KAAChL;gCAAWuD,SAAQ;0CACjBkG,MAAM3C,MAAM,KAAK,SACd2C,MAAM2D,QAAQ,GACZ,CAAC,KAAK,EAAE5L,UAAUiI,MAAM2D,QAAQ,EAAE,YAAY,CAAC,GAC/C,qBACF,CAAC,KAAK,EAAE/G,KAAK,IAAI,EAAEoD,MAAM2B,WAAW,CAACiC,WAAW,GAAG,CAAC,CAAC;;4BAE1D5D,MAAM6D,UAAU,iBACf,KAAC5N;gCAAO6D,SAAQ;gCAAW+H,MAAM7B,MAAM6D,UAAU;0CAC9C;iCAED;;;;8BAKV,KAACtN;oBAAWuD,SAAQ;oBAAQC,OAAM;8BAC/B,CAAC,qBAAqB,EAAE6C,KAAK,UAAU,EAAEoD,MAAMrD,SAAS,IAAI,eAAe,CAAC,CAAC;;;;;AAKxF;AACApC,cAAcuJ,WAAW,GAAG;AAE5B,eAAevJ,cAAa"}
@@ -21,6 +21,7 @@
21
21
  * product docs at read/checkout time, so a stale cart can never charge
22
22
  * a stale price. Pure helpers; the cart API owns I/O.
23
23
  */
24
+ import { type ModifierSelection } from './product-modifiers';
24
25
  export interface CartLine {
25
26
  productId: string;
26
27
  /** Absent = the product's default variant. */
@@ -32,6 +33,13 @@ export interface CartLine {
32
33
  * different days of one pass are two lines.
33
34
  */
34
35
  useDayKey?: string;
36
+ /**
37
+ * The add-ons the shopper chose on the product's page (AGL-4100), ids
38
+ * only, in the product's group order: priced from the product on every
39
+ * read and at checkout, never stored with a price. Absent: none. The same
40
+ * product with different choices is a different line.
41
+ */
42
+ modifiers?: ModifierSelection[];
35
43
  }
36
44
  /** `hosts/{hostId}/carts/{cartId}` doc. */
37
45
  export interface HostCart {
@@ -43,14 +51,18 @@ export interface HostCart {
43
51
  }
44
52
  export declare const CART_MAX_LINES = 50;
45
53
  export declare const CART_MAX_QUANTITY = 99;
46
- /** One cart line's identity: product, variant and use day. */
47
- export declare function cartLineKey(line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey'>): string;
54
+ /**
55
+ * One cart line's identity: product, variant, use day and add-ons
56
+ * (AGL-4100). A line with no add-ons keeps the key it always had, so a cart
57
+ * stored before add-ons were sold online reads, merges and removes as it did.
58
+ */
59
+ export declare function cartLineKey(line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey' | 'modifiers'>): string;
48
60
  /**
49
61
  * Adds/merges a line (quantities accumulate), clamped to per-line and
50
62
  * line-count caps. Quantity ≤ 0 removes the line.
51
63
  */
52
64
  export declare function upsertCartLine(cart: Pick<HostCart, 'lines'>, line: CartLine, mode?: 'add' | 'set'): CartLine[];
53
- export declare function removeCartLine(cart: Pick<HostCart, 'lines'>, line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey'>): CartLine[];
65
+ export declare function removeCartLine(cart: Pick<HostCart, 'lines'>, line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey' | 'modifiers'>): CartLine[];
54
66
  /** Total units across lines (the mini-cart badge). */
55
67
  export declare function cartCount(cart: Pick<HostCart, 'lines'> | undefined): number;
56
68
  /**
@@ -1,3 +1,4 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
1
2
  /**
2
3
  * @license
3
4
  * Copyright 2026 Aglyn LLC
@@ -19,12 +20,18 @@
19
20
  * store only ids + quantity — display data and prices resolve from the
20
21
  * product docs at read/checkout time, so a stale cart can never charge
21
22
  * a stale price. Pure helpers; the cart API owns I/O.
22
- */ import { _ as _extends } from "@swc/helpers/_/_extends";
23
+ */ import { modifierSelectionKey } from "./product-modifiers.js";
23
24
  export const CART_MAX_LINES = 50;
24
25
  export const CART_MAX_QUANTITY = 99;
25
- /** One cart line's identity: product, variant and use day. */ export function cartLineKey(line) {
26
+ /**
27
+ * One cart line's identity: product, variant, use day and add-ons
28
+ * (AGL-4100). A line with no add-ons keeps the key it always had, so a cart
29
+ * stored before add-ons were sold online reads, merges and removes as it did.
30
+ */ export function cartLineKey(line) {
26
31
  var _line_variantId, _line_useDayKey;
27
- return `${line.productId}:${(_line_variantId = line.variantId) != null ? _line_variantId : ''}:${(_line_useDayKey = line.useDayKey) != null ? _line_useDayKey : ''}`;
32
+ const base = `${line.productId}:${(_line_variantId = line.variantId) != null ? _line_variantId : ''}:${(_line_useDayKey = line.useDayKey) != null ? _line_useDayKey : ''}`;
33
+ const choices = modifierSelectionKey(line.modifiers);
34
+ return choices ? `${base}:${choices}` : base;
28
35
  }
29
36
  const lineKey = cartLineKey;
30
37
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-cart.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Cart v1 (AGL-293): a server-backed cart doc at\n * `hosts/{hostId}/carts/{cartId}`, keyed by an httpOnly cookie. Lines\n * store only ids + quantity — display data and prices resolve from the\n * product docs at read/checkout time, so a stale cart can never charge\n * a stale price. Pure helpers; the cart API owns I/O.\n */\n\nexport interface CartLine {\n productId: string\n /** Absent = the product's default variant. */\n variantId?: string\n quantity: number\n /**\n * The day the shopper chose to use a check-in item (AGL-4043),\n * `YYYY-MM-DD` on the store's calendar. Absent: the day they buy. Two\n * different days of one pass are two lines.\n */\n useDayKey?: string\n}\n\n/** `hosts/{hostId}/carts/{cartId}` doc. */\nexport interface HostCart {\n lines: CartLine[]\n /** Storefront customer once signed in (AGL-294 merge). */\n customerId?: string\n updatedAtMs?: number\n createdAtMs?: number\n}\n\nexport const CART_MAX_LINES = 50\nexport const CART_MAX_QUANTITY = 99\n\n/** One cart line's identity: product, variant and use day. */\nexport function cartLineKey(line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey'>): string {\n return `${line.productId}:${line.variantId ?? ''}:${line.useDayKey ?? ''}`\n}\n\nconst lineKey = cartLineKey\n\n/**\n * A line quantity, coerced to a whole finite number (AGL-2285).\n *\n * `Math.round(line.quantity)` was the whole sanitiser, and `Math.round(NaN)` is\n * `NaN` — which then walked past the guard below, because `NaN <= 0` is\n * `false`. A cart line with `quantity: NaN` (a legal Firestore double) was\n * stored, and from there `cartCount` reported `NaN` in the mini-cart badge and\n * `cart-checkout.ts` computed `itemsCents`, the platform fee and the Stripe\n * `line_items[n][quantity]` as `NaN` too — so Stripe 400s and the shopper\n * cannot check out AT ALL until they find the poisoned line and remove it.\n *\n * Answering 0 is what makes the existing `<= 0` guard do its job: an\n * unusable quantity removes the line (or refuses to add one) rather than\n * writing a value nothing downstream can compare against. The same lesson as\n * AGL-2229 one collection over — `Math.max`/`Math.min`/`Math.round` propagate\n * `NaN`, they do not discard it.\n */\nfunction wholeQuantity(value: unknown): number {\n const quantity = Math.round(Number(value ?? 0))\n return Number.isFinite(quantity) ? quantity : 0\n}\n\n/**\n * Adds/merges a line (quantities accumulate), clamped to per-line and\n * line-count caps. Quantity ≤ 0 removes the line.\n */\nexport function upsertCartLine(\n cart: Pick<HostCart, 'lines'>,\n line: CartLine,\n mode: 'add' | 'set' = 'add',\n): CartLine[] {\n const quantity = wholeQuantity(line.quantity)\n const key = lineKey(line)\n const existing = cart.lines.find((item) => lineKey(item) === key)\n if (!existing) {\n if (quantity <= 0) return cart.lines\n if (cart.lines.length >= CART_MAX_LINES) return cart.lines\n return [\n ...cart.lines,\n { ...line, quantity: Math.min(CART_MAX_QUANTITY, quantity) },\n ]\n }\n // The STORED side is coerced too (AGL-2285): a line written before this\n // guard, or by any other writer, can still hold a non-finite quantity, and\n // adding to it would carry that forward forever.\n const nextQuantity =\n mode === 'add' ? wholeQuantity(existing.quantity) + quantity : quantity\n if (nextQuantity <= 0) {\n return cart.lines.filter((item) => lineKey(item) !== key)\n }\n return cart.lines.map((item) =>\n lineKey(item) === key\n ? { ...item, quantity: Math.min(CART_MAX_QUANTITY, nextQuantity) }\n : item,\n )\n}\n\nexport function removeCartLine(\n cart: Pick<HostCart, 'lines'>,\n line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey'>,\n): CartLine[] {\n const key = lineKey(line)\n return cart.lines.filter((item) => lineKey(item) !== key)\n}\n\n/** Total units across lines (the mini-cart badge). */\nexport function cartCount(cart: Pick<HostCart, 'lines'> | undefined): number {\n // Coerced per line (AGL-2285) so one stored `NaN` cannot make the badge read\n // `NaN` for a cart that otherwise has real items in it.\n return (cart?.lines ?? []).reduce(\n (sum, line) => sum + wholeQuantity(line?.quantity),\n 0,\n )\n}\n\n/**\n * Merges a guest cart into a customer cart on sign-in (AGL-294):\n * quantities accumulate per line, capped as usual.\n */\nexport function mergeCarts(\n customerCart: Pick<HostCart, 'lines'>,\n guestCart: Pick<HostCart, 'lines'>,\n): CartLine[] {\n let lines = [...customerCart.lines]\n for (const line of guestCart.lines) {\n lines = upsertCartLine({ lines }, line, 'add')\n }\n return lines\n}\n"],"names":["CART_MAX_LINES","CART_MAX_QUANTITY","cartLineKey","line","productId","variantId","useDayKey","lineKey","wholeQuantity","value","quantity","Math","round","Number","isFinite","upsertCartLine","cart","mode","key","existing","lines","find","item","length","min","nextQuantity","filter","map","removeCartLine","cartCount","reduce","sum","mergeCarts","customerCart","guestCart"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC;AAwBD,OAAO,MAAMA,iBAAiB,GAAE;AAChC,OAAO,MAAMC,oBAAoB,GAAE;AAEnC,4DAA4D,GAC5D,OAAO,SAASC,YAAYC,IAA6D;QAC3DA,iBAAwBA;IAApD,OAAO,GAAGA,KAAKC,SAAS,CAAC,CAAC,GAAED,kBAAAA,KAAKE,SAAS,YAAdF,kBAAkB,GAAG,CAAC,GAAEA,kBAAAA,KAAKG,SAAS,YAAdH,kBAAkB,IAAI;AAC5E;AAEA,MAAMI,UAAUL;AAEhB;;;;;;;;;;;;;;;;CAgBC,GACD,SAASM,cAAcC,KAAc;IACnC,MAAMC,WAAWC,KAAKC,KAAK,CAACC,OAAOJ,gBAAAA,QAAS;IAC5C,OAAOI,OAAOC,QAAQ,CAACJ,YAAYA,WAAW;AAChD;AAEA;;;CAGC,GACD,OAAO,SAASK,eACdC,IAA6B,EAC7Bb,IAAc,EACdc,OAAsB,KAAK;IAE3B,MAAMP,WAAWF,cAAcL,KAAKO,QAAQ;IAC5C,MAAMQ,MAAMX,QAAQJ;IACpB,MAAMgB,WAAWH,KAAKI,KAAK,CAACC,IAAI,CAAC,CAACC,OAASf,QAAQe,UAAUJ;IAC7D,IAAI,CAACC,UAAU;QACb,IAAIT,YAAY,GAAG,OAAOM,KAAKI,KAAK;QACpC,IAAIJ,KAAKI,KAAK,CAACG,MAAM,IAAIvB,gBAAgB,OAAOgB,KAAKI,KAAK;QAC1D,OAAO;eACFJ,KAAKI,KAAK;YACb,aAAKjB;gBAAMO,UAAUC,KAAKa,GAAG,CAACvB,mBAAmBS;;SAClD;IACH;IACA,wEAAwE;IACxE,2EAA2E;IAC3E,iDAAiD;IACjD,MAAMe,eACJR,SAAS,QAAQT,cAAcW,SAAST,QAAQ,IAAIA,WAAWA;IACjE,IAAIe,gBAAgB,GAAG;QACrB,OAAOT,KAAKI,KAAK,CAACM,MAAM,CAAC,CAACJ,OAASf,QAAQe,UAAUJ;IACvD;IACA,OAAOF,KAAKI,KAAK,CAACO,GAAG,CAAC,CAACL,OACrBf,QAAQe,UAAUJ,MACd,aAAKI;YAAMZ,UAAUC,KAAKa,GAAG,CAACvB,mBAAmBwB;aACjDH;AAER;AAEA,OAAO,SAASM,eACdZ,IAA6B,EAC7Bb,IAA6D;IAE7D,MAAMe,MAAMX,QAAQJ;IACpB,OAAOa,KAAKI,KAAK,CAACM,MAAM,CAAC,CAACJ,OAASf,QAAQe,UAAUJ;AACvD;AAEA,oDAAoD,GACpD,OAAO,SAASW,UAAUb,IAAyC;;IACjE,6EAA6E;IAC7E,wDAAwD;IACxD,OAAO,SAACA,wBAAAA,KAAMI,KAAK,mBAAI,EAAE,EAAEU,MAAM,CAC/B,CAACC,KAAK5B,OAAS4B,MAAMvB,cAAcL,wBAAAA,KAAMO,QAAQ,GACjD;AAEJ;AAEA;;;CAGC,GACD,OAAO,SAASsB,WACdC,YAAqC,EACrCC,SAAkC;IAElC,IAAId,QAAQ;WAAIa,aAAab,KAAK;KAAC;IACnC,KAAK,MAAMjB,QAAQ+B,UAAUd,KAAK,CAAE;QAClCA,QAAQL,eAAe;YAAEK;QAAM,GAAGjB,MAAM;IAC1C;IACA,OAAOiB;AACT"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/commerce-cart.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Cart v1 (AGL-293): a server-backed cart doc at\n * `hosts/{hostId}/carts/{cartId}`, keyed by an httpOnly cookie. Lines\n * store only ids + quantity — display data and prices resolve from the\n * product docs at read/checkout time, so a stale cart can never charge\n * a stale price. Pure helpers; the cart API owns I/O.\n */\n\nimport { modifierSelectionKey, type ModifierSelection } from './product-modifiers'\n\nexport interface CartLine {\n productId: string\n /** Absent = the product's default variant. */\n variantId?: string\n quantity: number\n /**\n * The day the shopper chose to use a check-in item (AGL-4043),\n * `YYYY-MM-DD` on the store's calendar. Absent: the day they buy. Two\n * different days of one pass are two lines.\n */\n useDayKey?: string\n /**\n * The add-ons the shopper chose on the product's page (AGL-4100), ids\n * only, in the product's group order: priced from the product on every\n * read and at checkout, never stored with a price. Absent: none. The same\n * product with different choices is a different line.\n */\n modifiers?: ModifierSelection[]\n}\n\n/** `hosts/{hostId}/carts/{cartId}` doc. */\nexport interface HostCart {\n lines: CartLine[]\n /** Storefront customer once signed in (AGL-294 merge). */\n customerId?: string\n updatedAtMs?: number\n createdAtMs?: number\n}\n\nexport const CART_MAX_LINES = 50\nexport const CART_MAX_QUANTITY = 99\n\n/**\n * One cart line's identity: product, variant, use day and add-ons\n * (AGL-4100). A line with no add-ons keeps the key it always had, so a cart\n * stored before add-ons were sold online reads, merges and removes as it did.\n */\nexport function cartLineKey(\n line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey' | 'modifiers'>,\n): string {\n const base = `${line.productId}:${line.variantId ?? ''}:${line.useDayKey ?? ''}`\n const choices = modifierSelectionKey(line.modifiers)\n return choices ? `${base}:${choices}` : base\n}\n\nconst lineKey = cartLineKey\n\n/**\n * A line quantity, coerced to a whole finite number (AGL-2285).\n *\n * `Math.round(line.quantity)` was the whole sanitiser, and `Math.round(NaN)` is\n * `NaN` — which then walked past the guard below, because `NaN <= 0` is\n * `false`. A cart line with `quantity: NaN` (a legal Firestore double) was\n * stored, and from there `cartCount` reported `NaN` in the mini-cart badge and\n * `cart-checkout.ts` computed `itemsCents`, the platform fee and the Stripe\n * `line_items[n][quantity]` as `NaN` too — so Stripe 400s and the shopper\n * cannot check out AT ALL until they find the poisoned line and remove it.\n *\n * Answering 0 is what makes the existing `<= 0` guard do its job: an\n * unusable quantity removes the line (or refuses to add one) rather than\n * writing a value nothing downstream can compare against. The same lesson as\n * AGL-2229 one collection over — `Math.max`/`Math.min`/`Math.round` propagate\n * `NaN`, they do not discard it.\n */\nfunction wholeQuantity(value: unknown): number {\n const quantity = Math.round(Number(value ?? 0))\n return Number.isFinite(quantity) ? quantity : 0\n}\n\n/**\n * Adds/merges a line (quantities accumulate), clamped to per-line and\n * line-count caps. Quantity ≤ 0 removes the line.\n */\nexport function upsertCartLine(\n cart: Pick<HostCart, 'lines'>,\n line: CartLine,\n mode: 'add' | 'set' = 'add',\n): CartLine[] {\n const quantity = wholeQuantity(line.quantity)\n const key = lineKey(line)\n const existing = cart.lines.find((item) => lineKey(item) === key)\n if (!existing) {\n if (quantity <= 0) return cart.lines\n if (cart.lines.length >= CART_MAX_LINES) return cart.lines\n return [\n ...cart.lines,\n { ...line, quantity: Math.min(CART_MAX_QUANTITY, quantity) },\n ]\n }\n // The STORED side is coerced too (AGL-2285): a line written before this\n // guard, or by any other writer, can still hold a non-finite quantity, and\n // adding to it would carry that forward forever.\n const nextQuantity =\n mode === 'add' ? wholeQuantity(existing.quantity) + quantity : quantity\n if (nextQuantity <= 0) {\n return cart.lines.filter((item) => lineKey(item) !== key)\n }\n return cart.lines.map((item) =>\n lineKey(item) === key\n ? { ...item, quantity: Math.min(CART_MAX_QUANTITY, nextQuantity) }\n : item,\n )\n}\n\nexport function removeCartLine(\n cart: Pick<HostCart, 'lines'>,\n line: Pick<CartLine, 'productId' | 'variantId' | 'useDayKey' | 'modifiers'>,\n): CartLine[] {\n const key = lineKey(line)\n return cart.lines.filter((item) => lineKey(item) !== key)\n}\n\n/** Total units across lines (the mini-cart badge). */\nexport function cartCount(cart: Pick<HostCart, 'lines'> | undefined): number {\n // Coerced per line (AGL-2285) so one stored `NaN` cannot make the badge read\n // `NaN` for a cart that otherwise has real items in it.\n return (cart?.lines ?? []).reduce(\n (sum, line) => sum + wholeQuantity(line?.quantity),\n 0,\n )\n}\n\n/**\n * Merges a guest cart into a customer cart on sign-in (AGL-294):\n * quantities accumulate per line, capped as usual.\n */\nexport function mergeCarts(\n customerCart: Pick<HostCart, 'lines'>,\n guestCart: Pick<HostCart, 'lines'>,\n): CartLine[] {\n let lines = [...customerCart.lines]\n for (const line of guestCart.lines) {\n lines = upsertCartLine({ lines }, line, 'add')\n }\n return lines\n}\n"],"names":["modifierSelectionKey","CART_MAX_LINES","CART_MAX_QUANTITY","cartLineKey","line","base","productId","variantId","useDayKey","choices","modifiers","lineKey","wholeQuantity","value","quantity","Math","round","Number","isFinite","upsertCartLine","cart","mode","key","existing","lines","find","item","length","min","nextQuantity","filter","map","removeCartLine","cartCount","reduce","sum","mergeCarts","customerCart","guestCart"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GAED,SAASA,oBAAoB,QAAgC,yBAAqB;AA+BlF,OAAO,MAAMC,iBAAiB,GAAE;AAChC,OAAO,MAAMC,oBAAoB,GAAE;AAEnC;;;;CAIC,GACD,OAAO,SAASC,YACdC,IAA2E;QAEzCA,iBAAwBA;IAA1D,MAAMC,OAAO,GAAGD,KAAKE,SAAS,CAAC,CAAC,GAAEF,kBAAAA,KAAKG,SAAS,YAAdH,kBAAkB,GAAG,CAAC,GAAEA,kBAAAA,KAAKI,SAAS,YAAdJ,kBAAkB,IAAI;IAChF,MAAMK,UAAUT,qBAAqBI,KAAKM,SAAS;IACnD,OAAOD,UAAU,GAAGJ,KAAK,CAAC,EAAEI,SAAS,GAAGJ;AAC1C;AAEA,MAAMM,UAAUR;AAEhB;;;;;;;;;;;;;;;;CAgBC,GACD,SAASS,cAAcC,KAAc;IACnC,MAAMC,WAAWC,KAAKC,KAAK,CAACC,OAAOJ,gBAAAA,QAAS;IAC5C,OAAOI,OAAOC,QAAQ,CAACJ,YAAYA,WAAW;AAChD;AAEA;;;CAGC,GACD,OAAO,SAASK,eACdC,IAA6B,EAC7BhB,IAAc,EACdiB,OAAsB,KAAK;IAE3B,MAAMP,WAAWF,cAAcR,KAAKU,QAAQ;IAC5C,MAAMQ,MAAMX,QAAQP;IACpB,MAAMmB,WAAWH,KAAKI,KAAK,CAACC,IAAI,CAAC,CAACC,OAASf,QAAQe,UAAUJ;IAC7D,IAAI,CAACC,UAAU;QACb,IAAIT,YAAY,GAAG,OAAOM,KAAKI,KAAK;QACpC,IAAIJ,KAAKI,KAAK,CAACG,MAAM,IAAI1B,gBAAgB,OAAOmB,KAAKI,KAAK;QAC1D,OAAO;eACFJ,KAAKI,KAAK;YACb,aAAKpB;gBAAMU,UAAUC,KAAKa,GAAG,CAAC1B,mBAAmBY;;SAClD;IACH;IACA,wEAAwE;IACxE,2EAA2E;IAC3E,iDAAiD;IACjD,MAAMe,eACJR,SAAS,QAAQT,cAAcW,SAAST,QAAQ,IAAIA,WAAWA;IACjE,IAAIe,gBAAgB,GAAG;QACrB,OAAOT,KAAKI,KAAK,CAACM,MAAM,CAAC,CAACJ,OAASf,QAAQe,UAAUJ;IACvD;IACA,OAAOF,KAAKI,KAAK,CAACO,GAAG,CAAC,CAACL,OACrBf,QAAQe,UAAUJ,MACd,aAAKI;YAAMZ,UAAUC,KAAKa,GAAG,CAAC1B,mBAAmB2B;aACjDH;AAER;AAEA,OAAO,SAASM,eACdZ,IAA6B,EAC7BhB,IAA2E;IAE3E,MAAMkB,MAAMX,QAAQP;IACpB,OAAOgB,KAAKI,KAAK,CAACM,MAAM,CAAC,CAACJ,OAASf,QAAQe,UAAUJ;AACvD;AAEA,oDAAoD,GACpD,OAAO,SAASW,UAAUb,IAAyC;;IACjE,6EAA6E;IAC7E,wDAAwD;IACxD,OAAO,SAACA,wBAAAA,KAAMI,KAAK,mBAAI,EAAE,EAAEU,MAAM,CAC/B,CAACC,KAAK/B,OAAS+B,MAAMvB,cAAcR,wBAAAA,KAAMU,QAAQ,GACjD;AAEJ;AAEA;;;CAGC,GACD,OAAO,SAASsB,WACdC,YAAqC,EACrCC,SAAkC;IAElC,IAAId,QAAQ;WAAIa,aAAab,KAAK;KAAC;IACnC,KAAK,MAAMpB,QAAQkC,UAAUd,KAAK,CAAE;QAClCA,QAAQL,eAAe;YAAEK;QAAM,GAAGpB,MAAM;IAC1C;IACA,OAAOoB;AACT"}