@aglyn/plugins-commerce 1.0.0-beta.232 → 1.0.0-beta.234

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 (228) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart-extras.d.ts +6 -0
  3. package/src/lib/components/cart-extras.js +4 -1
  4. package/src/lib/components/cart-extras.js.map +1 -1
  5. package/src/lib/components/cart-fulfillment.d.ts +117 -0
  6. package/src/lib/components/cart-fulfillment.js +367 -0
  7. package/src/lib/components/cart-fulfillment.js.map +1 -0
  8. package/src/lib/components/cart.js +52 -10
  9. package/src/lib/components/cart.js.map +1 -1
  10. package/src/lib/components/commerce-console-page.js +42 -1
  11. package/src/lib/components/commerce-console-page.js.map +1 -1
  12. package/src/lib/components/console/host-orders-card.component.js +38 -10
  13. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  14. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  15. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  16. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  17. package/src/lib/components/console/locations-card.component.js +177 -3
  18. package/src/lib/components/console/locations-card.component.js.map +1 -1
  19. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  20. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  21. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  22. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  24. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  25. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  26. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  27. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  28. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  30. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  31. package/src/lib/components/console/pos/pos-api.js +13 -0
  32. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  33. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  34. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  35. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  36. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  37. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  39. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  40. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  42. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  43. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  44. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  45. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  46. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  47. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  48. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  49. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  50. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  51. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  52. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  53. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  54. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  55. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  56. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  57. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  65. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  66. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  68. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  69. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  71. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  72. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  74. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  75. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  86. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  87. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  88. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  89. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  90. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  92. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  93. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  94. package/src/lib/components/console/pos-page.component.js +174 -27
  95. package/src/lib/components/console/pos-page.component.js.map +1 -1
  96. package/src/lib/components/console/products-hub-card.component.js +35 -10
  97. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  98. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  99. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  100. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  101. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  102. package/src/lib/components/console/store-zones.d.ts +8 -1
  103. package/src/lib/components/console/store-zones.js +11 -1
  104. package/src/lib/components/console/store-zones.js.map +1 -1
  105. package/src/lib/components/order-status.js +66 -0
  106. package/src/lib/components/order-status.js.map +1 -1
  107. package/src/lib/components/product-detail.js +42 -15
  108. package/src/lib/components/product-detail.js.map +1 -1
  109. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  110. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  111. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  112. package/src/lib/constants/orders-list-query.d.ts +7 -2
  113. package/src/lib/constants/orders-list-query.js +89 -8
  114. package/src/lib/constants/orders-list-query.js.map +1 -1
  115. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  116. package/src/lib/constants/pos-shift-list-query.js +115 -0
  117. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  118. package/src/lib/constants/product-list-query.d.ts +6 -1
  119. package/src/lib/constants/product-list-query.js +77 -8
  120. package/src/lib/constants/product-list-query.js.map +1 -1
  121. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  122. package/src/lib/constants/stock-movement-query.js +52 -8
  123. package/src/lib/constants/stock-movement-query.js.map +1 -1
  124. package/src/lib/model/buyer-notifications.d.ts +5 -3
  125. package/src/lib/model/buyer-notifications.js +25 -4
  126. package/src/lib/model/buyer-notifications.js.map +1 -1
  127. package/src/lib/model/commerce-orders.d.ts +59 -0
  128. package/src/lib/model/commerce-orders.js.map +1 -1
  129. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  130. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  131. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  132. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  133. package/src/lib/model/commerce-pos-offline.js +301 -0
  134. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  135. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  136. package/src/lib/model/commerce-pos-ops.js +12 -4
  137. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  138. package/src/lib/model/commerce-pos.d.ts +13 -1
  139. package/src/lib/model/commerce-pos.js +5 -4
  140. package/src/lib/model/commerce-pos.js.map +1 -1
  141. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  142. package/src/lib/model/commerce-stock-holds.js +26 -8
  143. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  144. package/src/lib/model/commerce.d.ts +3 -0
  145. package/src/lib/model/commerce.js.map +1 -1
  146. package/src/lib/model/index.d.ts +4 -0
  147. package/src/lib/model/index.js +4 -0
  148. package/src/lib/model/index.js.map +1 -1
  149. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  150. package/src/lib/model/local-fulfillment-settings.js +361 -0
  151. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  152. package/src/lib/model/order-list-fields.d.ts +10 -1
  153. package/src/lib/model/order-list-fields.js +1 -0
  154. package/src/lib/model/order-list-fields.js.map +1 -1
  155. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  156. package/src/lib/model/order-local-fulfillment.js +125 -0
  157. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  158. package/src/lib/model/order-shipping-export.js +4 -0
  159. package/src/lib/model/order-shipping-export.js.map +1 -1
  160. package/src/lib/model/order-status-view.d.ts +20 -1
  161. package/src/lib/model/order-status-view.js +60 -6
  162. package/src/lib/model/order-status-view.js.map +1 -1
  163. package/src/lib/plugin-config.js +6 -2
  164. package/src/lib/plugin-config.js.map +1 -1
  165. package/src/lib/plugin.js +8 -0
  166. package/src/lib/plugin.js.map +1 -1
  167. package/src/lib/pos-kiosk-config.d.ts +26 -0
  168. package/src/lib/pos-kiosk-config.js +59 -0
  169. package/src/lib/pos-kiosk-config.js.map +1 -0
  170. package/src/lib/server/api-v1/openapi.js +8 -0
  171. package/src/lib/server/api-v1/openapi.js.map +1 -1
  172. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  173. package/src/lib/server/api-v1/order-view.js +35 -0
  174. package/src/lib/server/api-v1/order-view.js.map +1 -1
  175. package/src/lib/server/billing-webhook.js +238 -87
  176. package/src/lib/server/billing-webhook.js.map +1 -1
  177. package/src/lib/server/cart-checkout.d.ts +2 -0
  178. package/src/lib/server/cart-checkout.js +173 -13
  179. package/src/lib/server/cart-checkout.js.map +1 -1
  180. package/src/lib/server/checkout-extras.js +18 -4
  181. package/src/lib/server/checkout-extras.js.map +1 -1
  182. package/src/lib/server/checkout.js +71 -14
  183. package/src/lib/server/checkout.js.map +1 -1
  184. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  185. package/src/lib/server/local-fulfillment-status.js +379 -0
  186. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  187. package/src/lib/server/local-fulfillment.d.ts +190 -0
  188. package/src/lib/server/local-fulfillment.js +580 -0
  189. package/src/lib/server/local-fulfillment.js.map +1 -0
  190. package/src/lib/server/membership-register.js +3 -1
  191. package/src/lib/server/membership-register.js.map +1 -1
  192. package/src/lib/server/order-notifications.js +61 -0
  193. package/src/lib/server/order-notifications.js.map +1 -1
  194. package/src/lib/server/pos-display.d.ts +27 -1
  195. package/src/lib/server/pos-display.js +50 -9
  196. package/src/lib/server/pos-display.js.map +1 -1
  197. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  198. package/src/lib/server/pos-kiosk-principal.js +42 -0
  199. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  200. package/src/lib/server/pos-kiosk.d.ts +54 -0
  201. package/src/lib/server/pos-kiosk.js +972 -0
  202. package/src/lib/server/pos-kiosk.js.map +1 -0
  203. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  204. package/src/lib/server/pos-offline-sync.js +765 -0
  205. package/src/lib/server/pos-offline-sync.js.map +1 -0
  206. package/src/lib/server/pos-order.js +22 -4
  207. package/src/lib/server/pos-order.js.map +1 -1
  208. package/src/lib/server/pos-payment.d.ts +6 -0
  209. package/src/lib/server/pos-payment.js +225 -6
  210. package/src/lib/server/pos-payment.js.map +1 -1
  211. package/src/lib/server/pos-print.js +5 -0
  212. package/src/lib/server/pos-print.js.map +1 -1
  213. package/src/lib/server/pos-return.js +27 -0
  214. package/src/lib/server/pos-return.js.map +1 -1
  215. package/src/lib/server/pos-sale.d.ts +6 -0
  216. package/src/lib/server/pos-sale.js +2 -0
  217. package/src/lib/server/pos-sale.js.map +1 -1
  218. package/src/lib/server/pos-shift.js +8 -1
  219. package/src/lib/server/pos-shift.js.map +1 -1
  220. package/src/lib/server/refund.js +3 -0
  221. package/src/lib/server/refund.js.map +1 -1
  222. package/src/lib/server/stock-hold.d.ts +9 -1
  223. package/src/lib/server/stock-hold.js +15 -7
  224. package/src/lib/server/stock-hold.js.map +1 -1
  225. package/src/lib/server.js +16 -0
  226. package/src/lib/server.js.map +1 -1
  227. package/src/lib/tenant-emails.js +161 -0
  228. package/src/lib/tenant-emails.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-kiosk-page.component.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'use client'\n\nimport type { ConsolePublicPageProps } from '@aglyn/aglyn'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Container from '@mui/material/Container'\nimport Dialog from '@mui/material/Dialog'\nimport DialogActions from '@mui/material/DialogActions'\nimport DialogContent from '@mui/material/DialogContent'\nimport DialogContentText from '@mui/material/DialogContentText'\nimport DialogTitle from '@mui/material/DialogTitle'\nimport Stack from '@mui/material/Stack'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport * as CommerceModel from '../../model'\nimport { newAttemptKey, posNativeBridge } from './pos/pos-api'\nimport { PosItemDialog, posItemNeedsChoice, type PosItemChoice } from './pos/pos-item-dialog.component'\nimport { PosDisplayBrandMark, PosDisplayBrandScreen } from './pos-display/brand-screen'\nimport { PosDisplayPairingScreen } from './pos-display/pairing-screen'\nimport { displayMoney, type PosDisplayAnswer } from './pos-display/pos-display-api'\nimport { PosDisplayReceiptScreen } from './pos-display/receipt-screen'\nimport { PosDisplayTipScreen, posDisplayTouchSx } from './pos-display/tip-screen'\nimport { KioskDone, KioskPaying, KioskReview, type KioskPayOptions } from './pos-kiosk/kiosk-checkout'\nimport { KioskMenu, type KioskCartLine } from './pos-kiosk/kiosk-menu'\nimport { KioskStaffControl } from './pos-kiosk/kiosk-staff'\nimport {\n clearKioskCustomerStorage,\n kioskApi,\n readKioskToken,\n storeKioskToken,\n} from './pos-kiosk/pos-kiosk-api'\nimport { useKioskIdle } from './pos-kiosk/use-kiosk-idle'\n\n/** How often the kiosk asks after a card payment in flight. */\nexport const POS_KIOSK_PAYMENT_POLL_MS = 1_500\n\ntype Phase =\n | { kind: 'start' }\n | { kind: 'menu' }\n | { kind: 'review' }\n | { kind: 'tip'; method: 'reader' | 'tap' }\n | { kind: 'paying'; method: 'reader' | 'tap'; paymentId: string | null; chargeCents: number; failure: string | null }\n | { kind: 'receipt' }\n | { kind: 'done' }\n\ntype TipAnswer = { tipChoice: 'percent' | 'custom' | 'none'; tipPercent?: number; tipCents?: number }\n\n/** A product as the register's item sheet takes it, from the kiosk's catalog. */\nexport function kioskItemProduct(product: CommerceModel.PosKioskProduct) {\n return {\n $id: product.id,\n name: product.name,\n slug: product.id,\n type: 'physical',\n status: 'active',\n options: product.options,\n modifierGroups: product.modifierGroups,\n variants: product.variants.map((variant) => ({\n id: variant.id,\n options: variant.options,\n priceUsd: variant.priceCents / 100,\n // A sold-out variant reads as zero on hand; anything else as untracked,\n // so the kiosk never learns or shows a stock count.\n inventory: variant.soldOut ? 0 : null,\n })),\n } as unknown as CommerceModel.HostProduct & { $id: string }\n}\n\n/** The cart line a choice makes: same item and choices merge. */\nexport function kioskCartLine(\n product: CommerceModel.PosKioskProduct,\n choice: PosItemChoice,\n): KioskCartLine {\n const variant = product.variants.find((candidate) => candidate.id === choice.variant.id) ?? product.variants[0]!\n const picked = choice.modifiers\n .map((pick) => {\n const group = product.modifierGroups.find((candidate) => candidate.id === pick.groupId)\n return group?.options.find((option) => option.id === pick.optionId)\n })\n .filter((option): option is CommerceModel.ProductModifierOption => Boolean(option))\n const label = CommerceModel.lineLabelWithModifiers(\n Object.keys(variant.options).length ? Object.values(variant.options).join(' / ') : undefined,\n picked,\n )\n return {\n key: `${product.id}:${variant.id}:${CommerceModel.modifierSelectionKey(choice.modifiers)}`,\n productId: product.id,\n ...(variant.id !== 'default' || product.variants.length > 1 ? { variantId: variant.id } : {}),\n quantity: Math.min(CommerceModel.POS_KIOSK_MAX_QUANTITY, choice.quantity),\n ...(choice.modifiers.length ? { modifiers: choice.modifiers } : {}),\n name: product.name,\n ...(label ? { label } : {}),\n unitCents: variant.priceCents + picked.reduce((sum, option) => sum + option.priceCents, 0),\n }\n}\n\n/**\n * The self-service kiosk (AGL-3623), served at `/kiosk/commerce/pos-kiosk`\n * with no staff session: a customer builds their own order and pays on the\n * register's card reader or Tap to Pay, or sends it to the counter.\n *\n * It holds one secret — the kiosk token from pairing — and everything the\n * customer chooses or types lives in this component's memory only. The idle\n * reset (and \"Done\", and \"Start over\") voids an unpaid order, drops the\n * cart, the tip and any email or phone, sweeps the kiosk's storage keys, and\n * remounts every screen, so the next customer finds nothing of the last.\n */\nexport default function PosKioskPage(_props: ConsolePublicPageProps) {\n const [token, setToken] = useState<string | null | undefined>(undefined)\n const [context, setContext] = useState<CommerceModel.PosKioskContext | null>(null)\n const [catalog, setCatalog] = useState<CommerceModel.PosKioskCatalog | null>(null)\n const [catalogLoading, setCatalogLoading] = useState(false)\n const [categoryId, setCategoryId] = useState<string | null>(null)\n const [phase, setPhase] = useState<Phase>({ kind: 'start' })\n const [lines, setLines] = useState<KioskCartLine[]>([])\n const [itemProduct, setItemProduct] = useState<CommerceModel.PosKioskProduct | null>(null)\n const [cartOpen, setCartOpen] = useState(false)\n const [sale, setSale] = useState<CommerceModel.PosKioskSale | null>(null)\n const [tip, setTip] = useState<TipAnswer>({ tipChoice: 'none' })\n const [busy, setBusy] = useState(false)\n const [notice, setNotice] = useState<string | null>(null)\n const [offline, setOffline] = useState(false)\n // Bumped by every reset: keys every screen, so inputs never carry over.\n const [turn, setTurn] = useState(0)\n // One attempt per cart, and one per press of a payment button.\n const checkoutKey = useRef<string | null>(null)\n const payKey = useRef<string | null>(null)\n const saleRef = useRef(sale)\n saleRef.current = sale\n const phaseRef = useRef(phase)\n phaseRef.current = phase\n\n useEffect(() => {\n setToken(readKioskToken())\n }, [])\n\n const unpaired = useCallback(() => {\n storeKioskToken(null)\n clearKioskCustomerStorage()\n setToken(null)\n setContext(null)\n setCatalog(null)\n setSale(null)\n setLines([])\n setPhase({ kind: 'start' })\n }, [])\n\n /** A response that says the kiosk is no longer paired ends the session. */\n const lost = useCallback(\n (status: number) => {\n if (status === 401) {\n unpaired()\n return true\n }\n return false\n },\n [unpaired],\n )\n\n // The kiosk's settings and the menu: read when paired, and again every\n // ten minutes while idle on the start screen, so an edit reaches it.\n const refresh = useCallback(async () => {\n if (!token) return\n const result = await kioskApi.context(token)\n if (lost(result.status)) return\n setOffline(!result.ok && result.status === 0)\n if (result.ok && result.value) setContext(result.value)\n }, [token, lost])\n\n useEffect(() => {\n void refresh()\n const timer = setInterval(() => {\n if (phaseRef.current.kind === 'start') void refresh()\n }, 10 * 60 * 1000)\n return () => clearInterval(timer)\n }, [refresh])\n\n useEffect(() => {\n if (!token) return undefined\n let active = true\n setCatalogLoading(true)\n void kioskApi.catalog(token, categoryId).then((result) => {\n if (!active) return\n setCatalogLoading(false)\n if (lost(result.status)) return\n if (result.ok && result.value) setCatalog(result.value)\n else setOffline(result.status === 0)\n })\n return () => {\n active = false\n }\n }, [token, categoryId, turn, lost])\n\n const currency = context?.currency ?? catalog?.currency ?? 'usd'\n const money = useCallback((cents: number) => displayMoney(cents, currency), [currency])\n\n /**\n * THE RESET: the unpaid order voided, every customer detail dropped from\n * memory and storage, and the screens remounted on the start screen.\n */\n const reset = useCallback(() => {\n const open = saleRef.current\n if (token && open && open.status === 'open') void kioskApi.abandon(token, open.orderId)\n setSale(null)\n setLines([])\n setTip({ tipChoice: 'none' })\n setItemProduct(null)\n setCartOpen(false)\n setNotice(null)\n setCategoryId(null)\n checkoutKey.current = null\n payKey.current = null\n clearKioskCustomerStorage()\n setPhase({ kind: 'start' })\n setTurn((value) => value + 1)\n }, [token])\n\n const idle = useKioskIdle({\n // Never while a card is being collected: the customer is at the reader.\n active: Boolean(token) && phase.kind !== 'start' && phase.kind !== 'paying',\n idleSeconds: context?.idleSeconds ?? CommerceModel.POS_KIOSK_IDLE_SECONDS_DEFAULT,\n warningSeconds: CommerceModel.POS_KIOSK_IDLE_WARNING_SECONDS,\n onExpire: reset,\n })\n\n // The order-number screen returns to the start on its own.\n useEffect(() => {\n if (phase.kind !== 'done') return undefined\n const timer = setTimeout(reset, CommerceModel.POS_KIOSK_DONE_SECONDS * 1000)\n return () => clearTimeout(timer)\n }, [phase.kind, reset])\n\n const addChoice = useCallback((product: CommerceModel.PosKioskProduct, choice: PosItemChoice) => {\n const line = kioskCartLine(product, choice)\n checkoutKey.current = null\n setLines((current) => {\n const existing = current.find((candidate) => candidate.key === line.key)\n if (existing) {\n return current.map((candidate) =>\n candidate.key === line.key\n ? { ...candidate, quantity: Math.min(CommerceModel.POS_KIOSK_MAX_QUANTITY, candidate.quantity + line.quantity) }\n : candidate,\n )\n }\n if (current.length >= CommerceModel.POS_KIOSK_MAX_LINES) return current\n return [...current, line]\n })\n }, [])\n\n const tapProduct = useCallback(\n (product: CommerceModel.PosKioskProduct) => {\n const asItem = kioskItemProduct(product)\n if (posItemNeedsChoice(asItem)) {\n setItemProduct(product)\n return\n }\n const variant = asItem.variants[0]\n if (!variant || product.variants[0]?.soldOut) return\n addChoice(product, { variant, modifiers: [], quantity: 1 })\n },\n [addChoice],\n )\n\n const checkout = useCallback(async () => {\n if (!token || busy || lines.length === 0) return\n if (!checkoutKey.current) checkoutKey.current = newAttemptKey()\n setBusy(true)\n setNotice(null)\n const result = await kioskApi.checkout(\n token,\n lines.map(({ productId, variantId, quantity, modifiers }) => ({\n productId,\n ...(variantId ? { variantId } : {}),\n quantity,\n ...(modifiers ? { modifiers } : {}),\n })),\n checkoutKey.current,\n )\n setBusy(false)\n if (lost(result.status)) return\n if (!result.ok || !result.value?.sale) {\n // A refused cart is changed before it is tried again.\n checkoutKey.current = null\n setNotice(result.error ?? 'Your order could not be priced. Try again.')\n return\n }\n setSale(result.value.sale)\n setCartOpen(false)\n setPhase({ kind: 'review' })\n }, [token, busy, lines, lost])\n\n const backToMenu = useCallback(() => {\n const open = saleRef.current\n if (token && open && open.status === 'open') void kioskApi.abandon(token, open.orderId)\n setSale(null)\n checkoutKey.current = null\n setNotice(null)\n setPhase({ kind: 'menu' })\n }, [token])\n\n const sendToCounter = useCallback(async () => {\n const open = saleRef.current\n if (!token || !open) return\n setBusy(true)\n const result = await kioskApi.counter(token, open.orderId)\n setBusy(false)\n if (lost(result.status)) return\n if (!result.ok || !result.value?.sale) {\n setNotice(result.error ?? 'Your order could not be sent to the counter.')\n return\n }\n setSale(result.value.sale)\n setLines([])\n setPhase({ kind: 'done' })\n }, [token, lost])\n\n const startPayment = useCallback(\n async (method: 'reader' | 'tap', answer: TipAnswer) => {\n const open = saleRef.current\n if (!token || !open) return\n if (!payKey.current) payKey.current = newAttemptKey()\n setBusy(true)\n setNotice(null)\n const result = await kioskApi.pay(token, { orderId: open.orderId, method, ...answer }, payKey.current)\n if (lost(result.status)) return setBusy(false)\n if (!result.ok || !result.value) {\n setBusy(false)\n payKey.current = null\n setNotice(result.error ?? 'The card payment could not be started.')\n setPhase({ kind: 'review' })\n return\n }\n const { sale: next, paymentId, clientSecret, paymentIntentId } = result.value\n setSale(next)\n const tipCents = CommerceModel.posKioskTipCents(answer.tipChoice, {\n baseCents: open.dueCents,\n enabled: true,\n percentages: context?.tipping.percentages ?? [],\n percent: answer.tipPercent,\n cents: answer.tipCents,\n })\n const chargeCents = open.dueCents + (tipCents ?? 0)\n setPhase({ kind: 'paying', method, paymentId: paymentId ?? null, chargeCents, failure: null })\n setBusy(false)\n if (method === 'tap') {\n const bridge = posNativeBridge()\n if (!bridge || !clientSecret || !paymentIntentId) {\n setPhase({ kind: 'paying', method, paymentId: paymentId ?? null, chargeCents, failure: 'Tap to Pay is not available on this device.' })\n return\n }\n const collected = await bridge\n .collectCardPayment({ paymentIntentId, clientSecret, amountCents: chargeCents })\n .catch(() => ({ status: 'failed' as const, message: undefined }))\n if (collected.status !== 'collected') {\n setPhase({\n kind: 'paying',\n method,\n paymentId: paymentId ?? null,\n chargeCents,\n failure: collected.status === 'canceled' ? 'The payment was canceled.' : (collected.message ?? 'The card was not read.'),\n })\n }\n }\n },\n [token, lost, context],\n )\n\n // The card in flight, asked after until it is paid or it fails.\n const paymentId = phase.kind === 'paying' ? phase.paymentId : null\n const paymentFailed = phase.kind === 'paying' ? Boolean(phase.failure) : false\n useEffect(() => {\n if (!token || !paymentId || paymentFailed) return undefined\n const open = saleRef.current\n if (!open) return undefined\n let active = true\n const timer = setInterval(async () => {\n const result = await kioskApi.paymentStatus(token, open.orderId, paymentId)\n if (!active) return\n if (lost(result.status)) return\n const next = result.value?.sale\n if (!next) return\n setSale(next)\n if (next.status === 'paid') {\n clearInterval(timer)\n setLines([])\n payKey.current = null\n setPhase({ kind: 'receipt' })\n return\n }\n const status = next.payment?.id === paymentId ? next.payment.status : ''\n if (status === 'failed' || status === 'canceled') {\n clearInterval(timer)\n payKey.current = null\n setPhase((current) =>\n current.kind === 'paying'\n ? { ...current, failure: next.payment?.failureMessage ?? 'The card was declined.' }\n : current,\n )\n }\n }, POS_KIOSK_PAYMENT_POLL_MS)\n return () => {\n active = false\n clearInterval(timer)\n }\n }, [token, paymentId, paymentFailed, lost])\n\n const cancelPayment = useCallback(async () => {\n const open = saleRef.current\n if (!token || !open || phase.kind !== 'paying') return\n setBusy(true)\n if (phase.paymentId && !phase.failure) await kioskApi.cancelPayment(token, open.orderId, phase.paymentId)\n const fresh = await kioskApi.sale(token, open.orderId)\n setBusy(false)\n payKey.current = null\n if (fresh.value?.sale) setSale(fresh.value.sale)\n if (fresh.value?.sale.status === 'paid') {\n setPhase({ kind: 'receipt' })\n return\n }\n setPhase({ kind: 'review' })\n }, [token, phase])\n\n const answerReceipt = useCallback(\n async (answer: PosDisplayAnswer) => {\n const paid = saleRef.current\n if (!token || !paid || !answer.receiptChannel) return\n setBusy(true)\n const result = await kioskApi.receipt(token, {\n orderId: paid.orderId,\n channel: answer.receiptChannel,\n ...(answer.email ? { to: answer.email } : {}),\n ...(answer.phone ? { to: answer.phone } : {}),\n ...(answer.marketingOptIn ? { marketingOptIn: true } : {}),\n })\n setBusy(false)\n if (lost(result.status)) return\n if (!result.ok) {\n setNotice(result.error ?? 'Your receipt could not be sent. Ask at the counter.')\n }\n setPhase({ kind: 'done' })\n },\n [token, lost],\n )\n\n const pay: KioskPayOptions = useMemo(\n () => ({\n reader: Boolean(context?.payments.cardPresent && context.payments.reader),\n tap: Boolean(context?.payments.cardPresent && posNativeBridge()),\n counter: Boolean(context?.payments.payAtCounter),\n }),\n [context],\n )\n\n const choosePay = useCallback(\n (method: 'reader' | 'tap') => {\n if (context?.tipping.enabled) {\n setPhase({ kind: 'tip', method })\n return\n }\n setTip({ tipChoice: 'none' })\n void startPayment(method, { tipChoice: 'none' })\n },\n [context, startPayment],\n )\n\n if (token === undefined) {\n return (\n <Box sx={{ minHeight: '100dvh', display: 'grid', placeItems: 'center' }}>\n <CircularProgress aria-label=\"Loading\" />\n </Box>\n )\n }\n\n if (!token) {\n return (\n <PosDisplayPairingScreen\n mode=\"kiosk\"\n onPaired={(next) => {\n storeKioskToken(next)\n setToken(next)\n }}\n />\n )\n }\n\n const branding = context?.branding ?? null\n let screen\n if (phase.kind === 'start') {\n screen = (\n <PosDisplayBrandScreen branding={branding} message={branding?.message || 'Order here'}>\n <Button\n variant=\"contained\"\n size=\"large\"\n onClick={() => setPhase({ kind: 'menu' })}\n sx={(theme) => ({ ...posDisplayTouchSx(theme), px: 6 })}\n >\n {'Start order'}\n </Button>\n </PosDisplayBrandScreen>\n )\n } else if (phase.kind === 'menu') {\n screen = (\n <>\n {notice ? (\n <Alert severity=\"warning\" onClose={() => setNotice(null)} sx={{ m: 2, mb: 0 }}>\n {notice}\n </Alert>\n ) : null}\n <KioskMenu\n catalog={catalog}\n loading={catalogLoading && !catalog}\n categoryId={categoryId}\n onCategory={setCategoryId}\n onProduct={tapProduct}\n lines={lines}\n currency={currency}\n onReview={() => void checkout()}\n onQuantity={(key, quantity) => {\n checkoutKey.current = null\n setLines((current) =>\n quantity <= 0\n ? current.filter((line) => line.key !== key)\n : current.map((line) => (line.key === key ? { ...line, quantity } : line)),\n )\n }}\n cartOpen={cartOpen}\n onCartOpen={setCartOpen}\n busy={busy}\n />\n </>\n )\n } else if (phase.kind === 'review' && sale) {\n screen = (\n <KioskReview\n sale={sale}\n currency={currency}\n pay={pay}\n busy={busy}\n notice={notice}\n onPay={choosePay}\n onCounter={() => void sendToCounter()}\n onBack={backToMenu}\n />\n )\n } else if (phase.kind === 'tip' && sale && context) {\n screen = (\n <Container maxWidth=\"md\" sx={{ py: 4 }}>\n <Stack spacing={4} sx={{ alignItems: 'center' }}>\n <PosDisplayBrandMark branding={branding} />\n <PosDisplayTipScreen\n tip={{ baseCents: sale.dueCents, percentages: context.tipping.percentages, allowCustom: true }}\n promptId={`kiosk-${sale.orderId}`}\n busy={busy}\n currency={currency}\n onAnswer={(answer) => {\n const next: TipAnswer = {\n tipChoice: answer.tipChoice ?? 'none',\n ...(answer.tipPercent ? { tipPercent: answer.tipPercent } : {}),\n ...(answer.tipChoice === 'custom' ? { tipCents: answer.tipCents ?? 0 } : {}),\n }\n setTip(next)\n void startPayment(phase.method, next)\n }}\n />\n <Button onClick={() => setPhase({ kind: 'review' })} disabled={busy}>\n {'Back'}\n </Button>\n </Stack>\n </Container>\n )\n } else if (phase.kind === 'paying' && sale) {\n screen = (\n <KioskPaying\n chargeCents={phase.chargeCents}\n currency={currency}\n method={phase.method}\n failure={phase.failure}\n testMode={Boolean(context?.testMode && phase.method === 'reader')}\n busy={busy}\n onCancel={() => void cancelPayment()}\n onRetry={() => void startPayment(phase.method, tip)}\n onCounter={pay.counter ? () => void sendToCounter() : null}\n onSimulate={\n phase.paymentId\n ? () => void kioskApi.simulate(token, sale.orderId, phase.paymentId as string)\n : null\n }\n />\n )\n } else if (phase.kind === 'receipt' && sale && context) {\n screen = (\n <Container maxWidth=\"md\" sx={{ py: 4 }}>\n <Stack spacing={4} sx={{ alignItems: 'center' }}>\n <PosDisplayBrandMark branding={branding} />\n <PosDisplayReceiptScreen\n receipt={{ channels: context.receipts, offerMarketing: context.offerMarketing }}\n promptId={`kiosk-${sale.orderId}`}\n busy={busy}\n onAnswer={(answer) => void answerReceipt(answer)}\n />\n </Stack>\n </Container>\n )\n } else if (phase.kind === 'done' && sale) {\n screen = <KioskDone sale={sale} currency={currency} onDone={reset} />\n } else {\n screen = <PosDisplayBrandScreen branding={branding} busy />\n }\n\n return (\n <Box key={turn} sx={{ position: 'relative', minHeight: '100dvh' }}>\n {offline ? (\n <Alert severity=\"warning\" sx={{ position: 'fixed', top: 0, left: 0, right: 0, zIndex: (theme) => theme.zIndex.modal + 1 }}>\n {'Reconnecting…'}\n </Alert>\n ) : null}\n {screen}\n <PosItemDialog\n product={itemProduct ? kioskItemProduct(itemProduct) : null}\n onClose={() => setItemProduct(null)}\n onConfirm={(choice) => {\n const product = itemProduct\n setItemProduct(null)\n if (product) addChoice(product, choice)\n }}\n formatMoney={money}\n blockSoldOut\n maxQuantity={CommerceModel.POS_KIOSK_MAX_QUANTITY}\n />\n <Dialog open={idle.warning !== null} onClose={idle.stillHere} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Still there?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {`This order will be cleared in ${idle.warning ?? 0} seconds.`}\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={reset}>{'Start over'}</Button>\n <Button variant=\"contained\" onClick={idle.stillHere}>\n {'I’m still here'}\n </Button>\n </DialogActions>\n </Dialog>\n {phase.kind === 'start' || phase.kind === 'menu' ? (\n <KioskStaffControl token={token} onExit={unpaired} onUnauthorized={unpaired} />\n ) : null}\n </Box>\n )\n}\n\nPosKioskPage.displayName = 'PosKioskPage'\n"],"names":["Alert","Box","Button","CircularProgress","Container","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","useCallback","useEffect","useMemo","useRef","useState","CommerceModel","newAttemptKey","posNativeBridge","PosItemDialog","posItemNeedsChoice","PosDisplayBrandMark","PosDisplayBrandScreen","PosDisplayPairingScreen","displayMoney","PosDisplayReceiptScreen","PosDisplayTipScreen","posDisplayTouchSx","KioskDone","KioskPaying","KioskReview","KioskMenu","KioskStaffControl","clearKioskCustomerStorage","kioskApi","readKioskToken","storeKioskToken","useKioskIdle","POS_KIOSK_PAYMENT_POLL_MS","kioskItemProduct","product","$id","id","name","slug","type","status","options","modifierGroups","variants","map","variant","priceUsd","priceCents","inventory","soldOut","kioskCartLine","choice","find","candidate","picked","modifiers","pick","group","groupId","option","optionId","filter","Boolean","label","lineLabelWithModifiers","Object","keys","length","values","join","undefined","key","modifierSelectionKey","productId","variantId","quantity","Math","min","POS_KIOSK_MAX_QUANTITY","unitCents","reduce","sum","PosKioskPage","_props","context","idle","token","setToken","setContext","catalog","setCatalog","catalogLoading","setCatalogLoading","categoryId","setCategoryId","phase","setPhase","kind","lines","setLines","itemProduct","setItemProduct","cartOpen","setCartOpen","sale","setSale","tip","setTip","tipChoice","busy","setBusy","notice","setNotice","offline","setOffline","turn","setTurn","checkoutKey","payKey","saleRef","current","phaseRef","unpaired","lost","refresh","result","ok","value","timer","setInterval","clearInterval","active","then","currency","money","cents","reset","open","abandon","orderId","idleSeconds","POS_KIOSK_IDLE_SECONDS_DEFAULT","warningSeconds","POS_KIOSK_IDLE_WARNING_SECONDS","onExpire","setTimeout","POS_KIOSK_DONE_SECONDS","clearTimeout","addChoice","line","existing","POS_KIOSK_MAX_LINES","tapProduct","asItem","checkout","error","backToMenu","sendToCounter","counter","startPayment","method","answer","pay","next","paymentId","clientSecret","paymentIntentId","tipCents","posKioskTipCents","baseCents","dueCents","enabled","percentages","tipping","percent","tipPercent","chargeCents","failure","bridge","collected","collectCardPayment","amountCents","catch","message","paymentFailed","paymentStatus","payment","failureMessage","cancelPayment","fresh","answerReceipt","paid","receiptChannel","receipt","channel","email","to","phone","marketingOptIn","reader","payments","cardPresent","tap","payAtCounter","choosePay","sx","minHeight","display","placeItems","aria-label","mode","onPaired","branding","screen","size","onClick","theme","px","severity","onClose","m","mb","loading","onCategory","onProduct","onReview","onQuantity","onCartOpen","onPay","onCounter","onBack","maxWidth","py","spacing","alignItems","allowCustom","promptId","onAnswer","disabled","testMode","onCancel","onRetry","onSimulate","simulate","channels","receipts","offerMarketing","onDone","position","top","left","right","zIndex","modal","onConfirm","formatMoney","blockSoldOut","maxQuantity","warning","stillHere","fullWidth","onExit","onUnauthorized","displayName"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { authorizedFetch } from '@aglyn/shared-util-http/authorized-token';
18
+ import { type PosOfflineKit, type PosOfflineSale, type PosOfflineSaleOutcome } from '../../../model/commerce-pos-offline';
19
+ /**
20
+ * The offline register's two calls (AGL-3625), answered as data. `status: 0`
21
+ * is the network itself failing — the register's signal that it is offline
22
+ * even while the browser says it is not.
23
+ */
24
+ export type PosOfflineAnswer<T> = {
25
+ ok: true;
26
+ status: number;
27
+ body: T;
28
+ } | {
29
+ ok: false;
30
+ status: number;
31
+ error: string;
32
+ };
33
+ type User = Parameters<typeof authorizedFetch>[0];
34
+ /** The site's offline rules, from the server. */
35
+ export declare function fetchPosOfflineKit(user: User, hostId: string): Promise<PosOfflineAnswer<{
36
+ kit: PosOfflineKit;
37
+ }>>;
38
+ /** Sends one batch of queued sales; an empty batch only asks whether the route answers. */
39
+ export declare function syncPosOfflineSales(user: User, hostId: string, sales: PosOfflineSale[]): Promise<PosOfflineAnswer<{
40
+ results: PosOfflineSaleOutcome[];
41
+ }>>;
42
+ /** A key for one offline sale: the order's id once it syncs. */
43
+ export declare function newPosOfflineSaleKey(): string;
44
+ export {};
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
17
+ import { POS_OFFLINE_SYNC_ROUTE } from "../../../model/commerce-pos-offline.js";
18
+ async function call(user, init, query = '') {
19
+ let response;
20
+ try {
21
+ response = await authorizedFetch(user, `${POS_OFFLINE_SYNC_ROUTE}${query}`, init);
22
+ } catch (unused) {
23
+ return {
24
+ ok: false,
25
+ status: 0,
26
+ error: 'The register is offline.'
27
+ };
28
+ }
29
+ const body = await response.json().catch(()=>({}));
30
+ if (!response.ok) {
31
+ var _ref;
32
+ return {
33
+ ok: false,
34
+ status: response.status,
35
+ error: String((_ref = body == null ? void 0 : body.error) != null ? _ref : 'Something went wrong')
36
+ };
37
+ }
38
+ return {
39
+ ok: true,
40
+ status: response.status,
41
+ body
42
+ };
43
+ }
44
+ /** The site's offline rules, from the server. */ export function fetchPosOfflineKit(user, hostId) {
45
+ return call(user, {
46
+ method: 'GET'
47
+ }, `?${new URLSearchParams({
48
+ hostId
49
+ })}`);
50
+ }
51
+ /** Sends one batch of queued sales; an empty batch only asks whether the route answers. */ export function syncPosOfflineSales(user, hostId, sales) {
52
+ return call(user, {
53
+ method: 'POST',
54
+ headers: {
55
+ 'Content-Type': 'application/json'
56
+ },
57
+ body: JSON.stringify({
58
+ hostId,
59
+ sales
60
+ })
61
+ });
62
+ }
63
+ /** A key for one offline sale: the order's id once it syncs. */ export function newPosOfflineSaleKey() {
64
+ const random = typeof crypto !== 'undefined' && 'randomUUID' in crypto ? crypto.randomUUID().replace(/-/g, '') : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
65
+ // Leading letters keep a key from ever reading as an order number.
66
+ return `off${random}`.slice(0, 40);
67
+ }
68
+
69
+ //# sourceMappingURL=pos-offline-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-offline/pos-offline-api.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\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n POS_OFFLINE_SYNC_ROUTE,\n type PosOfflineKit,\n type PosOfflineSale,\n type PosOfflineSaleOutcome,\n} from '../../../model/commerce-pos-offline'\n\n/**\n * The offline register's two calls (AGL-3625), answered as data. `status: 0`\n * is the network itself failing — the register's signal that it is offline\n * even while the browser says it is not.\n */\nexport type PosOfflineAnswer<T> =\n | { ok: true; status: number; body: T }\n | { ok: false; status: number; error: string }\n\ntype User = Parameters<typeof authorizedFetch>[0]\n\nasync function call<T>(user: User, init: RequestInit, query = ''): Promise<PosOfflineAnswer<T>> {\n let response: Response\n try {\n response = await authorizedFetch(user, `${POS_OFFLINE_SYNC_ROUTE}${query}`, init)\n } catch {\n return { ok: false, status: 0, error: 'The register is offline.' }\n }\n const body = (await response.json().catch(() => ({}))) as T & { error?: string }\n if (!response.ok) {\n return { ok: false, status: response.status, error: String(body?.error ?? 'Something went wrong') }\n }\n return { ok: true, status: response.status, body }\n}\n\n/** The site's offline rules, from the server. */\nexport function fetchPosOfflineKit(user: User, hostId: string) {\n return call<{ kit: PosOfflineKit }>(user, { method: 'GET' }, `?${new URLSearchParams({ hostId })}`)\n}\n\n/** Sends one batch of queued sales; an empty batch only asks whether the route answers. */\nexport function syncPosOfflineSales(user: User, hostId: string, sales: PosOfflineSale[]) {\n return call<{ results: PosOfflineSaleOutcome[] }>(user, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, sales }),\n })\n}\n\n/** A key for one offline sale: the order's id once it syncs. */\nexport function newPosOfflineSaleKey(): string {\n const random =\n typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID().replace(/-/g, '')\n : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`\n // Leading letters keep a key from ever reading as an order number.\n return `off${random}`.slice(0, 40)\n}\n"],"names":["authorizedFetch","POS_OFFLINE_SYNC_ROUTE","call","user","init","query","response","ok","status","error","body","json","catch","String","fetchPosOfflineKit","hostId","method","URLSearchParams","syncPosOfflineSales","sales","headers","JSON","stringify","newPosOfflineSaleKey","random","crypto","randomUUID","replace","Date","now","toString","Math","slice"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,eAAe,QAAQ,2CAA0C;AAC1E,SACEC,sBAAsB,QAIjB,yCAAqC;AAa5C,eAAeC,KAAQC,IAAU,EAAEC,IAAiB,EAAEC,QAAQ,EAAE;IAC9D,IAAIC;IACJ,IAAI;QACFA,WAAW,MAAMN,gBAAgBG,MAAM,GAAGF,yBAAyBI,OAAO,EAAED;IAC9E,EAAE,eAAM;QACN,OAAO;YAAEG,IAAI;YAAOC,QAAQ;YAAGC,OAAO;QAA2B;IACnE;IACA,MAAMC,OAAQ,MAAMJ,SAASK,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;IAClD,IAAI,CAACN,SAASC,EAAE,EAAE;;QAChB,OAAO;YAAEA,IAAI;YAAOC,QAAQF,SAASE,MAAM;YAAEC,OAAOI,eAAOH,wBAAAA,KAAMD,KAAK,mBAAI;QAAwB;IACpG;IACA,OAAO;QAAEF,IAAI;QAAMC,QAAQF,SAASE,MAAM;QAAEE;IAAK;AACnD;AAEA,+CAA+C,GAC/C,OAAO,SAASI,mBAAmBX,IAAU,EAAEY,MAAc;IAC3D,OAAOb,KAA6BC,MAAM;QAAEa,QAAQ;IAAM,GAAG,CAAC,CAAC,EAAE,IAAIC,gBAAgB;QAAEF;IAAO,IAAI;AACpG;AAEA,yFAAyF,GACzF,OAAO,SAASG,oBAAoBf,IAAU,EAAEY,MAAc,EAAEI,KAAuB;IACrF,OAAOjB,KAA2CC,MAAM;QACtDa,QAAQ;QACRI,SAAS;YAAE,gBAAgB;QAAmB;QAC9CV,MAAMW,KAAKC,SAAS,CAAC;YAAEP;YAAQI;QAAM;IACvC;AACF;AAEA,8DAA8D,GAC9D,OAAO,SAASI;IACd,MAAMC,SACJ,OAAOC,WAAW,eAAe,gBAAgBA,SAC7CA,OAAOC,UAAU,GAAGC,OAAO,CAAC,MAAM,MAClC,GAAGC,KAAKC,GAAG,GAAGC,QAAQ,CAAC,MAAMC,KAAKP,MAAM,GAAGM,QAAQ,CAAC,IAAIE,KAAK,CAAC,KAAKD,KAAKP,MAAM,GAAGM,QAAQ,CAAC,IAAIE,KAAK,CAAC,IAAI;IAC9G,mEAAmE;IACnE,OAAO,CAAC,GAAG,EAAER,QAAQ,CAACQ,KAAK,CAAC,GAAG;AACjC"}
@@ -0,0 +1,7 @@
1
+ import type { PosOfflineState } from './use-pos-offline';
2
+ export declare function PosOfflineBanner(props: {
3
+ offline: PosOfflineState;
4
+ }): import("react").JSX.Element;
5
+ export declare namespace PosOfflineBanner {
6
+ var displayName: string;
7
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import { Alert, AlertTitle, Button, Stack, Typography } from "@mui/material";
19
+ import { useConfirmationContext } from "@aglyn/shared-ui-jsx";
20
+ import { posOfflineFlagLabels } from "../../../model/commerce-pos-offline.js";
21
+ import { usd } from "../pos/pos-api.js";
22
+ /*==========================================
23
+ * WHAT THE REGISTER SAYS ABOUT ITS CONNECTION (AGL-3625).
24
+ *
25
+ * - offline: what still sells (cash), what does not (cards, gift cards,
26
+ * room charges), and how many sales are waiting on this device;
27
+ * - back online: the sync, then what the server flagged — stock that went
28
+ * short, a changed price, a closed shift — by order number;
29
+ * - a sale the server would not take, kept on the device with its reason.
30
+ *
31
+ * Nothing when the register is online with nothing waiting and nothing to say.
32
+ *=========================================*/ const plural = (count, one, many)=>`${count} ${count === 1 ? one : many}`;
33
+ export function PosOfflineBanner(props) {
34
+ const { offline } = props;
35
+ const { confirm } = useConfirmationContext();
36
+ const waiting = offline.queue.filter((entry)=>entry.state === 'queued');
37
+ const refused = offline.queue.filter((entry)=>entry.state === 'refused');
38
+ const waitingCents = waiting.reduce((sum, entry)=>sum + entry.sale.totals.totalCents, 0);
39
+ const alerts = [];
40
+ if (offline.offline) {
41
+ var _offline_unavailableReason;
42
+ alerts.push(/*#__PURE__*/ _jsxs(Alert, {
43
+ severity: "warning",
44
+ role: "status",
45
+ children: [
46
+ /*#__PURE__*/ _jsx(AlertTitle, {
47
+ children: 'Offline'
48
+ }),
49
+ offline.ready ? 'Cash sales keep ringing and are saved on this register until the connection returns. ' + 'Card readers, typed cards, the QR link, gift cards, store credit and room charges are off.' : `Sales are paused: ${(_offline_unavailableReason = offline.unavailableReason) != null ? _offline_unavailableReason : 'this register cannot sell offline.'}`,
50
+ waiting.length ? /*#__PURE__*/ _jsx(Typography, {
51
+ variant: "body2",
52
+ sx: {
53
+ mt: 0.5
54
+ },
55
+ children: `${plural(waiting.length, 'sale', 'sales')} (${usd(waitingCents)}) waiting to sync.`
56
+ }) : null
57
+ ]
58
+ }, "offline"));
59
+ } else if (waiting.length) {
60
+ alerts.push(/*#__PURE__*/ _jsx(Alert, {
61
+ severity: "info",
62
+ role: "status",
63
+ action: offline.syncing ? null : /*#__PURE__*/ _jsx(Button, {
64
+ color: "inherit",
65
+ size: "small",
66
+ onClick: ()=>void offline.syncNow(),
67
+ children: 'Sync now'
68
+ }),
69
+ children: offline.syncing ? `Syncing ${plural(waiting.length, 'offline sale', 'offline sales')}…` : `${plural(waiting.length, 'offline sale', 'offline sales')} (${usd(waitingCents)}) waiting to sync.`
70
+ }, "sync"));
71
+ }
72
+ if (offline.syncError) {
73
+ alerts.push(/*#__PURE__*/ _jsx(Alert, {
74
+ severity: "error",
75
+ children: `Offline sales could not sync: ${offline.syncError} They stay on this register.`
76
+ }, "error"));
77
+ }
78
+ for (const entry of refused){
79
+ var _entry_error;
80
+ alerts.push(/*#__PURE__*/ _jsx(Alert, {
81
+ severity: "error",
82
+ action: /*#__PURE__*/ _jsx(Button, {
83
+ color: "inherit",
84
+ size: "small",
85
+ onClick: async ()=>{
86
+ const confirmed = await confirm({
87
+ title: 'Remove this sale from the register?',
88
+ description: `The ${usd(entry.sale.totals.totalCents)} cash sale will not be recorded anywhere. ` + 'Record it by hand first if the cash was taken.',
89
+ confirmationText: 'Remove',
90
+ confirmationButtonProps: {
91
+ color: 'error'
92
+ }
93
+ }).then(()=>true).catch(()=>false);
94
+ if (confirmed) await offline.discard(entry.saleKey);
95
+ },
96
+ children: 'Remove'
97
+ }),
98
+ children: `A ${usd(entry.sale.totals.totalCents)} offline sale from ${new Date(entry.sale.soldAtMs).toLocaleString()} ` + `did not sync: ${(_entry_error = entry.error) != null ? _entry_error : 'refused'}`
99
+ }, `refused-${entry.saleKey}`));
100
+ }
101
+ if (offline.notices.length) {
102
+ alerts.push(/*#__PURE__*/ _jsxs(Alert, {
103
+ severity: "warning",
104
+ action: /*#__PURE__*/ _jsx(Button, {
105
+ color: "inherit",
106
+ size: "small",
107
+ onClick: offline.dismissNotices,
108
+ children: 'Dismiss'
109
+ }),
110
+ children: [
111
+ /*#__PURE__*/ _jsx(AlertTitle, {
112
+ children: 'Synced, with something to check'
113
+ }),
114
+ /*#__PURE__*/ _jsx(Stack, {
115
+ spacing: 0.5,
116
+ children: offline.notices.map((notice)=>/*#__PURE__*/ _jsx(Typography, {
117
+ variant: "body2",
118
+ children: `Order ${notice.number ? `#${notice.number}` : notice.orderId}: ` + [
119
+ ...notice.stockConflicts.map((conflict)=>`${conflict.shortUnits} of ${conflict.requested}× ${conflict.name} not in stock`),
120
+ ...posOfflineFlagLabels(notice.flags.filter((flag)=>flag !== 'stock-short'))
121
+ ].join('; ')
122
+ }, notice.saleKey))
123
+ })
124
+ ]
125
+ }, "notices"));
126
+ }
127
+ if (!alerts.length) return null;
128
+ return /*#__PURE__*/ _jsx(Stack, {
129
+ spacing: 1,
130
+ children: alerts
131
+ });
132
+ }
133
+ PosOfflineBanner.displayName = 'PosOfflineBanner';
134
+
135
+ //# sourceMappingURL=pos-offline-banner.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-offline/pos-offline-banner.component.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'use client'\n\nimport { Alert, AlertTitle, Button, Stack, Typography } from '@mui/material'\nimport { useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport type { ReactElement } from 'react'\nimport { posOfflineFlagLabels } from '../../../model/commerce-pos-offline'\nimport { usd } from '../pos/pos-api'\nimport type { PosOfflineState } from './use-pos-offline'\n\n/*==========================================\n * WHAT THE REGISTER SAYS ABOUT ITS CONNECTION (AGL-3625).\n *\n * - offline: what still sells (cash), what does not (cards, gift cards,\n * room charges), and how many sales are waiting on this device;\n * - back online: the sync, then what the server flagged — stock that went\n * short, a changed price, a closed shift — by order number;\n * - a sale the server would not take, kept on the device with its reason.\n *\n * Nothing when the register is online with nothing waiting and nothing to say.\n *=========================================*/\n\nconst plural = (count: number, one: string, many: string) => `${count} ${count === 1 ? one : many}`\n\nexport function PosOfflineBanner(props: { offline: PosOfflineState }) {\n const { offline } = props\n const { confirm } = useConfirmationContext()\n const waiting = offline.queue.filter((entry) => entry.state === 'queued')\n const refused = offline.queue.filter((entry) => entry.state === 'refused')\n const waitingCents = waiting.reduce((sum, entry) => sum + entry.sale.totals.totalCents, 0)\n const alerts: ReactElement[] = []\n\n if (offline.offline) {\n alerts.push(\n <Alert key=\"offline\" severity=\"warning\" role=\"status\">\n <AlertTitle>{'Offline'}</AlertTitle>\n {offline.ready\n ? 'Cash sales keep ringing and are saved on this register until the connection returns. ' +\n 'Card readers, typed cards, the QR link, gift cards, store credit and room charges are off.'\n : `Sales are paused: ${offline.unavailableReason ?? 'this register cannot sell offline.'}`}\n {waiting.length ? (\n <Typography variant=\"body2\" sx={{ mt: 0.5 }}>\n {`${plural(waiting.length, 'sale', 'sales')} (${usd(waitingCents)}) waiting to sync.`}\n </Typography>\n ) : null}\n </Alert>,\n )\n } else if (waiting.length) {\n alerts.push(\n <Alert\n key=\"sync\"\n severity=\"info\"\n role=\"status\"\n action={\n offline.syncing ? null : (\n <Button color=\"inherit\" size=\"small\" onClick={() => void offline.syncNow()}>\n {'Sync now'}\n </Button>\n )\n }\n >\n {offline.syncing\n ? `Syncing ${plural(waiting.length, 'offline sale', 'offline sales')}…`\n : `${plural(waiting.length, 'offline sale', 'offline sales')} (${usd(waitingCents)}) waiting to sync.`}\n </Alert>,\n )\n }\n\n if (offline.syncError) {\n alerts.push(\n <Alert key=\"error\" severity=\"error\">\n {`Offline sales could not sync: ${offline.syncError} They stay on this register.`}\n </Alert>,\n )\n }\n\n for (const entry of refused) {\n alerts.push(\n <Alert\n key={`refused-${entry.saleKey}`}\n severity=\"error\"\n action={\n <Button\n color=\"inherit\"\n size=\"small\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this sale from the register?',\n description:\n `The ${usd(entry.sale.totals.totalCents)} cash sale will not be recorded anywhere. ` +\n 'Record it by hand first if the cash was taken.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (confirmed) await offline.discard(entry.saleKey)\n }}\n >\n {'Remove'}\n </Button>\n }\n >\n {`A ${usd(entry.sale.totals.totalCents)} offline sale from ${new Date(entry.sale.soldAtMs).toLocaleString()} ` +\n `did not sync: ${entry.error ?? 'refused'}`}\n </Alert>,\n )\n }\n\n if (offline.notices.length) {\n alerts.push(\n <Alert\n key=\"notices\"\n severity=\"warning\"\n action={\n <Button color=\"inherit\" size=\"small\" onClick={offline.dismissNotices}>\n {'Dismiss'}\n </Button>\n }\n >\n <AlertTitle>{'Synced, with something to check'}</AlertTitle>\n <Stack spacing={0.5}>\n {offline.notices.map((notice) => (\n <Typography key={notice.saleKey} variant=\"body2\">\n {`Order ${notice.number ? `#${notice.number}` : notice.orderId}: ` +\n [\n ...notice.stockConflicts.map(\n (conflict) => `${conflict.shortUnits} of ${conflict.requested}× ${conflict.name} not in stock`,\n ),\n ...posOfflineFlagLabels(notice.flags.filter((flag) => flag !== 'stock-short')),\n ].join('; ')}\n </Typography>\n ))}\n </Stack>\n </Alert>,\n )\n }\n\n if (!alerts.length) return null\n return <Stack spacing={1}>{alerts}</Stack>\n}\nPosOfflineBanner.displayName = 'PosOfflineBanner'\n"],"names":["Alert","AlertTitle","Button","Stack","Typography","useConfirmationContext","posOfflineFlagLabels","usd","plural","count","one","many","PosOfflineBanner","props","offline","confirm","waiting","queue","filter","entry","state","refused","waitingCents","reduce","sum","sale","totals","totalCents","alerts","push","severity","role","ready","unavailableReason","length","variant","sx","mt","action","syncing","color","size","onClick","syncNow","syncError","confirmed","title","description","confirmationText","confirmationButtonProps","then","catch","discard","saleKey","Date","soldAtMs","toLocaleString","error","notices","dismissNotices","spacing","map","notice","number","orderId","stockConflicts","conflict","shortUnits","requested","name","flags","flag","join","displayName"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { PosOfflineRungSale, PosOfflineState } from './use-pos-offline';
2
+ import type { RegisterLine } from '../pos/pos-cart-panel.component';
3
+ export interface PosOfflineCheckoutProps {
4
+ open: boolean;
5
+ offline: PosOfflineState;
6
+ hostId: string;
7
+ lines: RegisterLine[];
8
+ discountPct: number;
9
+ customer?: {
10
+ email?: string | null;
11
+ name?: string | null;
12
+ kind?: string;
13
+ id?: string;
14
+ } | null;
15
+ registerName?: string;
16
+ cashierName?: string;
17
+ onClose: () => void;
18
+ /** The sale is on the device; the basket can be cleared. */
19
+ onRung: (rung: PosOfflineRungSale) => void;
20
+ /** The cashier is done with the receipt step. */
21
+ onDone: () => void;
22
+ }
23
+ /** Prints an offline sale's receipt from what the register queued. */
24
+ export declare function printPosOfflineReceipt(rung: PosOfflineRungSale, kit: PosOfflineState['kit'], hostId: string, options?: {
25
+ gift?: boolean;
26
+ registerName?: string;
27
+ cashierName?: string;
28
+ }): void;
29
+ export declare function PosOfflineCheckout(props: PosOfflineCheckoutProps): import("react").JSX.Element;
30
+ export declare namespace PosOfflineCheckout {
31
+ var displayName: string;
32
+ }