@aglyn/plugins-commerce 1.0.0-beta.231 → 1.0.0-beta.233

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 (266) 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/catalog-organization-card.component.js +1 -0
  13. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  14. package/src/lib/components/console/host-orders-card.component.js +42 -11
  15. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  16. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  17. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  18. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  19. package/src/lib/components/console/locations-card.component.js +177 -3
  20. package/src/lib/components/console/locations-card.component.js.map +1 -1
  21. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  22. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  24. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  25. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  26. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  27. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  28. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  30. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  31. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  32. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  33. package/src/lib/components/console/pos/pos-api.js +13 -0
  34. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  35. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  36. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  37. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  39. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  40. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  42. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  43. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  44. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  45. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  46. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  47. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  48. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  49. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  50. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  51. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  52. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  53. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  54. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  55. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  56. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  57. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  65. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  66. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  68. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  69. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  71. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  72. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  74. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  75. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  86. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  87. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  88. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  89. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  90. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  92. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  93. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  94. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  95. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  96. package/src/lib/components/console/pos-page.component.js +228 -51
  97. package/src/lib/components/console/pos-page.component.js.map +1 -1
  98. package/src/lib/components/console/pos-zones.d.ts +23 -0
  99. package/src/lib/components/console/pos-zones.js +31 -0
  100. package/src/lib/components/console/pos-zones.js.map +1 -0
  101. package/src/lib/components/console/product-editor-dialog.component.js +10 -64
  102. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  103. package/src/lib/components/console/products-hub-card.component.js +46 -30
  104. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  105. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  106. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  107. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  108. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  109. package/src/lib/components/console/store-zones.d.ts +8 -1
  110. package/src/lib/components/console/store-zones.js +11 -1
  111. package/src/lib/components/console/store-zones.js.map +1 -1
  112. package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
  113. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
  114. package/src/lib/components/order-status.js +66 -0
  115. package/src/lib/components/order-status.js.map +1 -1
  116. package/src/lib/components/product-detail.js +42 -15
  117. package/src/lib/components/product-detail.js.map +1 -1
  118. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  119. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  120. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  121. package/src/lib/constants/orders-list-query.d.ts +7 -2
  122. package/src/lib/constants/orders-list-query.js +89 -8
  123. package/src/lib/constants/orders-list-query.js.map +1 -1
  124. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  125. package/src/lib/constants/pos-shift-list-query.js +115 -0
  126. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  127. package/src/lib/constants/product-list-query.d.ts +6 -1
  128. package/src/lib/constants/product-list-query.js +77 -8
  129. package/src/lib/constants/product-list-query.js.map +1 -1
  130. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  131. package/src/lib/constants/stock-movement-query.js +52 -8
  132. package/src/lib/constants/stock-movement-query.js.map +1 -1
  133. package/src/lib/declarations.server.js +21 -0
  134. package/src/lib/declarations.server.js.map +1 -1
  135. package/src/lib/model/buyer-notifications.d.ts +5 -3
  136. package/src/lib/model/buyer-notifications.js +25 -4
  137. package/src/lib/model/buyer-notifications.js.map +1 -1
  138. package/src/lib/model/commerce-orders.d.ts +103 -1
  139. package/src/lib/model/commerce-orders.js +2 -1
  140. package/src/lib/model/commerce-orders.js.map +1 -1
  141. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  142. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  143. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  144. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  145. package/src/lib/model/commerce-pos-offline.js +301 -0
  146. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  147. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  148. package/src/lib/model/commerce-pos-ops.js +12 -4
  149. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  150. package/src/lib/model/commerce-pos.d.ts +13 -1
  151. package/src/lib/model/commerce-pos.js +5 -4
  152. package/src/lib/model/commerce-pos.js.map +1 -1
  153. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  154. package/src/lib/model/commerce-stock-holds.js +26 -8
  155. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  156. package/src/lib/model/commerce.d.ts +7 -1
  157. package/src/lib/model/commerce.js.map +1 -1
  158. package/src/lib/model/index.d.ts +5 -0
  159. package/src/lib/model/index.js +5 -0
  160. package/src/lib/model/index.js.map +1 -1
  161. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  162. package/src/lib/model/local-fulfillment-settings.js +361 -0
  163. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  164. package/src/lib/model/order-list-fields.d.ts +10 -1
  165. package/src/lib/model/order-list-fields.js +1 -0
  166. package/src/lib/model/order-list-fields.js.map +1 -1
  167. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  168. package/src/lib/model/order-local-fulfillment.js +125 -0
  169. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  170. package/src/lib/model/order-shipping-export.js +4 -0
  171. package/src/lib/model/order-shipping-export.js.map +1 -1
  172. package/src/lib/model/order-status-view.d.ts +20 -1
  173. package/src/lib/model/order-status-view.js +60 -6
  174. package/src/lib/model/order-status-view.js.map +1 -1
  175. package/src/lib/model/product-write.d.ts +186 -0
  176. package/src/lib/model/product-write.js +116 -0
  177. package/src/lib/model/product-write.js.map +1 -0
  178. package/src/lib/plugin-config.js +6 -2
  179. package/src/lib/plugin-config.js.map +1 -1
  180. package/src/lib/plugin.js +11 -0
  181. package/src/lib/plugin.js.map +1 -1
  182. package/src/lib/pos-kiosk-config.d.ts +26 -0
  183. package/src/lib/pos-kiosk-config.js +59 -0
  184. package/src/lib/pos-kiosk-config.js.map +1 -0
  185. package/src/lib/server/api-v1/openapi.js +8 -0
  186. package/src/lib/server/api-v1/openapi.js.map +1 -1
  187. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  188. package/src/lib/server/api-v1/order-view.js +35 -0
  189. package/src/lib/server/api-v1/order-view.js.map +1 -1
  190. package/src/lib/server/billing-webhook.js +238 -87
  191. package/src/lib/server/billing-webhook.js.map +1 -1
  192. package/src/lib/server/cart-checkout.d.ts +2 -0
  193. package/src/lib/server/cart-checkout.js +173 -13
  194. package/src/lib/server/cart-checkout.js.map +1 -1
  195. package/src/lib/server/channel-order-updates.d.ts +50 -0
  196. package/src/lib/server/channel-order-updates.js +290 -0
  197. package/src/lib/server/channel-order-updates.js.map +1 -0
  198. package/src/lib/server/channel-orders.d.ts +85 -0
  199. package/src/lib/server/channel-orders.js +543 -0
  200. package/src/lib/server/channel-orders.js.map +1 -0
  201. package/src/lib/server/checkout-extras.js +18 -4
  202. package/src/lib/server/checkout-extras.js.map +1 -1
  203. package/src/lib/server/checkout.js +71 -14
  204. package/src/lib/server/checkout.js.map +1 -1
  205. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  206. package/src/lib/server/local-fulfillment-status.js +379 -0
  207. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  208. package/src/lib/server/local-fulfillment.d.ts +190 -0
  209. package/src/lib/server/local-fulfillment.js +580 -0
  210. package/src/lib/server/local-fulfillment.js.map +1 -0
  211. package/src/lib/server/membership-register.js +3 -1
  212. package/src/lib/server/membership-register.js.map +1 -1
  213. package/src/lib/server/order-notifications.js +61 -0
  214. package/src/lib/server/order-notifications.js.map +1 -1
  215. package/src/lib/server/pos-display.d.ts +27 -1
  216. package/src/lib/server/pos-display.js +50 -9
  217. package/src/lib/server/pos-display.js.map +1 -1
  218. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  219. package/src/lib/server/pos-kiosk-principal.js +42 -0
  220. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  221. package/src/lib/server/pos-kiosk.d.ts +54 -0
  222. package/src/lib/server/pos-kiosk.js +972 -0
  223. package/src/lib/server/pos-kiosk.js.map +1 -0
  224. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  225. package/src/lib/server/pos-offline-sync.js +765 -0
  226. package/src/lib/server/pos-offline-sync.js.map +1 -0
  227. package/src/lib/server/pos-order.js +22 -4
  228. package/src/lib/server/pos-order.js.map +1 -1
  229. package/src/lib/server/pos-payment.d.ts +6 -0
  230. package/src/lib/server/pos-payment.js +225 -6
  231. package/src/lib/server/pos-payment.js.map +1 -1
  232. package/src/lib/server/pos-print.js +5 -0
  233. package/src/lib/server/pos-print.js.map +1 -1
  234. package/src/lib/server/pos-return.js +27 -0
  235. package/src/lib/server/pos-return.js.map +1 -1
  236. package/src/lib/server/pos-sale.d.ts +6 -0
  237. package/src/lib/server/pos-sale.js +2 -0
  238. package/src/lib/server/pos-sale.js.map +1 -1
  239. package/src/lib/server/pos-shift.js +8 -1
  240. package/src/lib/server/pos-shift.js.map +1 -1
  241. package/src/lib/server/product-catalog.js +5 -1
  242. package/src/lib/server/product-catalog.js.map +1 -1
  243. package/src/lib/server/product-drafts.d.ts +5 -1
  244. package/src/lib/server/product-drafts.js +3 -3
  245. package/src/lib/server/product-drafts.js.map +1 -1
  246. package/src/lib/server/product-writer.d.ts +19 -0
  247. package/src/lib/server/product-writer.js +261 -0
  248. package/src/lib/server/product-writer.js.map +1 -0
  249. package/src/lib/server/products-write.d.ts +61 -0
  250. package/src/lib/server/products-write.js +375 -0
  251. package/src/lib/server/products-write.js.map +1 -0
  252. package/src/lib/server/refund.js +3 -0
  253. package/src/lib/server/refund.js.map +1 -1
  254. package/src/lib/server/stock-hold.d.ts +9 -1
  255. package/src/lib/server/stock-hold.js +15 -7
  256. package/src/lib/server/stock-hold.js.map +1 -1
  257. package/src/lib/server.js +21 -0
  258. package/src/lib/server.js.map +1 -1
  259. package/src/lib/tenant-emails.js +161 -0
  260. package/src/lib/tenant-emails.js.map +1 -1
  261. package/src/lib/testing/memory-firestore.d.ts +16 -3
  262. package/src/lib/testing/memory-firestore.js +11 -3
  263. package/src/lib/testing/memory-firestore.js.map +1 -1
  264. package/src/lib/transfer/products.server.d.ts +5 -0
  265. package/src/lib/transfer/products.server.js +2 -2
  266. package/src/lib/transfer/products.server.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/pos-tender-panel.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 {\n Alert,\n Box,\n Button,\n Chip,\n Divider,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport * as CommerceModel from '../../../model'\nimport {\n centsFromInput,\n newAttemptKey,\n posGiftCardBalance,\n posNativeBridge,\n posTender,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n type PosTenderAction,\n type PosTenderResult,\n} from './pos-api'\nimport { POS_TOUCH_PX } from './pos-product-grid.component'\nimport {\n PosCashDialog,\n PosFolioDialog,\n PosGiftCardDialog,\n PosKeyedCardDialog,\n PosQrDialog,\n} from './pos-tender-dialogs.component'\nimport type { PosDisplayControl } from './use-pos-display'\n\ntype User = Parameters<typeof posTender>[0]\n\nconst STATUS_LABEL: Record<CommerceModel.OrderPaymentStatus, string> = {\n pending: 'Waiting',\n succeeded: 'Approved',\n failed: 'Declined',\n canceled: 'Canceled',\n reversed: 'Returned',\n}\n\nconst STATUS_COLOR: Record<\n CommerceModel.OrderPaymentStatus,\n 'default' | 'success' | 'error' | 'warning' | 'info'\n> = {\n pending: 'info',\n succeeded: 'success',\n failed: 'error',\n canceled: 'default',\n reversed: 'warning',\n}\n\nexport interface PosTenderPanelProps {\n user: User\n hostId: string\n registerId: string\n sale: PosSaleSummary\n context: PosRegisterContext | null\n stays: any[]\n display: PosDisplayControl\n onSale: (sale: PosSaleSummary) => void\n /** The sale is voided: the basket is the cashier's again. */\n onVoided: () => void\n /** The tip chosen for the next payment, before it is taken. */\n onTipChange?: (tipCents: number) => void\n /** A PIN-switched cashier (AGL-3609) takes each payment they start. */\n cashierAssertion?: string\n notify: (message: string, variant: 'success' | 'error' | 'warning' | 'info') => void\n}\n\n/**\n * Taking payment on an open sale (AGL-3607): the balance due, every payment\n * taken so far with its live status, and the tenders. A sale can take as many\n * payments as it needs; it is paid when the balance reaches zero, and only\n * then does the server take the stock and complete it.\n */\nexport function PosTenderPanel(props: PosTenderPanelProps) {\n const { user, hostId, sale, context, display, onSale, notify } = props\n const settings = context?.settings\n const [amount, setAmount] = useState('')\n const [tipCents, setTipCents] = useState(0)\n const [busy, setBusy] = useState(false)\n const [dialog, setDialog] = useState<'cash' | 'gift' | 'folio' | null>(null)\n const [qr, setQr] = useState<{ url: string; amountCents: number } | null>(null)\n const [keyed, setKeyed] = useState<{ clientSecret: string; amountCents: number; paymentId: string } | null>(\n null,\n )\n const [readerId, setReaderId] = useState('')\n const inFlight = useRef(false)\n const { confirm } = useConfirmationContext()\n const { onTipChange } = props\n useEffect(() => {\n onTipChange?.(tipCents)\n }, [onTipChange, tipCents])\n\n const readers = (context?.readers ?? []).filter(\n (reader) => !reader.registerId || reader.registerId === props.registerId,\n )\n useEffect(() => {\n if (!readerId && readers.length) {\n setReaderId(readers.find((reader) => reader.registerId === props.registerId)?.id ?? readers[0].id)\n }\n }, [readerId, readers, props.registerId])\n\n // The amount defaults to whatever is still open; a split is the cashier\n // typing less than that.\n const typedCents = centsFromInput(amount)\n const chargeCents = typedCents > 0 ? Math.min(typedCents, sale.tenderableCents) : sale.tenderableCents\n const paid = sale.status === 'paid'\n\n const run = useCallback(\n async (\n action: PosTenderAction,\n body: Record<string, unknown> = {},\n starts = false,\n ): Promise<PosTenderResult | null> => {\n if (inFlight.current) return null\n inFlight.current = true\n setBusy(true)\n try {\n const result = await posTender(\n user,\n hostId,\n sale.orderId,\n action,\n starts && props.cashierAssertion ? { ...body, cashierAssertion: props.cashierAssertion } : body,\n starts ? newAttemptKey() : undefined,\n )\n onSale(result.sale)\n if (starts) {\n setAmount('')\n setTipCents(0)\n }\n return result\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Something went wrong', 'error')\n return null\n } finally {\n inFlight.current = false\n setBusy(false)\n }\n },\n [user, hostId, sale.orderId, onSale, notify, props.cashierAssertion],\n )\n\n // Card payments still waiting are checked every two seconds: the reader,\n // the QR page and the typed card all settle on the server, and this is the\n // register's view of it (the webhook does the same thing when it lands).\n const pending = sale.payments.filter(\n (payment) => payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method),\n )\n const pendingKey = pending.map((payment) => payment.id).join(',')\n const latest = useRef({ user, onSale })\n latest.current = { user, onSale }\n useEffect(() => {\n if (!pendingKey) return undefined\n const timer = setInterval(async () => {\n for (const id of pendingKey.split(',')) {\n try {\n const result = await posTender(latest.current.user, hostId, sale.orderId, 'status', {\n paymentId: id,\n })\n latest.current.onSale(result.sale)\n } catch {\n // The next tick asks again.\n }\n }\n }, 2000)\n return () => clearInterval(timer)\n }, [pendingKey, hostId, sale.orderId])\n\n // The display shows \"tap your card\" while a reader payment waits, and the\n // running balance otherwise.\n const readerWaiting = pending.some((payment) => payment.method === 'card_present')\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (readerWaiting) {\n void display.show({ mode: 'processing', processing: { message: 'Tap, insert or swipe your card on the reader.' } })\n }\n }, [readerWaiting, display])\n\n const askTip = useCallback(async () => {\n const base = chargeCents\n if (!(base > 0) || !settings) return\n const answer = await display.ask({\n mode: 'tip',\n tip: { baseCents: base, percentages: settings.tipPercentages, allowCustom: true },\n })\n if (answer) {\n setTipCents(answer.tipCents ?? 0)\n notify(answer.tipCents ? `Tip: ${usd(answer.tipCents)}` : 'No tip', 'info')\n }\n }, [chargeCents, settings, display, notify])\n\n const startCardPresent = useCallback(async () => {\n if (!readerId) return\n await run('card-present', { amountCents: chargeCents, tipCents, readerId }, true)\n }, [run, chargeCents, tipCents, readerId])\n\n const startBridge = useCallback(async () => {\n const bridge = posNativeBridge()\n if (!bridge) return\n const amountCents = chargeCents\n const result = await run('card-present-sdk', { amountCents, tipCents }, true)\n if (!result?.paymentIntentId || !result.clientSecret || !result.paymentId) return\n try {\n const collected = await bridge.collectCardPayment({\n paymentIntentId: result.paymentIntentId,\n clientSecret: result.clientSecret,\n amountCents: amountCents + tipCents,\n })\n if (collected.status !== 'collected') {\n notify(collected.message ?? 'The card was not taken.', 'warning')\n }\n } finally {\n // Settled by the server either way: the status poll captures an\n // authorized tap and records a decline or a cancel.\n await run('status', { paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents, notify])\n\n const startKeyed = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-keyed', { amountCents, tipCents }, true)\n if (result?.clientSecret && result.paymentId) {\n setKeyed({ clientSecret: result.clientSecret, amountCents: amountCents + tipCents, paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents])\n\n const startLink = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-link', { amountCents, tipCents }, true)\n const url = result?.sale.payments.find((payment) => payment.id === result.paymentId)?.checkoutUrl\n if (url) setQr({ url, amountCents: amountCents + tipCents })\n }, [run, chargeCents, tipCents])\n\n const tipOn = Boolean(settings?.tippingEnabled) && !paid\n\n return (\n <Stack spacing={1.5} sx={{ minHeight: 0 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>\n <Typography variant=\"h6\">{paid ? 'Paid' : 'Balance due'}</Typography>\n <Typography variant=\"h4\" component=\"p\">\n {usd(paid ? sale.totalCents : sale.dueCents)}\n </Typography>\n </Box>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Total ${usd(sale.totalCents)} · paid ${usd(sale.paidCents)}` +\n (sale.tipCents ? ` · tips ${usd(sale.tipCents)}` : '')}\n </Typography>\n\n {sale.payments.length ? (\n <Stack spacing={1} aria-label=\"Payments\">\n {sale.payments.map((payment) => (\n <Box key={payment.id} sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 140 }}>\n {CommerceModel.describeOrderPayment({ ...payment, atMs: 0 })}\n {payment.changeCents ? ` · change ${usd(payment.changeCents)}` : ''}\n </Typography>\n <Chip size=\"small\" label={STATUS_LABEL[payment.status]} color={STATUS_COLOR[payment.status]} />\n {payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method) ? (\n <>\n {payment.method === 'card_link' && payment.checkoutUrl ? (\n <Button\n size=\"small\"\n onClick={() => setQr({ url: payment.checkoutUrl as string, amountCents: payment.amountCents })}\n >\n {'Show QR'}\n </Button>\n ) : null}\n {payment.method === 'card_present' && payment.livemode === false && context?.terminal?.testMode ? (\n <Button size=\"small\" onClick={() => void run('simulate', { paymentId: payment.id })}>\n {'Simulate tap'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={() => void run('cancel', { paymentId: payment.id })}>\n {'Cancel'}\n </Button>\n </>\n ) : null}\n {payment.status === 'failed' && payment.method === 'card_present' && !paid ? (\n <Button size=\"small\" onClick={() => void run('retry', { paymentId: payment.id })}>\n {'Retry'}\n </Button>\n ) : null}\n {payment.failureMessage && payment.status === 'failed' ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ width: 1 }}>\n {payment.failureMessage}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : null}\n\n {!paid ? (\n <>\n <Divider />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n label=\"Amount to charge ($)\"\n placeholder={(sale.tenderableCents / 100).toFixed(2)}\n value={amount}\n onChange={(event) => setAmount(event.target.value.replace(/[^0-9.]/g, ''))}\n sx={{ flex: 1 }}\n helperText={\n typedCents > 0 && typedCents < sale.tenderableCents\n ? `Split: ${usd(sale.tenderableCents - typedCents)} stays open`\n : ' '\n }\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n {tipOn ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"body2\" sx={{ mr: 1 }}>\n {`Tip ${usd(tipCents)}`}\n </Typography>\n {display.connected ? (\n <Button\n variant=\"outlined\"\n onClick={() => void askTip()}\n disabled={busy || Boolean(display.asking)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {display.asking === 'tip' ? 'Waiting for customer…' : 'Ask on display'}\n </Button>\n ) : null}\n {(settings?.tipPercentages ?? []).map((pct) => (\n <Button\n key={pct}\n variant={tipCents === CommerceModel.posTipFromPercent(chargeCents, pct) && tipCents > 0 ? 'contained' : 'outlined'}\n onClick={() => setTipCents(CommerceModel.posTipFromPercent(chargeCents, pct))}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {`${pct}%`}\n </Button>\n ))}\n <Button onClick={() => setTipCents(0)} sx={{ minHeight: POS_TOUCH_PX }}>\n {'No tip'}\n </Button>\n </Stack>\n ) : null}\n <Box\n sx={{\n display: 'grid',\n gap: 1,\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n }}\n >\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('cash')}\n sx={{ minHeight: 56 }}\n >\n {'Cash'}\n </Button>\n {context?.terminal?.available && readers.length ? (\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0 || !readerId}\n onClick={() => void startCardPresent()}\n sx={{ minHeight: 56 }}\n >\n {'Card reader'}\n </Button>\n ) : null}\n {posNativeBridge() ? (\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startBridge()}\n sx={{ minHeight: 56 }}\n >\n {'Tap to Pay / Bluetooth reader'}\n </Button>\n ) : null}\n {context?.publishableKey ? (\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startKeyed()}\n sx={{ minHeight: 56 }}\n >\n {'Type card'}\n </Button>\n ) : null}\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startLink()}\n sx={{ minHeight: 56 }}\n >\n {'Card (QR)'}\n </Button>\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('gift')}\n sx={{ minHeight: 56 }}\n >\n {'Gift card'}\n </Button>\n {props.stays.length ? (\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('folio')}\n sx={{ minHeight: 56 }}\n >\n {'Room'}\n </Button>\n ) : null}\n </Box>\n {context?.terminal?.available && readers.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Card reader\"\n value={readerId}\n onChange={(event) => setReaderId(event.target.value)}\n >\n {readers.map((reader) => (\n <MenuItem key={reader.id} value={reader.id}>\n {`${reader.label}${reader.status === 'online' ? '' : ' (offline)'}`}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {readers.some((reader) => reader.id === readerId && reader.status !== 'online') ? (\n <Alert severity=\"warning\">{'The selected card reader looks offline.'}</Alert>\n ) : null}\n <Button\n color=\"error\"\n disabled={busy}\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Void this sale?',\n description:\n 'Every payment taken on it is handed back: cards are refunded, gift ' +\n 'cards re-credited and room charges removed. Hand back any cash.',\n confirmationText: 'Void sale',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const result = await run('void')\n if (result) {\n notify('Sale voided', 'info')\n props.onVoided()\n }\n }}\n sx={{ minHeight: POS_TOUCH_PX, alignSelf: 'flex-start' }}\n >\n {'Void sale'}\n </Button>\n </>\n ) : null}\n\n <PosCashDialog\n open={dialog === 'cash'}\n dueCents={chargeCents}\n tipCents={tipCents}\n busy={busy}\n onClose={() => setDialog(null)}\n onTake={async (tenderedCents) => {\n const result = await run(\n 'cash',\n {\n tenderedCents,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n tipCents,\n },\n true,\n )\n if (result) {\n setDialog(null)\n const change = result.sale.payments.find((payment) => payment.id === result.paymentId)?.changeCents\n if (change) notify(`Change due: ${usd(change)}`, 'success')\n }\n }}\n />\n <PosGiftCardDialog\n open={dialog === 'gift'}\n busy={busy}\n onClose={() => setDialog(null)}\n onCheck={async (code) => {\n try {\n return await posGiftCardBalance(user, hostId, code)\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not read that card', 'warning')\n return null\n }\n }}\n onApply={async (code) => {\n const result = await run('gift-card', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n />\n <PosFolioDialog\n open={dialog === 'folio'}\n amountCents={chargeCents}\n stays={props.stays}\n busy={busy}\n onClose={() => setDialog(null)}\n onCharge={async (reservationId) => {\n const result = await run(\n 'folio',\n { reservationId, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosQrDialog url={qr?.url ?? ''} amountCents={qr?.amountCents ?? 0} onClose={() => setQr(null)} />\n <PosKeyedCardDialog\n clientSecret={keyed?.clientSecret ?? ''}\n publishableKey={context?.publishableKey ?? ''}\n amountCents={keyed?.amountCents ?? 0}\n onClose={async () => {\n const open = keyed\n setKeyed(null)\n // Closing without paying releases the amount for another tender.\n if (open) await run('cancel', { paymentId: open.paymentId })\n }}\n onConfirmed={async () => {\n const open = keyed\n setKeyed(null)\n if (open) await run('status', { paymentId: open.paymentId })\n }}\n />\n </Stack>\n )\n}\nPosTenderPanel.displayName = 'PosTenderPanel'\n"],"names":["Alert","Box","Button","Chip","Divider","MenuItem","Stack","TextField","Typography","useConfirmationContext","useCallback","useEffect","useRef","useState","CommerceModel","centsFromInput","newAttemptKey","posGiftCardBalance","posNativeBridge","posTender","PosRequestError","usd","POS_TOUCH_PX","PosCashDialog","PosFolioDialog","PosGiftCardDialog","PosKeyedCardDialog","PosQrDialog","STATUS_LABEL","pending","succeeded","failed","canceled","reversed","STATUS_COLOR","PosTenderPanel","props","context","user","hostId","sale","display","onSale","notify","settings","amount","setAmount","tipCents","setTipCents","busy","setBusy","dialog","setDialog","qr","setQr","keyed","setKeyed","readerId","setReaderId","inFlight","confirm","onTipChange","readers","filter","reader","registerId","length","find","id","typedCents","chargeCents","Math","min","tenderableCents","paid","status","run","action","body","starts","current","result","orderId","cashierAssertion","undefined","error","message","payments","payment","isCardPaymentMethod","method","pendingKey","map","join","latest","timer","setInterval","split","paymentId","clearInterval","readerWaiting","some","connected","asking","show","mode","processing","askTip","base","answer","ask","tip","baseCents","percentages","tipPercentages","allowCustom","startCardPresent","amountCents","startBridge","bridge","paymentIntentId","clientSecret","collected","collectCardPayment","startKeyed","startLink","url","checkoutUrl","tipOn","Boolean","tippingEnabled","spacing","sx","minHeight","justifyContent","alignItems","variant","component","totalCents","dueCents","color","paidCents","aria-label","gap","flexWrap","flex","minWidth","describeOrderPayment","atMs","changeCents","size","label","onClick","livemode","terminal","testMode","failureMessage","width","direction","placeholder","toFixed","value","onChange","event","target","replace","helperText","slotProps","htmlInput","inputMode","rowGap","mr","disabled","pct","posTipFromPercent","gridTemplateColumns","available","publishableKey","stays","select","severity","confirmed","title","description","confirmationText","confirmationButtonProps","then","catch","onVoided","alignSelf","open","onClose","onTake","tenderedCents","change","onCheck","code","onApply","onCharge","reservationId","onConfirmed","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/pos-tender-panel.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 {\n Alert,\n Box,\n Button,\n Chip,\n Divider,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport * as CommerceModel from '../../../model'\nimport {\n centsFromInput,\n newAttemptKey,\n posCreditLookup,\n posGiftCardBalance,\n posNativeBridge,\n posTender,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n type PosTenderAction,\n type PosTenderResult,\n} from './pos-api'\nimport { POS_TOUCH_PX } from './pos-product-grid.component'\nimport {\n PosCashDialog,\n PosCreditDialog,\n PosFolioDialog,\n PosGiftCardDialog,\n PosKeyedCardDialog,\n PosQrDialog,\n} from './pos-tender-dialogs.component'\nimport type { PosDisplayControl } from './use-pos-display'\n\ntype User = Parameters<typeof posTender>[0]\n\nconst STATUS_LABEL: Record<CommerceModel.OrderPaymentStatus, string> = {\n pending: 'Waiting',\n succeeded: 'Approved',\n failed: 'Declined',\n canceled: 'Canceled',\n reversed: 'Returned',\n}\n\nconst STATUS_COLOR: Record<\n CommerceModel.OrderPaymentStatus,\n 'default' | 'success' | 'error' | 'warning' | 'info'\n> = {\n pending: 'info',\n succeeded: 'success',\n failed: 'error',\n canceled: 'default',\n reversed: 'warning',\n}\n\nexport interface PosTenderPanelProps {\n user: User\n hostId: string\n registerId: string\n sale: PosSaleSummary\n context: PosRegisterContext | null\n stays: any[]\n display: PosDisplayControl\n onSale: (sale: PosSaleSummary) => void\n /** The sale is voided: the basket is the cashier's again. */\n onVoided: () => void\n /** The tip chosen for the next payment, before it is taken. */\n onTipChange?: (tipCents: number) => void\n /** A PIN-switched cashier (AGL-3609) takes each payment they start. */\n cashierAssertion?: string\n notify: (message: string, variant: 'success' | 'error' | 'warning' | 'info') => void\n /**\n * The register is offline (AGL-3625). Every tender here is the server's —\n * the card reader, the typed card, the QR link, the gift card, the room\n * charge and this sale's own cash — so each is off until it returns.\n */\n offline?: boolean\n /** Rings this basket as an offline cash sale instead; offered while nothing is paid. */\n onSellOffline?: () => void\n}\n\n/**\n * Taking payment on an open sale (AGL-3607): the balance due, every payment\n * taken so far with its live status, and the tenders. A sale can take as many\n * payments as it needs; it is paid when the balance reaches zero, and only\n * then does the server take the stock and complete it.\n */\nexport function PosTenderPanel(props: PosTenderPanelProps) {\n const { user, hostId, sale, context, display, onSale, notify } = props\n const settings = context?.settings\n const [amount, setAmount] = useState('')\n const [tipCents, setTipCents] = useState(0)\n const [busy, setBusy] = useState(false)\n const [dialog, setDialog] = useState<'cash' | 'gift' | 'folio' | 'credit' | null>(null)\n // The store-credit provider whose dialog is open (AGL-3640).\n const [creditProvider, setCreditProvider] = useState<{ providerId: string; label: string; lookup: boolean } | null>(\n null,\n )\n const [qr, setQr] = useState<{ url: string; amountCents: number } | null>(null)\n const [keyed, setKeyed] = useState<{ clientSecret: string; amountCents: number; paymentId: string } | null>(\n null,\n )\n const [readerId, setReaderId] = useState('')\n const inFlight = useRef(false)\n const { confirm } = useConfirmationContext()\n const { onTipChange } = props\n useEffect(() => {\n onTipChange?.(tipCents)\n }, [onTipChange, tipCents])\n\n const readers = (context?.readers ?? []).filter(\n (reader) => !reader.registerId || reader.registerId === props.registerId,\n )\n useEffect(() => {\n if (!readerId && readers.length) {\n setReaderId(readers.find((reader) => reader.registerId === props.registerId)?.id ?? readers[0].id)\n }\n }, [readerId, readers, props.registerId])\n\n // The amount defaults to whatever is still open; a split is the cashier\n // typing less than that.\n const typedCents = centsFromInput(amount)\n const chargeCents = typedCents > 0 ? Math.min(typedCents, sale.tenderableCents) : sale.tenderableCents\n const paid = sale.status === 'paid'\n const offline = props.offline === true\n\n const run = useCallback(\n async (\n action: PosTenderAction,\n body: Record<string, unknown> = {},\n starts = false,\n ): Promise<PosTenderResult | null> => {\n if (inFlight.current) return null\n inFlight.current = true\n setBusy(true)\n try {\n const result = await posTender(\n user,\n hostId,\n sale.orderId,\n action,\n starts && props.cashierAssertion ? { ...body, cashierAssertion: props.cashierAssertion } : body,\n starts ? newAttemptKey() : undefined,\n )\n onSale(result.sale)\n if (starts) {\n setAmount('')\n setTipCents(0)\n }\n return result\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Something went wrong', 'error')\n return null\n } finally {\n inFlight.current = false\n setBusy(false)\n }\n },\n [user, hostId, sale.orderId, onSale, notify, props.cashierAssertion],\n )\n\n // Card payments still waiting are checked every two seconds: the reader,\n // the QR page and the typed card all settle on the server, and this is the\n // register's view of it (the webhook does the same thing when it lands).\n const pending = sale.payments.filter(\n (payment) => payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method),\n )\n const pendingKey = pending.map((payment) => payment.id).join(',')\n const latest = useRef({ user, onSale })\n latest.current = { user, onSale }\n useEffect(() => {\n if (!pendingKey) return undefined\n const timer = setInterval(async () => {\n for (const id of pendingKey.split(',')) {\n try {\n const result = await posTender(latest.current.user, hostId, sale.orderId, 'status', {\n paymentId: id,\n })\n latest.current.onSale(result.sale)\n } catch {\n // The next tick asks again.\n }\n }\n }, 2000)\n return () => clearInterval(timer)\n }, [pendingKey, hostId, sale.orderId])\n\n // The display shows \"tap your card\" while a reader payment waits, and the\n // running balance otherwise.\n const readerWaiting = pending.some((payment) => payment.method === 'card_present')\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (readerWaiting) {\n void display.show({ mode: 'processing', processing: { message: 'Tap, insert or swipe your card on the reader.' } })\n }\n }, [readerWaiting, display])\n\n const askTip = useCallback(async () => {\n const base = chargeCents\n if (!(base > 0) || !settings) return\n const answer = await display.ask({\n mode: 'tip',\n tip: { baseCents: base, percentages: settings.tipPercentages, allowCustom: true },\n })\n if (answer) {\n setTipCents(answer.tipCents ?? 0)\n notify(answer.tipCents ? `Tip: ${usd(answer.tipCents)}` : 'No tip', 'info')\n }\n }, [chargeCents, settings, display, notify])\n\n const startCardPresent = useCallback(async () => {\n if (!readerId) return\n await run('card-present', { amountCents: chargeCents, tipCents, readerId }, true)\n }, [run, chargeCents, tipCents, readerId])\n\n const startBridge = useCallback(async () => {\n const bridge = posNativeBridge()\n if (!bridge) return\n const amountCents = chargeCents\n const result = await run('card-present-sdk', { amountCents, tipCents }, true)\n if (!result?.paymentIntentId || !result.clientSecret || !result.paymentId) return\n try {\n const collected = await bridge.collectCardPayment({\n paymentIntentId: result.paymentIntentId,\n clientSecret: result.clientSecret,\n amountCents: amountCents + tipCents,\n })\n if (collected.status !== 'collected') {\n notify(collected.message ?? 'The card was not taken.', 'warning')\n }\n } finally {\n // Settled by the server either way: the status poll captures an\n // authorized tap and records a decline or a cancel.\n await run('status', { paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents, notify])\n\n const startKeyed = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-keyed', { amountCents, tipCents }, true)\n if (result?.clientSecret && result.paymentId) {\n setKeyed({ clientSecret: result.clientSecret, amountCents: amountCents + tipCents, paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents])\n\n const startLink = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-link', { amountCents, tipCents }, true)\n const url = result?.sale.payments.find((payment) => payment.id === result.paymentId)?.checkoutUrl\n if (url) setQr({ url, amountCents: amountCents + tipCents })\n }, [run, chargeCents, tipCents])\n\n const tipOn = Boolean(settings?.tippingEnabled) && !paid\n\n return (\n <Stack spacing={1.5} sx={{ minHeight: 0 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>\n <Typography variant=\"h6\">{paid ? 'Paid' : 'Balance due'}</Typography>\n <Typography variant=\"h4\" component=\"p\">\n {usd(paid ? sale.totalCents : sale.dueCents)}\n </Typography>\n </Box>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Total ${usd(sale.totalCents)} · paid ${usd(sale.paidCents)}` +\n (sale.tipCents ? ` · tips ${usd(sale.tipCents)}` : '')}\n </Typography>\n\n {sale.payments.length ? (\n <Stack spacing={1} aria-label=\"Payments\">\n {sale.payments.map((payment) => (\n <Box key={payment.id} sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 140 }}>\n {CommerceModel.describeOrderPayment({ ...payment, atMs: 0 })}\n {payment.changeCents ? ` · change ${usd(payment.changeCents)}` : ''}\n </Typography>\n <Chip size=\"small\" label={STATUS_LABEL[payment.status]} color={STATUS_COLOR[payment.status]} />\n {payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method) ? (\n <>\n {payment.method === 'card_link' && payment.checkoutUrl ? (\n <Button\n size=\"small\"\n onClick={() => setQr({ url: payment.checkoutUrl as string, amountCents: payment.amountCents })}\n >\n {'Show QR'}\n </Button>\n ) : null}\n {payment.method === 'card_present' && payment.livemode === false && context?.terminal?.testMode ? (\n <Button size=\"small\" onClick={() => void run('simulate', { paymentId: payment.id })}>\n {'Simulate tap'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={() => void run('cancel', { paymentId: payment.id })}>\n {'Cancel'}\n </Button>\n </>\n ) : null}\n {payment.status === 'failed' && payment.method === 'card_present' && !paid ? (\n <Button size=\"small\" onClick={() => void run('retry', { paymentId: payment.id })}>\n {'Retry'}\n </Button>\n ) : null}\n {payment.failureMessage && payment.status === 'failed' ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ width: 1 }}>\n {payment.failureMessage}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : null}\n\n {offline && !paid ? (\n <Alert\n severity=\"warning\"\n action={\n props.onSellOffline && sale.payments.length === 0 ? (\n <Button color=\"inherit\" size=\"small\" onClick={props.onSellOffline}>\n {'Sell for cash offline'}\n </Button>\n ) : null\n }\n >\n {sale.payments.length === 0\n ? 'Offline: card readers, typed cards, the QR link, gift cards, store credit and room charges are off. ' +\n 'Take this basket as an offline cash sale, or wait for the connection.'\n : 'Offline: this sale has a payment on it and finishes when the connection returns. ' +\n 'Card readers, typed cards, the QR link, gift cards, store credit and room charges are off.'}\n </Alert>\n ) : null}\n {!paid ? (\n <>\n <Divider />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n label=\"Amount to charge ($)\"\n placeholder={(sale.tenderableCents / 100).toFixed(2)}\n value={amount}\n onChange={(event) => setAmount(event.target.value.replace(/[^0-9.]/g, ''))}\n sx={{ flex: 1 }}\n helperText={\n typedCents > 0 && typedCents < sale.tenderableCents\n ? `Split: ${usd(sale.tenderableCents - typedCents)} stays open`\n : ' '\n }\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n {tipOn ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"body2\" sx={{ mr: 1 }}>\n {`Tip ${usd(tipCents)}`}\n </Typography>\n {display.connected ? (\n <Button\n variant=\"outlined\"\n onClick={() => void askTip()}\n disabled={offline || busy || Boolean(display.asking)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {display.asking === 'tip' ? 'Waiting for customer…' : 'Ask on display'}\n </Button>\n ) : null}\n {(settings?.tipPercentages ?? []).map((pct) => (\n <Button\n key={pct}\n variant={tipCents === CommerceModel.posTipFromPercent(chargeCents, pct) && tipCents > 0 ? 'contained' : 'outlined'}\n onClick={() => setTipCents(CommerceModel.posTipFromPercent(chargeCents, pct))}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {`${pct}%`}\n </Button>\n ))}\n <Button onClick={() => setTipCents(0)} sx={{ minHeight: POS_TOUCH_PX }}>\n {'No tip'}\n </Button>\n </Stack>\n ) : null}\n <Box\n sx={{\n display: 'grid',\n gap: 1,\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n }}\n >\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('cash')}\n sx={{ minHeight: 56 }}\n >\n {'Cash'}\n </Button>\n {context?.terminal?.available && readers.length ? (\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0 || !readerId}\n onClick={() => void startCardPresent()}\n sx={{ minHeight: 56 }}\n >\n {'Card reader'}\n </Button>\n ) : null}\n {posNativeBridge() ? (\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startBridge()}\n sx={{ minHeight: 56 }}\n >\n {'Tap to Pay / Bluetooth reader'}\n </Button>\n ) : null}\n {context?.publishableKey ? (\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startKeyed()}\n sx={{ minHeight: 56 }}\n >\n {'Type card'}\n </Button>\n ) : null}\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startLink()}\n sx={{ minHeight: 56 }}\n >\n {'Card (QR)'}\n </Button>\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('gift')}\n sx={{ minHeight: 56 }}\n >\n {'Gift card'}\n </Button>\n {(context?.credits ?? []).map((credit) => (\n <Button\n key={credit.providerId}\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => {\n setCreditProvider(credit)\n setDialog('credit')\n }}\n sx={{ minHeight: 56 }}\n >\n {credit.label}\n </Button>\n ))}\n {props.stays.length ? (\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('folio')}\n sx={{ minHeight: 56 }}\n >\n {'Room'}\n </Button>\n ) : null}\n </Box>\n {context?.terminal?.available && readers.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Card reader\"\n value={readerId}\n onChange={(event) => setReaderId(event.target.value)}\n >\n {readers.map((reader) => (\n <MenuItem key={reader.id} value={reader.id}>\n {`${reader.label}${reader.status === 'online' ? '' : ' (offline)'}`}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {readers.some((reader) => reader.id === readerId && reader.status !== 'online') ? (\n <Alert severity=\"warning\">{'The selected card reader looks offline.'}</Alert>\n ) : null}\n <Button\n color=\"error\"\n disabled={offline || busy}\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Void this sale?',\n description:\n 'Every payment taken on it is handed back: cards are refunded, gift ' +\n 'cards and store credit re-credited and room charges removed. Hand back any cash.',\n confirmationText: 'Void sale',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const result = await run('void')\n if (result) {\n notify('Sale voided', 'info')\n props.onVoided()\n }\n }}\n sx={{ minHeight: POS_TOUCH_PX, alignSelf: 'flex-start' }}\n >\n {'Void sale'}\n </Button>\n </>\n ) : null}\n\n <PosCashDialog\n open={dialog === 'cash'}\n dueCents={chargeCents}\n tipCents={tipCents}\n busy={busy}\n onClose={() => setDialog(null)}\n onTake={async (tenderedCents) => {\n const result = await run(\n 'cash',\n {\n tenderedCents,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n tipCents,\n },\n true,\n )\n if (result) {\n setDialog(null)\n const change = result.sale.payments.find((payment) => payment.id === result.paymentId)?.changeCents\n if (change) notify(`Change due: ${usd(change)}`, 'success')\n }\n }}\n />\n <PosGiftCardDialog\n open={dialog === 'gift'}\n busy={busy}\n onClose={() => setDialog(null)}\n onCheck={async (code) => {\n try {\n return await posGiftCardBalance(user, hostId, code)\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not read that card', 'warning')\n return null\n }\n }}\n onApply={async (code) => {\n const result = await run('gift-card', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n />\n <PosCreditDialog\n open={dialog === 'credit' && Boolean(creditProvider)}\n label={creditProvider?.label ?? 'Store credit'}\n canLookup={Boolean(creditProvider?.lookup)}\n busy={busy}\n onClose={() => setDialog(null)}\n onLookup={async (query) => {\n if (!creditProvider) return null\n try {\n return (await posCreditLookup(user, hostId, creditProvider.providerId, query)).accounts\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not look that up', 'warning')\n return null\n }\n }}\n onApplyCode={async (code) => {\n const result = await run('credit', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n onApplyAccount={async (account) => {\n if (!creditProvider) return\n const result = await run(\n 'credit',\n {\n providerId: creditProvider.providerId,\n reference: account.reference,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosFolioDialog\n open={dialog === 'folio'}\n amountCents={chargeCents}\n stays={props.stays}\n busy={busy}\n onClose={() => setDialog(null)}\n onCharge={async (reservationId) => {\n const result = await run(\n 'folio',\n { reservationId, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosQrDialog url={qr?.url ?? ''} amountCents={qr?.amountCents ?? 0} onClose={() => setQr(null)} />\n <PosKeyedCardDialog\n clientSecret={keyed?.clientSecret ?? ''}\n publishableKey={context?.publishableKey ?? ''}\n amountCents={keyed?.amountCents ?? 0}\n onClose={async () => {\n const open = keyed\n setKeyed(null)\n // Closing without paying releases the amount for another tender.\n if (open) await run('cancel', { paymentId: open.paymentId })\n }}\n onConfirmed={async () => {\n const open = keyed\n setKeyed(null)\n if (open) await run('status', { paymentId: open.paymentId })\n }}\n />\n </Stack>\n )\n}\nPosTenderPanel.displayName = 'PosTenderPanel'\n"],"names":["Alert","Box","Button","Chip","Divider","MenuItem","Stack","TextField","Typography","useConfirmationContext","useCallback","useEffect","useRef","useState","CommerceModel","centsFromInput","newAttemptKey","posCreditLookup","posGiftCardBalance","posNativeBridge","posTender","PosRequestError","usd","POS_TOUCH_PX","PosCashDialog","PosCreditDialog","PosFolioDialog","PosGiftCardDialog","PosKeyedCardDialog","PosQrDialog","STATUS_LABEL","pending","succeeded","failed","canceled","reversed","STATUS_COLOR","PosTenderPanel","props","context","user","hostId","sale","display","onSale","notify","settings","amount","setAmount","tipCents","setTipCents","busy","setBusy","dialog","setDialog","creditProvider","setCreditProvider","qr","setQr","keyed","setKeyed","readerId","setReaderId","inFlight","confirm","onTipChange","readers","filter","reader","registerId","length","find","id","typedCents","chargeCents","Math","min","tenderableCents","paid","status","offline","run","action","body","starts","current","result","orderId","cashierAssertion","undefined","error","message","payments","payment","isCardPaymentMethod","method","pendingKey","map","join","latest","timer","setInterval","split","paymentId","clearInterval","readerWaiting","some","connected","asking","show","mode","processing","askTip","base","answer","ask","tip","baseCents","percentages","tipPercentages","allowCustom","startCardPresent","amountCents","startBridge","bridge","paymentIntentId","clientSecret","collected","collectCardPayment","startKeyed","startLink","url","checkoutUrl","tipOn","Boolean","tippingEnabled","spacing","sx","minHeight","justifyContent","alignItems","variant","component","totalCents","dueCents","color","paidCents","aria-label","gap","flexWrap","flex","minWidth","describeOrderPayment","atMs","changeCents","size","label","onClick","livemode","terminal","testMode","failureMessage","width","severity","onSellOffline","direction","placeholder","toFixed","value","onChange","event","target","replace","helperText","slotProps","htmlInput","inputMode","rowGap","mr","disabled","pct","posTipFromPercent","gridTemplateColumns","available","publishableKey","credits","credit","providerId","stays","select","confirmed","title","description","confirmationText","confirmationButtonProps","then","catch","onVoided","alignSelf","open","onClose","onTake","tenderedCents","change","onCheck","code","onApply","canLookup","lookup","onLookup","query","accounts","onApplyCode","onApplyAccount","account","reference","onCharge","reservationId","onConfirmed","displayName"],"mappings":"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"}
@@ -27,8 +27,11 @@ export interface PosDisplayControl {
27
27
  */
28
28
  ask: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<CommerceModel.PosDisplayResponse | null>;
29
29
  cancelAsk: () => void;
30
- /** A fresh six-digit pairing code for a new display. */
31
- pairingCode: () => Promise<{
30
+ /**
31
+ * A fresh six-digit pairing code for a new customer display, or for a
32
+ * self-service kiosk (AGL-3623).
33
+ */
34
+ pairingCode: (mode?: CommerceModel.PosDeviceMode) => Promise<{
32
35
  code: string;
33
36
  expiresAtMs: number;
34
37
  }>;
@@ -135,12 +135,13 @@ import { newAttemptKey, posDisplayCall } from "./pos-api.js";
135
135
  hostId,
136
136
  registerId
137
137
  ]);
138
- const pairingCode = useCallback(async ()=>{
138
+ const pairingCode = useCallback(async (mode = 'display')=>{
139
139
  if (!user) throw new Error('Not signed in');
140
140
  const result = await posDisplayCall(user, {
141
141
  action: 'pairing-code',
142
142
  hostId,
143
- registerId
143
+ registerId,
144
+ mode
144
145
  });
145
146
  return result;
146
147
  }, [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/use-pos-display.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'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { newAttemptKey, posDisplayCall } from './pos-api'\n\ntype User = Parameters<typeof posDisplayCall>[0]\n\n/**\n * The tip the customer screen shows beside the sale (AGL-3608): the tips\n * already on its payments, plus one chosen for the payment about to be taken\n * (on the display or by the cashier), which the ledger does not hold until\n * that payment is recorded. Without the second part the screen read the\n * sale's total right after the customer added a tip, short by that tip.\n */\nexport function posDisplayTipCents(\n sale: { status: string; tipCents: number } | null | undefined,\n pendingTipCents: number,\n): number {\n if (!sale) return 0\n const pending = sale.status === 'paid' ? 0 : Math.max(0, Math.round(pendingTipCents) || 0)\n return Math.max(0, sale.tipCents) + pending\n}\n\n/** How long the register waits for the customer to answer a prompt. */\nexport const POS_DISPLAY_ANSWER_TIMEOUT_MS = 3 * 60 * 1000\n\nexport interface PosDisplayControl {\n /** A display for this register polled within the last two minutes. */\n connected: boolean\n /** The prompt the register is waiting on, if any. */\n asking: CommerceModel.PosDisplayMode | null\n /** Shows something on the display with no answer expected. */\n show: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<void>\n /**\n * Asks the customer (a tip or a receipt) and resolves with their answer,\n * or null when the cashier cancels or the customer does not answer.\n */\n ask: (\n state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>,\n ) => Promise<CommerceModel.PosDisplayResponse | null>\n cancelAsk: () => void\n /** A fresh six-digit pairing code for a new display. */\n pairingCode: () => Promise<{ code: string; expiresAtMs: number }>\n}\n\n/**\n * The register's half of the customer display (AGL-3608). It writes the\n * display's state through `commerce/pos-display` and reads answers back the\n * same way; nothing here talks to Firestore, because the display state is\n * server-only (it can hold a customer's typed email address).\n */\nexport function usePosDisplay(\n user: User | null | undefined,\n hostId: string,\n registerId: string,\n): PosDisplayControl {\n const [connected, setConnected] = useState(false)\n const [asking, setAsking] = useState<CommerceModel.PosDisplayMode | null>(null)\n const cancelRef = useRef<(() => void) | null>(null)\n // The poll reads the latest session through a ref and is keyed on the uid,\n // so a refreshed user object does not restart it.\n const userRef = useRef(user)\n userRef.current = user\n const uid = (user as { uid?: string } | null | undefined)?.uid ?? ''\n\n useEffect(() => {\n if (!uid || !registerId) return undefined\n let active = true\n const check = async () => {\n const signedIn = userRef.current\n if (!signedIn) return\n try {\n const result = await posDisplayCall<{ connected: boolean }>(\n signedIn,\n { action: 'state', hostId, registerId },\n 'GET',\n )\n if (active) setConnected(Boolean(result.connected))\n } catch {\n if (active) setConnected(false)\n }\n }\n void check()\n const timer = setInterval(check, 15_000)\n return () => {\n active = false\n clearInterval(timer)\n }\n }, [uid, hostId, registerId])\n\n const show = useCallback<PosDisplayControl['show']>(\n async (state) => {\n if (!user || !registerId || !connected) return\n await posDisplayCall(user, { action: 'push', hostId, registerId, state }).catch(() => undefined)\n },\n [user, hostId, registerId, connected],\n )\n\n const cancelAsk = useCallback(() => {\n cancelRef.current?.()\n }, [])\n\n const ask = useCallback<PosDisplayControl['ask']>(\n async (state) => {\n if (!user || !registerId) return null\n cancelRef.current?.()\n const promptId = newAttemptKey().slice(0, 32)\n await posDisplayCall(user, {\n action: 'push',\n hostId,\n registerId,\n state: { ...state, promptId },\n })\n setAsking(state.mode)\n return await new Promise<CommerceModel.PosDisplayResponse | null>((resolve) => {\n let done = false\n const finish = (answer: CommerceModel.PosDisplayResponse | null) => {\n if (done) return\n done = true\n clearInterval(timer)\n clearTimeout(timeout)\n cancelRef.current = null\n setAsking(null)\n resolve(answer)\n }\n const timer = setInterval(async () => {\n try {\n const result = await posDisplayCall<{\n state: CommerceModel.PosDisplayState | null\n }>(user, { action: 'state', hostId, registerId }, 'GET')\n const response = result.state?.response\n if (response && response.promptId === promptId) finish(response)\n } catch {\n // A missed poll is retried on the next tick.\n }\n }, 1000)\n const timeout = setTimeout(() => finish(null), POS_DISPLAY_ANSWER_TIMEOUT_MS)\n cancelRef.current = () => finish(null)\n })\n },\n [user, hostId, registerId],\n )\n\n const pairingCode = useCallback(async () => {\n if (!user) throw new Error('Not signed in')\n const result = await posDisplayCall<{ code: string; expiresAtMs: number }>(user, {\n action: 'pairing-code',\n hostId,\n registerId,\n })\n return result\n }, [user, hostId, registerId])\n\n return { connected, asking, show, ask, cancelAsk, pairingCode }\n}\n"],"names":["useCallback","useEffect","useRef","useState","newAttemptKey","posDisplayCall","posDisplayTipCents","sale","pendingTipCents","pending","status","Math","max","round","tipCents","POS_DISPLAY_ANSWER_TIMEOUT_MS","usePosDisplay","user","hostId","registerId","connected","setConnected","asking","setAsking","cancelRef","userRef","current","uid","undefined","active","check","signedIn","result","action","Boolean","timer","setInterval","clearInterval","show","state","catch","cancelAsk","ask","promptId","slice","mode","Promise","resolve","done","finish","answer","clearTimeout","timeout","response","setTimeout","pairingCode","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/use-pos-display.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'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { newAttemptKey, posDisplayCall } from './pos-api'\n\ntype User = Parameters<typeof posDisplayCall>[0]\n\n/**\n * The tip the customer screen shows beside the sale (AGL-3608): the tips\n * already on its payments, plus one chosen for the payment about to be taken\n * (on the display or by the cashier), which the ledger does not hold until\n * that payment is recorded. Without the second part the screen read the\n * sale's total right after the customer added a tip, short by that tip.\n */\nexport function posDisplayTipCents(\n sale: { status: string; tipCents: number } | null | undefined,\n pendingTipCents: number,\n): number {\n if (!sale) return 0\n const pending = sale.status === 'paid' ? 0 : Math.max(0, Math.round(pendingTipCents) || 0)\n return Math.max(0, sale.tipCents) + pending\n}\n\n/** How long the register waits for the customer to answer a prompt. */\nexport const POS_DISPLAY_ANSWER_TIMEOUT_MS = 3 * 60 * 1000\n\nexport interface PosDisplayControl {\n /** A display for this register polled within the last two minutes. */\n connected: boolean\n /** The prompt the register is waiting on, if any. */\n asking: CommerceModel.PosDisplayMode | null\n /** Shows something on the display with no answer expected. */\n show: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<void>\n /**\n * Asks the customer (a tip or a receipt) and resolves with their answer,\n * or null when the cashier cancels or the customer does not answer.\n */\n ask: (\n state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>,\n ) => Promise<CommerceModel.PosDisplayResponse | null>\n cancelAsk: () => void\n /**\n * A fresh six-digit pairing code for a new customer display, or for a\n * self-service kiosk (AGL-3623).\n */\n pairingCode: (mode?: CommerceModel.PosDeviceMode) => Promise<{ code: string; expiresAtMs: number }>\n}\n\n/**\n * The register's half of the customer display (AGL-3608). It writes the\n * display's state through `commerce/pos-display` and reads answers back the\n * same way; nothing here talks to Firestore, because the display state is\n * server-only (it can hold a customer's typed email address).\n */\nexport function usePosDisplay(\n user: User | null | undefined,\n hostId: string,\n registerId: string,\n): PosDisplayControl {\n const [connected, setConnected] = useState(false)\n const [asking, setAsking] = useState<CommerceModel.PosDisplayMode | null>(null)\n const cancelRef = useRef<(() => void) | null>(null)\n // The poll reads the latest session through a ref and is keyed on the uid,\n // so a refreshed user object does not restart it.\n const userRef = useRef(user)\n userRef.current = user\n const uid = (user as { uid?: string } | null | undefined)?.uid ?? ''\n\n useEffect(() => {\n if (!uid || !registerId) return undefined\n let active = true\n const check = async () => {\n const signedIn = userRef.current\n if (!signedIn) return\n try {\n const result = await posDisplayCall<{ connected: boolean }>(\n signedIn,\n { action: 'state', hostId, registerId },\n 'GET',\n )\n if (active) setConnected(Boolean(result.connected))\n } catch {\n if (active) setConnected(false)\n }\n }\n void check()\n const timer = setInterval(check, 15_000)\n return () => {\n active = false\n clearInterval(timer)\n }\n }, [uid, hostId, registerId])\n\n const show = useCallback<PosDisplayControl['show']>(\n async (state) => {\n if (!user || !registerId || !connected) return\n await posDisplayCall(user, { action: 'push', hostId, registerId, state }).catch(() => undefined)\n },\n [user, hostId, registerId, connected],\n )\n\n const cancelAsk = useCallback(() => {\n cancelRef.current?.()\n }, [])\n\n const ask = useCallback<PosDisplayControl['ask']>(\n async (state) => {\n if (!user || !registerId) return null\n cancelRef.current?.()\n const promptId = newAttemptKey().slice(0, 32)\n await posDisplayCall(user, {\n action: 'push',\n hostId,\n registerId,\n state: { ...state, promptId },\n })\n setAsking(state.mode)\n return await new Promise<CommerceModel.PosDisplayResponse | null>((resolve) => {\n let done = false\n const finish = (answer: CommerceModel.PosDisplayResponse | null) => {\n if (done) return\n done = true\n clearInterval(timer)\n clearTimeout(timeout)\n cancelRef.current = null\n setAsking(null)\n resolve(answer)\n }\n const timer = setInterval(async () => {\n try {\n const result = await posDisplayCall<{\n state: CommerceModel.PosDisplayState | null\n }>(user, { action: 'state', hostId, registerId }, 'GET')\n const response = result.state?.response\n if (response && response.promptId === promptId) finish(response)\n } catch {\n // A missed poll is retried on the next tick.\n }\n }, 1000)\n const timeout = setTimeout(() => finish(null), POS_DISPLAY_ANSWER_TIMEOUT_MS)\n cancelRef.current = () => finish(null)\n })\n },\n [user, hostId, registerId],\n )\n\n const pairingCode = useCallback(async (mode: CommerceModel.PosDeviceMode = 'display') => {\n if (!user) throw new Error('Not signed in')\n const result = await posDisplayCall<{ code: string; expiresAtMs: number }>(user, {\n action: 'pairing-code',\n hostId,\n registerId,\n mode,\n })\n return result\n }, [user, hostId, registerId])\n\n return { connected, asking, show, ask, cancelAsk, pairingCode }\n}\n"],"names":["useCallback","useEffect","useRef","useState","newAttemptKey","posDisplayCall","posDisplayTipCents","sale","pendingTipCents","pending","status","Math","max","round","tipCents","POS_DISPLAY_ANSWER_TIMEOUT_MS","usePosDisplay","user","hostId","registerId","connected","setConnected","asking","setAsking","cancelRef","userRef","current","uid","undefined","active","check","signedIn","result","action","Boolean","timer","setInterval","clearInterval","show","state","catch","cancelAsk","ask","promptId","slice","mode","Promise","resolve","done","finish","answer","clearTimeout","timeout","response","setTimeout","pairingCode","Error"],"mappings":"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"}
@@ -292,12 +292,12 @@ const EMPTY_ADDRESS = {
292
292
  children: [
293
293
  /*#__PURE__*/ _jsx(Typography, {
294
294
  variant: "subtitle2",
295
- children: 'Customer displays'
295
+ children: 'Customer displays and kiosks'
296
296
  }),
297
297
  /*#__PURE__*/ _jsx(Typography, {
298
298
  variant: "body2",
299
299
  color: "text.secondary",
300
- children: 'Pair a tablet facing your customer from the register: tap Pair display and enter the code on the tablet.'
300
+ children: 'Pair a tablet from the register: tap Pair display, choose Customer display or Self-service kiosk, and enter the code on the tablet.'
301
301
  }),
302
302
  registers.flatMap((register)=>{
303
303
  var _displays_register_$id;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-devices-card.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 { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useFirestoreCollection, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { posDisplayCall, posReadersCall, PosRequestError } from './pos/pos-api'\n\ninterface ReaderRow {\n id: string\n label: string\n registerId: string | null\n deviceType: string | null\n serialNumber: string | null\n status: string\n livemode: boolean\n}\n\ninterface ReadersAnswer {\n available: boolean\n testMode: boolean\n locationReady: boolean\n readers: ReaderRow[]\n}\n\ninterface DisplayRow {\n id: string\n label: string\n createdAtMs: number\n lastSeenAtMs: number\n}\n\nexport interface PosDevicesCardProps {\n hostId: string\n}\n\nconst EMPTY_ADDRESS = { line1: '', line2: '', city: '', state: '', postalCode: '', country: 'US' }\n\n/**\n * The register's hardware (AGL-3607, AGL-3608): Stripe Terminal card readers\n * — registered with the code a reader shows, bound to a register, renamed,\n * removed — and the customer displays paired to each register, which can be\n * signed out. Readers appear only where card readers are offered at all.\n */\nexport function PosDevicesCard({ hostId }: PosDevicesCardProps) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n const [answer, setAnswer] = useState<ReadersAnswer | null>(null)\n const [displays, setDisplays] = useState<Record<string, DisplayRow[]>>({})\n const [adding, setAdding] = useState(false)\n const [code, setCode] = useState('')\n const [label, setLabel] = useState('')\n const [registerId, setRegisterId] = useState('')\n const [address, setAddress] = useState(EMPTY_ADDRESS)\n const [busy, setBusy] = useState(false)\n const [renaming, setRenaming] = useState<{ id: string; label: string } | null>(null)\n\n const notify = useCallback(\n (error: unknown, fallback: string) =>\n enqueueSnackbar(error instanceof PosRequestError ? error.message : fallback, {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const load = useCallback(\n async (refresh = false) => {\n if (!user) return\n try {\n setAnswer(await posReadersCall<ReadersAnswer>(user, { action: 'list', hostId, refresh }))\n } catch {\n setAnswer(null)\n }\n },\n [user, hostId],\n )\n const uid = user?.uid ?? ''\n useEffect(() => {\n void load(true)\n // Keyed on the person, not the session object (see the register page).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId])\n\n const registerIds = registers.map((register: any) => register.$id).join(',')\n useEffect(() => {\n if (!user || !registerIds) return\n let active = true\n void Promise.all(\n registerIds.split(',').map(async (id) => {\n const result = await posDisplayCall<{ displays: DisplayRow[] }>(user, {\n action: 'displays',\n hostId,\n registerId: id,\n }).catch(() => ({ displays: [] as DisplayRow[] }))\n return [id, result.displays] as const\n }),\n ).then((entries) => {\n if (active) setDisplays(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId, registerIds])\n\n const registerName = (id: string | null) =>\n registers.find((register: any) => register.$id === id)?.name ?? null\n\n const addReader = async () => {\n if (!user) return\n setBusy(true)\n try {\n await posReadersCall(user, {\n action: 'register',\n hostId,\n registrationCode: code.trim(),\n label: label.trim(),\n ...(registerId ? { registerId } : {}),\n ...(answer?.locationReady ? {} : { address }),\n })\n setAdding(false)\n setCode('')\n setLabel('')\n setRegisterId('')\n await load()\n } catch (error) {\n notify(error, 'The reader could not be added')\n } finally {\n setBusy(false)\n }\n }\n\n const readers = answer?.readers ?? []\n const showReaders = Boolean(answer?.available)\n\n return (\n <CardDisplay\n header={'POS devices'}\n help={pluginDocsHelp('pos', { anchor: '#card-readers' })}\n HeaderProps={\n showReaders\n ? {\n action: (\n <Button size=\"small\" onClick={() => setAdding(true)}>\n {'Add card reader'}\n </Button>\n ),\n }\n : undefined\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {showReaders ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Card readers'}</Typography>\n {readers.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {answer?.testMode\n ? 'No card readers yet. In test mode, add one with the code \"simulated-wpe\" to try a simulated reader.'\n : 'No card readers yet. Add a Stripe Reader S700 or BBPOS WisePOS E with the code it shows on screen.'}\n </Typography>\n ) : (\n readers.map((reader) => (\n <Stack\n key={reader.id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 160 }}>\n {reader.label}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {` · ${registerName(reader.registerId) ?? 'Any register'}` +\n (reader.livemode ? '' : ' · test')}\n </Typography>\n </Typography>\n <Chip\n size=\"small\"\n label={reader.status === 'online' ? 'Online' : 'Offline'}\n color={reader.status === 'online' ? 'success' : 'default'}\n />\n <TextField\n select\n size=\"small\"\n label=\"Register\"\n value={reader.registerId ?? ''}\n onChange={async (event) => {\n if (!user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: reader.id,\n registerId: event.target.value,\n })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be updated')\n }\n }}\n sx={{ minWidth: 140 }}\n >\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n onClick={() => setRenaming({ id: reader.id, label: reader.label })}\n >\n {'Rename'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this card reader?',\n description:\n `\"${reader.label}\" is removed from your account and stops taking payments. ` +\n 'To use it again, register it with a new code.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !user) return\n try {\n await posReadersCall(user, { action: 'remove', hostId, readerId: reader.id })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be removed')\n }\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n ))\n )}\n </Stack>\n ) : null}\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Customer displays'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pair a tablet facing your customer from the register: tap Pair display and enter the code on the tablet.'}\n </Typography>\n {registers.flatMap((register: any) =>\n (displays[register.$id] ?? []).map((display) => (\n <Stack key={`${register.$id}:${display.id}`} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${display.label} · ${register.name}`}\n </Typography>\n <Chip\n size=\"small\"\n label={Date.now() - display.lastSeenAtMs < 120_000 ? 'Connected' : 'Not connected'}\n color={Date.now() - display.lastSeenAtMs < 120_000 ? 'success' : 'default'}\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n if (!user) return\n try {\n await posDisplayCall(user, {\n action: 'revoke',\n hostId,\n registerId: register.$id,\n displayId: display.id,\n })\n setDisplays((prev) => ({\n ...prev,\n [register.$id]: (prev[register.$id] ?? []).filter((entry) => entry.id !== display.id),\n }))\n } catch (error) {\n notify(error, 'The display could not be signed out')\n }\n }}\n >\n {'Sign out'}\n </Button>\n </Stack>\n )),\n )}\n </Stack>\n </Stack>\n\n <Dialog open={Boolean(renaming)} onClose={() => setRenaming(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Rename card reader'}</DialogTitle>\n <DialogContent>\n <TextField\n label=\"Name\"\n value={renaming?.label ?? ''}\n onChange={(event) => setRenaming((prev) => (prev ? { ...prev, label: event.target.value } : prev))}\n fullWidth\n autoFocus\n sx={{ mt: 1 }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setRenaming(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!renaming?.label.trim()}\n onClick={async () => {\n if (!renaming || !user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: renaming.id,\n label: renaming.label.trim(),\n })\n setRenaming(null)\n await load()\n } catch (error) {\n notify(error, 'The reader could not be renamed')\n }\n }}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={adding} onClose={() => setAdding(false)} maxWidth=\"sm\" fullWidth>\n <DialogTitle>{'Add a card reader'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'On the reader, open Settings and choose Generate pairing code, then enter the code it shows.'}\n </Typography>\n <TextField\n label=\"Registration code\"\n value={code}\n onChange={(event) => setCode(event.target.value)}\n autoFocus\n slotProps={{ htmlInput: { autoComplete: 'off' } }}\n />\n <TextField label=\"Name\" placeholder=\"Front counter reader\" value={label} onChange={(event) => setLabel(event.target.value)} />\n <TextField select label=\"Register\" value={registerId} onChange={(event) => setRegisterId(event.target.value)}>\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n {answer && !answer.locationReady ? (\n <Box sx={{ display: 'grid', gap: 1.5, gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' } }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ gridColumn: '1 / -1' }}>\n {'Where the reader is used. Stripe sets the reader up for this country.'}\n </Typography>\n <TextField label=\"Street\" value={address.line1} onChange={(event) => setAddress({ ...address, line1: event.target.value })} sx={{ gridColumn: '1 / -1' }} />\n <TextField label=\"City\" value={address.city} onChange={(event) => setAddress({ ...address, city: event.target.value })} />\n <TextField label=\"State\" value={address.state} onChange={(event) => setAddress({ ...address, state: event.target.value })} />\n <TextField label=\"Postal code\" value={address.postalCode} onChange={(event) => setAddress({ ...address, postalCode: event.target.value })} />\n <TextField\n label=\"Country\"\n value={address.country}\n onChange={(event) => setAddress({ ...address, country: event.target.value.toUpperCase().slice(0, 2) })}\n />\n </Box>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setAdding(false)}>{'Cancel'}</Button>\n <Button variant=\"contained\" disabled={busy || !code.trim()} onClick={() => void addReader()}>\n {'Add reader'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nPosDevicesCard.displayName = 'PosDevicesCard'\n\nexport default PosDevicesCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","useFirestore","useFirestoreCollection","useUser","Box","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","limit","query","useCallback","useEffect","useState","posDisplayCall","posReadersCall","PosRequestError","EMPTY_ADDRESS","line1","line2","city","state","postalCode","country","PosDevicesCard","hostId","firestore","data","user","enqueueSnackbar","confirm","registerDocs","idField","registers","sort","a","b","String","name","localeCompare","answer","setAnswer","displays","setDisplays","adding","setAdding","code","setCode","label","setLabel","registerId","setRegisterId","address","setAddress","busy","setBusy","renaming","setRenaming","notify","error","fallback","message","variant","persist","load","refresh","action","uid","registerIds","map","register","$id","join","active","Promise","all","split","id","result","catch","then","entries","Object","fromEntries","registerName","find","addReader","registrationCode","trim","locationReady","readers","showReaders","Boolean","available","header","help","anchor","HeaderProps","size","onClick","undefined","contentGutterX","contentGutterY","spacing","length","color","testMode","reader","direction","sx","alignItems","flexWrap","rowGap","flex","minWidth","component","livemode","status","select","value","onChange","event","readerId","target","confirmed","title","description","confirmationText","confirmationButtonProps","flatMap","display","Date","now","lastSeenAtMs","displayId","prev","filter","entry","open","onClose","maxWidth","fullWidth","autoFocus","mt","disabled","flexDirection","gap","slotProps","htmlInput","autoComplete","placeholder","gridTemplateColumns","xs","sm","gridColumn","toUpperCase","slice","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SAASA,cAAc,QAAQ,eAAc;AAC7C,SAASC,WAAW,EAAEC,sBAAsB,QAAQ,uBAAsB;AAC1E,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,YAAY,EAAEC,sBAAsB,EAAEC,OAAO,QAAQ,iCAAgC;AAC9F,SACEC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SAASC,UAAU,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AAC7D,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AACxD,SAASC,cAAc,EAAEC,cAAc,EAAEC,eAAe,QAAQ,mBAAe;AA8B/E,MAAMC,gBAAgB;IAAEC,OAAO;IAAIC,OAAO;IAAIC,MAAM;IAAIC,OAAO;IAAIC,YAAY;IAAIC,SAAS;AAAK;AAEjG;;;;;CAKC,GACD,OAAO,SAASC,eAAe,EAAEC,MAAM,EAAuB;;IAC5D,MAAMC,YAAYhC;IAClB,MAAM,EAAEiC,MAAMC,IAAI,EAAE,GAAGhC;IACvB,MAAM,EAAEiC,eAAe,EAAE,GAAGpC;IAC5B,MAAM,EAAEqC,OAAO,EAAE,GAAGtC;IACpB,MAAM,EAAEmC,MAAMI,YAAY,EAAE,GAAGpC,uBAC7B,IAAMe,MAAMF,WAAWkB,WAAW,SAASD,QAAQ,cAAchB,MAAM,MACvE;QAACiB;QAAWD;KAAO,EACnB;QAAEO,SAAS;IAAM;IAEnB,MAAMC,YAAY;WAAKF,uBAAAA,eAAgB,EAAE;KAAE,CAACG,IAAI,CAAC,CAACC,GAAQC;YACjDD,SAAmCC;eAA1CC,QAAOF,UAAAA,EAAEG,IAAI,YAANH,UAAU,IAAII,aAAa,CAACF,QAAOD,UAAAA,EAAEE,IAAI,YAANF,UAAU;;IAEtD,MAAM,CAACI,QAAQC,UAAU,GAAG5B,SAA+B;IAC3D,MAAM,CAAC6B,UAAUC,YAAY,GAAG9B,SAAuC,CAAC;IACxE,MAAM,CAAC+B,QAAQC,UAAU,GAAGhC,SAAS;IACrC,MAAM,CAACiC,MAAMC,QAAQ,GAAGlC,SAAS;IACjC,MAAM,CAACmC,OAAOC,SAAS,GAAGpC,SAAS;IACnC,MAAM,CAACqC,YAAYC,cAAc,GAAGtC,SAAS;IAC7C,MAAM,CAACuC,SAASC,WAAW,GAAGxC,SAASI;IACvC,MAAM,CAACqC,MAAMC,QAAQ,GAAG1C,SAAS;IACjC,MAAM,CAAC2C,UAAUC,YAAY,GAAG5C,SAA+C;IAE/E,MAAM6C,SAAS/C,YACb,CAACgD,OAAgBC,WACf/B,gBAAgB8B,iBAAiB3C,kBAAkB2C,MAAME,OAAO,GAAGD,UAAU;YAC3EE,SAAS;YACTC,SAAS;QACX,IACF;QAAClC;KAAgB;IAGnB,MAAMmC,OAAOrD,YACX,OAAOsD,UAAU,KAAK;QACpB,IAAI,CAACrC,MAAM;QACX,IAAI;YACFa,UAAU,MAAM1B,eAA8Ba,MAAM;gBAAEsC,QAAQ;gBAAQzC;gBAAQwC;YAAQ;QACxF,EAAE,eAAM;YACNxB,UAAU;QACZ;IACF,GACA;QAACb;QAAMH;KAAO;IAEhB,MAAM0C,cAAMvC,wBAAAA,KAAMuC,GAAG,mBAAI;IACzBvD,UAAU;QACR,KAAKoD,KAAK;IACV,uEAAuE;IACvE,uDAAuD;IACzD,GAAG;QAACG;QAAK1C;KAAO;IAEhB,MAAM2C,cAAcnC,UAAUoC,GAAG,CAAC,CAACC,WAAkBA,SAASC,GAAG,EAAEC,IAAI,CAAC;IACxE5D,UAAU;QACR,IAAI,CAACgB,QAAQ,CAACwC,aAAa;QAC3B,IAAIK,SAAS;QACb,KAAKC,QAAQC,GAAG,CACdP,YAAYQ,KAAK,CAAC,KAAKP,GAAG,CAAC,OAAOQ;YAChC,MAAMC,SAAS,MAAMhE,eAA2Cc,MAAM;gBACpEsC,QAAQ;gBACRzC;gBACAyB,YAAY2B;YACd,GAAGE,KAAK,CAAC,IAAO,CAAA;oBAAErC,UAAU,EAAE;gBAAiB,CAAA;YAC/C,OAAO;gBAACmC;gBAAIC,OAAOpC,QAAQ;aAAC;QAC9B,IACAsC,IAAI,CAAC,CAACC;YACN,IAAIR,QAAQ9B,YAAYuC,OAAOC,WAAW,CAACF;QAC7C;QACA,OAAO;YACLR,SAAS;QACX;IACA,uDAAuD;IACzD,GAAG;QAACN;QAAK1C;QAAQ2C;KAAY;IAE7B,MAAMgB,eAAe,CAACP;;YACpB5C;wBAAAA,kBAAAA,UAAUoD,IAAI,CAAC,CAACf,WAAkBA,SAASC,GAAG,KAAKM,wBAAnD5C,gBAAwDK,IAAI,mBAAI;;IAElE,MAAMgD,YAAY;QAChB,IAAI,CAAC1D,MAAM;QACX2B,QAAQ;QACR,IAAI;YACF,MAAMxC,eAAea,MAAM;gBACzBsC,QAAQ;gBACRzC;gBACA8D,kBAAkBzC,KAAK0C,IAAI;gBAC3BxC,OAAOA,MAAMwC,IAAI;eACbtC,aAAa;gBAAEA;YAAW,IAAI,CAAC,GAC/BV,CAAAA,0BAAAA,OAAQiD,aAAa,IAAG,CAAC,IAAI;gBAAErC;YAAQ;YAE7CP,UAAU;YACVE,QAAQ;YACRE,SAAS;YACTE,cAAc;YACd,MAAMa;QACR,EAAE,OAAOL,OAAO;YACdD,OAAOC,OAAO;QAChB,SAAU;YACRJ,QAAQ;QACV;IACF;IAEA,MAAMmC,mBAAUlD,0BAAAA,OAAQkD,OAAO,oBAAI,EAAE;IACrC,MAAMC,cAAcC,QAAQpD,0BAAAA,OAAQqD,SAAS;IAE7C,qBACE,MAACtG;QACCuG,QAAQ;QACRC,MAAMzG,eAAe,OAAO;YAAE0G,QAAQ;QAAgB;QACtDC,aACEN,cACI;YACEzB,sBACE,KAACpE;gBAAOoG,MAAK;gBAAQC,SAAS,IAAMtD,UAAU;0BAC3C;;QAGP,IACAuD;QAENC,cAAc;QACdC,cAAc;;0BAEd,MAACjG;gBAAMkG,SAAS;;oBACbZ,4BACC,MAACtF;wBAAMkG,SAAS;;0CACd,KAAChG;gCAAWuD,SAAQ;0CAAa;;4BAChC4B,QAAQc,MAAM,KAAK,kBAClB,KAACjG;gCAAWuD,SAAQ;gCAAQ2C,OAAM;0CAC/BjE,CAAAA,0BAAAA,OAAQkE,QAAQ,IACb,wGACA;iCAGNhB,QAAQrB,GAAG,CAAC,CAACsC;oCAUEvB,eAaFuB;qDAtBX,MAACtG;oCAECuG,WAAU;oCACVL,SAAS;oCACTM,IAAI;wCAAEC,YAAY;wCAAUC,UAAU;wCAAQC,QAAQ;oCAAE;;sDAExD,MAACzG;4CAAWuD,SAAQ;4CAAQ+C,IAAI;gDAAEI,MAAM;gDAAGC,UAAU;4CAAI;;gDACtDP,OAAO3D,KAAK;8DACb,KAACzC;oDAAW4G,WAAU;oDAAOrD,SAAQ;oDAAU2C,OAAM;8DAClD,CAAC,GAAG,GAAErB,gBAAAA,aAAauB,OAAOzD,UAAU,aAA9BkC,gBAAmC,gBAAgB,GACvDuB,CAAAA,OAAOS,QAAQ,GAAG,KAAK,SAAQ;;;;sDAGtC,KAACrH;4CACCmG,MAAK;4CACLlD,OAAO2D,OAAOU,MAAM,KAAK,WAAW,WAAW;4CAC/CZ,OAAOE,OAAOU,MAAM,KAAK,WAAW,YAAY;;sDAElD,MAAC/G;4CACCgH,MAAM;4CACNpB,MAAK;4CACLlD,OAAM;4CACNuE,KAAK,GAAEZ,qBAAAA,OAAOzD,UAAU,YAAjByD,qBAAqB;4CAC5Ba,UAAU,OAAOC;gDACf,IAAI,CAAC7F,MAAM;gDACX,IAAI;oDACF,MAAMb,eAAea,MAAM;wDACzBsC,QAAQ;wDACRzC;wDACAiG,UAAUf,OAAO9B,EAAE;wDACnB3B,YAAYuE,MAAME,MAAM,CAACJ,KAAK;oDAChC;oDACA,MAAMvD;gDACR,EAAE,OAAOL,OAAO;oDACdD,OAAOC,OAAO;gDAChB;4CACF;4CACAkD,IAAI;gDAAEK,UAAU;4CAAI;;8DAEpB,KAAC9G;oDAASmH,OAAM;8DAAI;;gDACnBtF,UAAUoC,GAAG,CAAC,CAACC,yBACd,KAAClE;wDAA4BmH,OAAOjD,SAASC,GAAG;kEAC7CD,SAAShC,IAAI;uDADDgC,SAASC,GAAG;;;sDAK/B,KAACzE;4CACCoG,MAAK;4CACLC,SAAS,IAAM1C,YAAY;oDAAEoB,IAAI8B,OAAO9B,EAAE;oDAAE7B,OAAO2D,OAAO3D,KAAK;gDAAC;sDAE/D;;sDAEH,KAAClD;4CACCoG,MAAK;4CACLO,OAAM;4CACNN,SAAS;gDACP,MAAMyB,YAAY,MAAM9F,QAAQ;oDAC9B+F,OAAO;oDACPC,aACE,CAAC,CAAC,EAAEnB,OAAO3D,KAAK,CAAC,0DAA0D,CAAC,GAC5E;oDACF+E,kBAAkB;oDAClBC,yBAAyB;wDAAEvB,OAAO;oDAAQ;gDAC5C,GACGzB,IAAI,CAAC,IAAM,MACXD,KAAK,CAAC,IAAM;gDACf,IAAI,CAAC6C,aAAa,CAAChG,MAAM;gDACzB,IAAI;oDACF,MAAMb,eAAea,MAAM;wDAAEsC,QAAQ;wDAAUzC;wDAAQiG,UAAUf,OAAO9B,EAAE;oDAAC;oDAC3E,MAAMb;gDACR,EAAE,OAAOL,OAAO;oDACdD,OAAOC,OAAO;gDAChB;4CACF;sDAEC;;;mCA1EEgD,OAAO9B,EAAE;;;yBAgFpB;kCACJ,MAACxE;wBAAMkG,SAAS;;0CACd,KAAChG;gCAAWuD,SAAQ;0CAAa;;0CACjC,KAACvD;gCAAWuD,SAAQ;gCAAQ2C,OAAM;0CAC/B;;4BAEFxE,UAAUgG,OAAO,CAAC,CAAC3D;oCACjB5B;uCAAD,EAACA,yBAAAA,QAAQ,CAAC4B,SAASC,GAAG,CAAC,YAAtB7B,yBAA0B,EAAE,EAAE2B,GAAG,CAAC,CAAC6D,wBAClC,MAAC7H;wCAA4CuG,WAAU;wCAAML,SAAS;wCAAGM,IAAI;4CAAEC,YAAY;wCAAS;;0DAClG,KAACvG;gDAAWuD,SAAQ;gDAAQ+C,IAAI;oDAAEI,MAAM;gDAAE;0DACvC,GAAGiB,QAAQlF,KAAK,CAAC,GAAG,EAAEsB,SAAShC,IAAI,EAAE;;0DAExC,KAACvC;gDACCmG,MAAK;gDACLlD,OAAOmF,KAAKC,GAAG,KAAKF,QAAQG,YAAY,GAAG,SAAU,cAAc;gDACnE5B,OAAO0B,KAAKC,GAAG,KAAKF,QAAQG,YAAY,GAAG,SAAU,YAAY;;0DAEnE,KAACvI;gDACCoG,MAAK;gDACLO,OAAM;gDACNN,SAAS;oDACP,IAAI,CAACvE,MAAM;oDACX,IAAI;wDACF,MAAMd,eAAec,MAAM;4DACzBsC,QAAQ;4DACRzC;4DACAyB,YAAYoB,SAASC,GAAG;4DACxB+D,WAAWJ,QAAQrD,EAAE;wDACvB;wDACAlC,YAAY,CAAC4F;gEAEMA;mEAFI,aAClBA;gEACH,CAACjE,SAASC,GAAG,CAAC,EAAE,EAACgE,qBAAAA,IAAI,CAACjE,SAASC,GAAG,CAAC,YAAlBgE,qBAAsB,EAAE,EAAEC,MAAM,CAAC,CAACC,QAAUA,MAAM5D,EAAE,KAAKqD,QAAQrD,EAAE;;;oDAExF,EAAE,OAAOlB,OAAO;wDACdD,OAAOC,OAAO;oDAChB;gDACF;0DAEC;;;uCA9BO,GAAGW,SAASC,GAAG,CAAC,CAAC,EAAE2D,QAAQrD,EAAE,EAAE;;;;;;0BAsCnD,MAAC7E;gBAAO0I,MAAM9C,QAAQpC;gBAAWmF,SAAS,IAAMlF,YAAY;gBAAOmF,UAAS;gBAAKC,SAAS;;kCACxF,KAAC1I;kCAAa;;kCACd,KAACD;kCACC,cAAA,KAACI;4BACC0C,OAAM;4BACNuE,KAAK,WAAE/D,4BAAAA,SAAUR,KAAK,oBAAI;4BAC1BwE,UAAU,CAACC,QAAUhE,YAAY,CAAC8E,OAAUA,OAAO,aAAKA;wCAAMvF,OAAOyE,MAAME,MAAM,CAACJ,KAAK;yCAAKgB;4BAC5FM,SAAS;4BACTC,SAAS;4BACTjC,IAAI;gCAAEkC,IAAI;4BAAE;;;kCAGhB,MAAC9I;;0CACC,KAACH;gCAAOqG,SAAS,IAAM1C,YAAY;0CAAQ;;0CAC3C,KAAC3D;gCACCgE,SAAQ;gCACRkF,UAAU,EAACxF,4BAAAA,SAAUR,KAAK,CAACwC,IAAI;gCAC/BW,SAAS;oCACP,IAAI,CAAC3C,YAAY,CAAC5B,MAAM;oCACxB,IAAI;wCACF,MAAMb,eAAea,MAAM;4CACzBsC,QAAQ;4CACRzC;4CACAiG,UAAUlE,SAASqB,EAAE;4CACrB7B,OAAOQ,SAASR,KAAK,CAACwC,IAAI;wCAC5B;wCACA/B,YAAY;wCACZ,MAAMO;oCACR,EAAE,OAAOL,OAAO;wCACdD,OAAOC,OAAO;oCAChB;gCACF;0CAEC;;;;;;0BAIP,MAAC3D;gBAAO0I,MAAM9F;gBAAQ+F,SAAS,IAAM9F,UAAU;gBAAQ+F,UAAS;gBAAKC,SAAS;;kCAC5E,KAAC1I;kCAAa;;kCACd,MAACD;wBAAc2G,IAAI;4BAAEqB,SAAS;4BAAQe,eAAe;4BAAUC,KAAK;wBAAE;;0CACpE,KAAC3I;gCAAWuD,SAAQ;gCAAQ2C,OAAM;gCAAiBI,IAAI;oCAAEkC,IAAI;gCAAE;0CAC5D;;0CAEH,KAACzI;gCACC0C,OAAM;gCACNuE,OAAOzE;gCACP0E,UAAU,CAACC,QAAU1E,QAAQ0E,MAAME,MAAM,CAACJ,KAAK;gCAC/CuB,SAAS;gCACTK,WAAW;oCAAEC,WAAW;wCAAEC,cAAc;oCAAM;gCAAE;;0CAElD,KAAC/I;gCAAU0C,OAAM;gCAAOsG,aAAY;gCAAuB/B,OAAOvE;gCAAOwE,UAAU,CAACC,QAAUxE,SAASwE,MAAME,MAAM,CAACJ,KAAK;;0CACzH,MAACjH;gCAAUgH,MAAM;gCAACtE,OAAM;gCAAWuE,OAAOrE;gCAAYsE,UAAU,CAACC,QAAUtE,cAAcsE,MAAME,MAAM,CAACJ,KAAK;;kDACzG,KAACnH;wCAASmH,OAAM;kDAAI;;oCACnBtF,UAAUoC,GAAG,CAAC,CAACC,yBACd,KAAClE;4CAA4BmH,OAAOjD,SAASC,GAAG;sDAC7CD,SAAShC,IAAI;2CADDgC,SAASC,GAAG;;;4BAK9B/B,UAAU,CAACA,OAAOiD,aAAa,iBAC9B,MAAC5F;gCAAIgH,IAAI;oCAAEqB,SAAS;oCAAQgB,KAAK;oCAAKK,qBAAqB;wCAAEC,IAAI;wCAAOC,IAAI;oCAAU;gCAAE;;kDACtF,KAAClJ;wCAAWuD,SAAQ;wCAAQ2C,OAAM;wCAAiBI,IAAI;4CAAE6C,YAAY;wCAAS;kDAC3E;;kDAEH,KAACpJ;wCAAU0C,OAAM;wCAASuE,OAAOnE,QAAQlC,KAAK;wCAAEsG,UAAU,CAACC,QAAUpE,WAAW,aAAKD;gDAASlC,OAAOuG,MAAME,MAAM,CAACJ,KAAK;;wCAAKV,IAAI;4CAAE6C,YAAY;wCAAS;;kDACvJ,KAACpJ;wCAAU0C,OAAM;wCAAOuE,OAAOnE,QAAQhC,IAAI;wCAAEoG,UAAU,CAACC,QAAUpE,WAAW,aAAKD;gDAAShC,MAAMqG,MAAME,MAAM,CAACJ,KAAK;;;kDACnH,KAACjH;wCAAU0C,OAAM;wCAAQuE,OAAOnE,QAAQ/B,KAAK;wCAAEmG,UAAU,CAACC,QAAUpE,WAAW,aAAKD;gDAAS/B,OAAOoG,MAAME,MAAM,CAACJ,KAAK;;;kDACtH,KAACjH;wCAAU0C,OAAM;wCAAcuE,OAAOnE,QAAQ9B,UAAU;wCAAEkG,UAAU,CAACC,QAAUpE,WAAW,aAAKD;gDAAS9B,YAAYmG,MAAME,MAAM,CAACJ,KAAK;;;kDACtI,KAACjH;wCACC0C,OAAM;wCACNuE,OAAOnE,QAAQ7B,OAAO;wCACtBiG,UAAU,CAACC,QAAUpE,WAAW,aAAKD;gDAAS7B,SAASkG,MAAME,MAAM,CAACJ,KAAK,CAACoC,WAAW,GAAGC,KAAK,CAAC,GAAG;;;;iCAGnG;;;kCAEN,MAAC3J;;0CACC,KAACH;gCAAOqG,SAAS,IAAMtD,UAAU;0CAAS;;0CAC1C,KAAC/C;gCAAOgE,SAAQ;gCAAYkF,UAAU1F,QAAQ,CAACR,KAAK0C,IAAI;gCAAIW,SAAS,IAAM,KAAKb;0CAC7E;;;;;;;;AAMb;AACA9D,eAAeqI,WAAW,GAAG;AAE7B,eAAerI,eAAc"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-devices-card.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 { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useFirestoreCollection, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { posDisplayCall, posReadersCall, PosRequestError } from './pos/pos-api'\n\ninterface ReaderRow {\n id: string\n label: string\n registerId: string | null\n deviceType: string | null\n serialNumber: string | null\n status: string\n livemode: boolean\n}\n\ninterface ReadersAnswer {\n available: boolean\n testMode: boolean\n locationReady: boolean\n readers: ReaderRow[]\n}\n\ninterface DisplayRow {\n id: string\n label: string\n createdAtMs: number\n lastSeenAtMs: number\n}\n\nexport interface PosDevicesCardProps {\n hostId: string\n}\n\nconst EMPTY_ADDRESS = { line1: '', line2: '', city: '', state: '', postalCode: '', country: 'US' }\n\n/**\n * The register's hardware (AGL-3607, AGL-3608): Stripe Terminal card readers\n * — registered with the code a reader shows, bound to a register, renamed,\n * removed — and the customer displays paired to each register, which can be\n * signed out. Readers appear only where card readers are offered at all.\n */\nexport function PosDevicesCard({ hostId }: PosDevicesCardProps) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n const [answer, setAnswer] = useState<ReadersAnswer | null>(null)\n const [displays, setDisplays] = useState<Record<string, DisplayRow[]>>({})\n const [adding, setAdding] = useState(false)\n const [code, setCode] = useState('')\n const [label, setLabel] = useState('')\n const [registerId, setRegisterId] = useState('')\n const [address, setAddress] = useState(EMPTY_ADDRESS)\n const [busy, setBusy] = useState(false)\n const [renaming, setRenaming] = useState<{ id: string; label: string } | null>(null)\n\n const notify = useCallback(\n (error: unknown, fallback: string) =>\n enqueueSnackbar(error instanceof PosRequestError ? error.message : fallback, {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const load = useCallback(\n async (refresh = false) => {\n if (!user) return\n try {\n setAnswer(await posReadersCall<ReadersAnswer>(user, { action: 'list', hostId, refresh }))\n } catch {\n setAnswer(null)\n }\n },\n [user, hostId],\n )\n const uid = user?.uid ?? ''\n useEffect(() => {\n void load(true)\n // Keyed on the person, not the session object (see the register page).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId])\n\n const registerIds = registers.map((register: any) => register.$id).join(',')\n useEffect(() => {\n if (!user || !registerIds) return\n let active = true\n void Promise.all(\n registerIds.split(',').map(async (id) => {\n const result = await posDisplayCall<{ displays: DisplayRow[] }>(user, {\n action: 'displays',\n hostId,\n registerId: id,\n }).catch(() => ({ displays: [] as DisplayRow[] }))\n return [id, result.displays] as const\n }),\n ).then((entries) => {\n if (active) setDisplays(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId, registerIds])\n\n const registerName = (id: string | null) =>\n registers.find((register: any) => register.$id === id)?.name ?? null\n\n const addReader = async () => {\n if (!user) return\n setBusy(true)\n try {\n await posReadersCall(user, {\n action: 'register',\n hostId,\n registrationCode: code.trim(),\n label: label.trim(),\n ...(registerId ? { registerId } : {}),\n ...(answer?.locationReady ? {} : { address }),\n })\n setAdding(false)\n setCode('')\n setLabel('')\n setRegisterId('')\n await load()\n } catch (error) {\n notify(error, 'The reader could not be added')\n } finally {\n setBusy(false)\n }\n }\n\n const readers = answer?.readers ?? []\n const showReaders = Boolean(answer?.available)\n\n return (\n <CardDisplay\n header={'POS devices'}\n help={pluginDocsHelp('pos', { anchor: '#card-readers' })}\n HeaderProps={\n showReaders\n ? {\n action: (\n <Button size=\"small\" onClick={() => setAdding(true)}>\n {'Add card reader'}\n </Button>\n ),\n }\n : undefined\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {showReaders ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Card readers'}</Typography>\n {readers.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {answer?.testMode\n ? 'No card readers yet. In test mode, add one with the code \"simulated-wpe\" to try a simulated reader.'\n : 'No card readers yet. Add a Stripe Reader S700 or BBPOS WisePOS E with the code it shows on screen.'}\n </Typography>\n ) : (\n readers.map((reader) => (\n <Stack\n key={reader.id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 160 }}>\n {reader.label}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {` · ${registerName(reader.registerId) ?? 'Any register'}` +\n (reader.livemode ? '' : ' · test')}\n </Typography>\n </Typography>\n <Chip\n size=\"small\"\n label={reader.status === 'online' ? 'Online' : 'Offline'}\n color={reader.status === 'online' ? 'success' : 'default'}\n />\n <TextField\n select\n size=\"small\"\n label=\"Register\"\n value={reader.registerId ?? ''}\n onChange={async (event) => {\n if (!user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: reader.id,\n registerId: event.target.value,\n })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be updated')\n }\n }}\n sx={{ minWidth: 140 }}\n >\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n onClick={() => setRenaming({ id: reader.id, label: reader.label })}\n >\n {'Rename'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this card reader?',\n description:\n `\"${reader.label}\" is removed from your account and stops taking payments. ` +\n 'To use it again, register it with a new code.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !user) return\n try {\n await posReadersCall(user, { action: 'remove', hostId, readerId: reader.id })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be removed')\n }\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n ))\n )}\n </Stack>\n ) : null}\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Customer displays and kiosks'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pair a tablet from the register: tap Pair display, choose Customer display or Self-service kiosk, and enter the code on the tablet.'}\n </Typography>\n {registers.flatMap((register: any) =>\n (displays[register.$id] ?? []).map((display) => (\n <Stack key={`${register.$id}:${display.id}`} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${display.label} · ${register.name}`}\n </Typography>\n <Chip\n size=\"small\"\n label={Date.now() - display.lastSeenAtMs < 120_000 ? 'Connected' : 'Not connected'}\n color={Date.now() - display.lastSeenAtMs < 120_000 ? 'success' : 'default'}\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n if (!user) return\n try {\n await posDisplayCall(user, {\n action: 'revoke',\n hostId,\n registerId: register.$id,\n displayId: display.id,\n })\n setDisplays((prev) => ({\n ...prev,\n [register.$id]: (prev[register.$id] ?? []).filter((entry) => entry.id !== display.id),\n }))\n } catch (error) {\n notify(error, 'The display could not be signed out')\n }\n }}\n >\n {'Sign out'}\n </Button>\n </Stack>\n )),\n )}\n </Stack>\n </Stack>\n\n <Dialog open={Boolean(renaming)} onClose={() => setRenaming(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Rename card reader'}</DialogTitle>\n <DialogContent>\n <TextField\n label=\"Name\"\n value={renaming?.label ?? ''}\n onChange={(event) => setRenaming((prev) => (prev ? { ...prev, label: event.target.value } : prev))}\n fullWidth\n autoFocus\n sx={{ mt: 1 }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setRenaming(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!renaming?.label.trim()}\n onClick={async () => {\n if (!renaming || !user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: renaming.id,\n label: renaming.label.trim(),\n })\n setRenaming(null)\n await load()\n } catch (error) {\n notify(error, 'The reader could not be renamed')\n }\n }}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={adding} onClose={() => setAdding(false)} maxWidth=\"sm\" fullWidth>\n <DialogTitle>{'Add a card reader'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'On the reader, open Settings and choose Generate pairing code, then enter the code it shows.'}\n </Typography>\n <TextField\n label=\"Registration code\"\n value={code}\n onChange={(event) => setCode(event.target.value)}\n autoFocus\n slotProps={{ htmlInput: { autoComplete: 'off' } }}\n />\n <TextField label=\"Name\" placeholder=\"Front counter reader\" value={label} onChange={(event) => setLabel(event.target.value)} />\n <TextField select label=\"Register\" value={registerId} onChange={(event) => setRegisterId(event.target.value)}>\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n {answer && !answer.locationReady ? (\n <Box sx={{ display: 'grid', gap: 1.5, gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' } }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ gridColumn: '1 / -1' }}>\n {'Where the reader is used. Stripe sets the reader up for this country.'}\n </Typography>\n <TextField label=\"Street\" value={address.line1} onChange={(event) => setAddress({ ...address, line1: event.target.value })} sx={{ gridColumn: '1 / -1' }} />\n <TextField label=\"City\" value={address.city} onChange={(event) => setAddress({ ...address, city: event.target.value })} />\n <TextField label=\"State\" value={address.state} onChange={(event) => setAddress({ ...address, state: event.target.value })} />\n <TextField label=\"Postal code\" value={address.postalCode} onChange={(event) => setAddress({ ...address, postalCode: event.target.value })} />\n <TextField\n label=\"Country\"\n value={address.country}\n onChange={(event) => setAddress({ ...address, country: event.target.value.toUpperCase().slice(0, 2) })}\n />\n </Box>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setAdding(false)}>{'Cancel'}</Button>\n <Button variant=\"contained\" disabled={busy || !code.trim()} onClick={() => void addReader()}>\n {'Add reader'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nPosDevicesCard.displayName = 'PosDevicesCard'\n\nexport default PosDevicesCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","useFirestore","useFirestoreCollection","useUser","Box","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","limit","query","useCallback","useEffect","useState","posDisplayCall","posReadersCall","PosRequestError","EMPTY_ADDRESS","line1","line2","city","state","postalCode","country","PosDevicesCard","hostId","firestore","data","user","enqueueSnackbar","confirm","registerDocs","idField","registers","sort","a","b","String","name","localeCompare","answer","setAnswer","displays","setDisplays","adding","setAdding","code","setCode","label","setLabel","registerId","setRegisterId","address","setAddress","busy","setBusy","renaming","setRenaming","notify","error","fallback","message","variant","persist","load","refresh","action","uid","registerIds","map","register","$id","join","active","Promise","all","split","id","result","catch","then","entries","Object","fromEntries","registerName","find","addReader","registrationCode","trim","locationReady","readers","showReaders","Boolean","available","header","help","anchor","HeaderProps","size","onClick","undefined","contentGutterX","contentGutterY","spacing","length","color","testMode","reader","direction","sx","alignItems","flexWrap","rowGap","flex","minWidth","component","livemode","status","select","value","onChange","event","readerId","target","confirmed","title","description","confirmationText","confirmationButtonProps","flatMap","display","Date","now","lastSeenAtMs","displayId","prev","filter","entry","open","onClose","maxWidth","fullWidth","autoFocus","mt","disabled","flexDirection","gap","slotProps","htmlInput","autoComplete","placeholder","gridTemplateColumns","xs","sm","gridColumn","toUpperCase","slice","displayName"],"mappings":"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"}
@@ -14,11 +14,14 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ import type * as CommerceModel from '../../../model';
17
18
  import { type PosDisplayBranding } from './pos-display-api';
18
19
  /**
19
20
  * The unpaired display (AGL-3608): six digits from the register's Customer
20
- * display menu, exchanged once for this device's token.
21
+ * display menu, exchanged once for this device's token. A self-service kiosk
22
+ * (AGL-3623) pairs through the same screen with `mode="kiosk"`.
21
23
  */
22
- export declare function PosDisplayPairingScreen({ onPaired, }: {
24
+ export declare function PosDisplayPairingScreen({ onPaired, mode, }: {
23
25
  onPaired: (token: string, branding: PosDisplayBranding) => void;
26
+ mode?: CommerceModel.PosDeviceMode;
24
27
  }): import("react").JSX.Element;
@@ -24,8 +24,10 @@ import { useState } from "react";
24
24
  import { pairDisplay } from "./pos-display-api.js";
25
25
  /**
26
26
  * The unpaired display (AGL-3608): six digits from the register's Customer
27
- * display menu, exchanged once for this device's token.
28
- */ export function PosDisplayPairingScreen({ onPaired }) {
27
+ * display menu, exchanged once for this device's token. A self-service kiosk
28
+ * (AGL-3623) pairs through the same screen with `mode="kiosk"`.
29
+ */ export function PosDisplayPairingScreen({ onPaired, mode = 'display' }) {
30
+ const noun = mode === 'kiosk' ? 'kiosk' : 'display';
29
31
  const [code, setCode] = useState('');
30
32
  const [busy, setBusy] = useState(false);
31
33
  const [error, setError] = useState(null);
@@ -37,7 +39,7 @@ import { pairDisplay } from "./pos-display-api.js";
37
39
  if (!ready || busy) return;
38
40
  setBusy(true);
39
41
  setError(null);
40
- const result = await pairDisplay(code);
42
+ const result = await pairDisplay(code, mode);
41
43
  setBusy(false);
42
44
  const token = result.ok ? (_result_value = result.value) == null ? void 0 : _result_value.token : undefined;
43
45
  setCode('');
@@ -65,7 +67,7 @@ import { pairDisplay } from "./pos-display-api.js";
65
67
  sx: {
66
68
  textAlign: 'center'
67
69
  },
68
- children: "Pair this display"
70
+ children: `Pair this ${noun}`
69
71
  }),
70
72
  /*#__PURE__*/ _jsx(Typography, {
71
73
  variant: "h6",
@@ -118,7 +120,7 @@ import { pairDisplay } from "./pos-display-api.js";
118
120
  maxWidth: theme.spacing(48),
119
121
  minHeight: theme.spacing(8)
120
122
  }, theme.typography.h6),
121
- children: busy ? 'Pairing…' : 'Pair display'
123
+ children: busy ? 'Pairing…' : `Pair ${noun}`
122
124
  })
123
125
  ]
124
126
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-display/pairing-screen.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 Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { type FormEvent, useState } from 'react'\nimport { pairDisplay, type PosDisplayBranding } from './pos-display-api'\n\n/**\n * The unpaired display (AGL-3608): six digits from the register's Customer\n * display menu, exchanged once for this device's token.\n */\nexport function PosDisplayPairingScreen({\n onPaired,\n}: {\n onPaired: (token: string, branding: PosDisplayBranding) => void\n}) {\n const [code, setCode] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const ready = code.length === 6\n\n const submit = async (event: FormEvent) => {\n event.preventDefault()\n if (!ready || busy) return\n setBusy(true)\n setError(null)\n const result = await pairDisplay(code)\n setBusy(false)\n const token = result.ok ? result.value?.token : undefined\n setCode('')\n if (token) {\n onPaired(token, result.value?.branding)\n return\n }\n setError(result.error ?? 'That code is not valid. Show a new code on the register.')\n }\n\n return (\n <Stack\n component=\"form\"\n onSubmit={submit}\n spacing={4}\n sx={{ minHeight: '100dvh', alignItems: 'center', justifyContent: 'center', px: 2 }}\n >\n <Typography variant=\"h3\" component=\"h1\" sx={{ textAlign: 'center' }}>\n Pair this display\n </Typography>\n <Typography variant=\"h6\" color=\"text.secondary\" sx={{ textAlign: 'center' }}>\n Enter the code shown on the register\n </Typography>\n <TextField\n value={code}\n onChange={(event) => setCode(event.target.value.replace(/\\D/g, '').slice(0, 6))}\n autoFocus\n autoComplete=\"one-time-code\"\n placeholder=\"000000\"\n slotProps={{\n htmlInput: {\n inputMode: 'numeric',\n pattern: '[0-9]*',\n maxLength: 6,\n 'aria-label': 'Pairing code',\n style: { textAlign: 'center' },\n },\n }}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n '& input': { ...theme.typography.h3, letterSpacing: theme.spacing(1) },\n })}\n />\n {error ? (\n <Alert severity=\"error\" sx={{ width: '100%', maxWidth: (theme) => theme.spacing(48) }}>\n {error}\n </Alert>\n ) : null}\n <Button\n type=\"submit\"\n variant=\"contained\"\n size=\"large\"\n disabled={!ready || busy}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n minHeight: theme.spacing(8),\n ...theme.typography.h6,\n })}\n >\n {busy ? 'Pairing…' : 'Pair display'}\n </Button>\n </Stack>\n )\n}\n"],"names":["Alert","Button","Stack","TextField","Typography","useState","pairDisplay","PosDisplayPairingScreen","onPaired","code","setCode","busy","setBusy","error","setError","ready","length","submit","event","result","preventDefault","token","ok","value","undefined","branding","component","onSubmit","spacing","sx","minHeight","alignItems","justifyContent","px","variant","textAlign","color","onChange","target","replace","slice","autoFocus","autoComplete","placeholder","slotProps","htmlInput","inputMode","pattern","maxLength","style","theme","width","maxWidth","typography","h3","letterSpacing","severity","type","size","disabled","h6"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,OAAOA,WAAW,sBAAqB;AACvC,OAAOC,YAAY,uBAAsB;AACzC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,eAAe,0BAAyB;AAC/C,OAAOC,gBAAgB,2BAA0B;AACjD,SAAyBC,QAAQ,QAAQ,QAAO;AAChD,SAASC,WAAW,QAAiC,uBAAmB;AAExE;;;CAGC,GACD,OAAO,SAASC,wBAAwB,EACtCC,QAAQ,EAGT;IACC,MAAM,CAACC,MAAMC,QAAQ,GAAGL,SAAS;IACjC,MAAM,CAACM,MAAMC,QAAQ,GAAGP,SAAS;IACjC,MAAM,CAACQ,OAAOC,SAAS,GAAGT,SAAwB;IAClD,MAAMU,QAAQN,KAAKO,MAAM,KAAK;IAE9B,MAAMC,SAAS,OAAOC;YAaXC;YANiBA;QAN1BD,MAAME,cAAc;QACpB,IAAI,CAACL,SAASJ,MAAM;QACpBC,QAAQ;QACRE,SAAS;QACT,MAAMK,SAAS,MAAMb,YAAYG;QACjCG,QAAQ;QACR,MAAMS,QAAQF,OAAOG,EAAE,IAAGH,gBAAAA,OAAOI,KAAK,qBAAZJ,cAAcE,KAAK,GAAGG;QAChDd,QAAQ;QACR,IAAIW,OAAO;gBACOF;YAAhBX,SAASa,QAAOF,iBAAAA,OAAOI,KAAK,qBAAZJ,eAAcM,QAAQ;YACtC;QACF;QACAX,UAASK,gBAAAA,OAAON,KAAK,YAAZM,gBAAgB;IAC3B;IAEA,qBACE,MAACjB;QACCwB,WAAU;QACVC,UAAUV;QACVW,SAAS;QACTC,IAAI;YAAEC,WAAW;YAAUC,YAAY;YAAUC,gBAAgB;YAAUC,IAAI;QAAE;;0BAEjF,KAAC7B;gBAAW8B,SAAQ;gBAAKR,WAAU;gBAAKG,IAAI;oBAAEM,WAAW;gBAAS;0BAAG;;0BAGrE,KAAC/B;gBAAW8B,SAAQ;gBAAKE,OAAM;gBAAiBP,IAAI;oBAAEM,WAAW;gBAAS;0BAAG;;0BAG7E,KAAChC;gBACCoB,OAAOd;gBACP4B,UAAU,CAACnB,QAAUR,QAAQQ,MAAMoB,MAAM,CAACf,KAAK,CAACgB,OAAO,CAAC,OAAO,IAAIC,KAAK,CAAC,GAAG;gBAC5EC,SAAS;gBACTC,cAAa;gBACbC,aAAY;gBACZC,WAAW;oBACTC,WAAW;wBACTC,WAAW;wBACXC,SAAS;wBACTC,WAAW;wBACX,cAAc;wBACdC,OAAO;4BAAEd,WAAW;wBAAS;oBAC/B;gBACF;gBACAN,IAAI,CAACqB,QAAW,CAAA;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxB,WAAW,aAAKsB,MAAMG,UAAU,CAACC,EAAE;4BAAEC,eAAeL,MAAMtB,OAAO,CAAC;;oBACpE,CAAA;;YAEDf,sBACC,KAACb;gBAAMwD,UAAS;gBAAQ3B,IAAI;oBAAEsB,OAAO;oBAAQC,UAAU,CAACF,QAAUA,MAAMtB,OAAO,CAAC;gBAAI;0BACjFf;iBAED;0BACJ,KAACZ;gBACCwD,MAAK;gBACLvB,SAAQ;gBACRwB,MAAK;gBACLC,UAAU,CAAC5C,SAASJ;gBACpBkB,IAAI,CAACqB,QAAW;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxBE,WAAWoB,MAAMtB,OAAO,CAAC;uBACtBsB,MAAMG,UAAU,CAACO,EAAE;0BAGvBjD,OAAO,aAAa;;;;AAI7B"}
1
+ {"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-display/pairing-screen.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 Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { type FormEvent, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { pairDisplay, type PosDisplayBranding } from './pos-display-api'\n\n/**\n * The unpaired display (AGL-3608): six digits from the register's Customer\n * display menu, exchanged once for this device's token. A self-service kiosk\n * (AGL-3623) pairs through the same screen with `mode=\"kiosk\"`.\n */\nexport function PosDisplayPairingScreen({\n onPaired,\n mode = 'display',\n}: {\n onPaired: (token: string, branding: PosDisplayBranding) => void\n mode?: CommerceModel.PosDeviceMode\n}) {\n const noun = mode === 'kiosk' ? 'kiosk' : 'display'\n const [code, setCode] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const ready = code.length === 6\n\n const submit = async (event: FormEvent) => {\n event.preventDefault()\n if (!ready || busy) return\n setBusy(true)\n setError(null)\n const result = await pairDisplay(code, mode)\n setBusy(false)\n const token = result.ok ? result.value?.token : undefined\n setCode('')\n if (token) {\n onPaired(token, result.value?.branding)\n return\n }\n setError(result.error ?? 'That code is not valid. Show a new code on the register.')\n }\n\n return (\n <Stack\n component=\"form\"\n onSubmit={submit}\n spacing={4}\n sx={{ minHeight: '100dvh', alignItems: 'center', justifyContent: 'center', px: 2 }}\n >\n <Typography variant=\"h3\" component=\"h1\" sx={{ textAlign: 'center' }}>\n {`Pair this ${noun}`}\n </Typography>\n <Typography variant=\"h6\" color=\"text.secondary\" sx={{ textAlign: 'center' }}>\n Enter the code shown on the register\n </Typography>\n <TextField\n value={code}\n onChange={(event) => setCode(event.target.value.replace(/\\D/g, '').slice(0, 6))}\n autoFocus\n autoComplete=\"one-time-code\"\n placeholder=\"000000\"\n slotProps={{\n htmlInput: {\n inputMode: 'numeric',\n pattern: '[0-9]*',\n maxLength: 6,\n 'aria-label': 'Pairing code',\n style: { textAlign: 'center' },\n },\n }}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n '& input': { ...theme.typography.h3, letterSpacing: theme.spacing(1) },\n })}\n />\n {error ? (\n <Alert severity=\"error\" sx={{ width: '100%', maxWidth: (theme) => theme.spacing(48) }}>\n {error}\n </Alert>\n ) : null}\n <Button\n type=\"submit\"\n variant=\"contained\"\n size=\"large\"\n disabled={!ready || busy}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n minHeight: theme.spacing(8),\n ...theme.typography.h6,\n })}\n >\n {busy ? 'Pairing…' : `Pair ${noun}`}\n </Button>\n </Stack>\n )\n}\n"],"names":["Alert","Button","Stack","TextField","Typography","useState","pairDisplay","PosDisplayPairingScreen","onPaired","mode","noun","code","setCode","busy","setBusy","error","setError","ready","length","submit","event","result","preventDefault","token","ok","value","undefined","branding","component","onSubmit","spacing","sx","minHeight","alignItems","justifyContent","px","variant","textAlign","color","onChange","target","replace","slice","autoFocus","autoComplete","placeholder","slotProps","htmlInput","inputMode","pattern","maxLength","style","theme","width","maxWidth","typography","h3","letterSpacing","severity","type","size","disabled","h6"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,OAAOA,WAAW,sBAAqB;AACvC,OAAOC,YAAY,uBAAsB;AACzC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,eAAe,0BAAyB;AAC/C,OAAOC,gBAAgB,2BAA0B;AACjD,SAAyBC,QAAQ,QAAQ,QAAO;AAEhD,SAASC,WAAW,QAAiC,uBAAmB;AAExE;;;;CAIC,GACD,OAAO,SAASC,wBAAwB,EACtCC,QAAQ,EACRC,OAAO,SAAS,EAIjB;IACC,MAAMC,OAAOD,SAAS,UAAU,UAAU;IAC1C,MAAM,CAACE,MAAMC,QAAQ,GAAGP,SAAS;IACjC,MAAM,CAACQ,MAAMC,QAAQ,GAAGT,SAAS;IACjC,MAAM,CAACU,OAAOC,SAAS,GAAGX,SAAwB;IAClD,MAAMY,QAAQN,KAAKO,MAAM,KAAK;IAE9B,MAAMC,SAAS,OAAOC;YAaXC;YANiBA;QAN1BD,MAAME,cAAc;QACpB,IAAI,CAACL,SAASJ,MAAM;QACpBC,QAAQ;QACRE,SAAS;QACT,MAAMK,SAAS,MAAMf,YAAYK,MAAMF;QACvCK,QAAQ;QACR,MAAMS,QAAQF,OAAOG,EAAE,IAAGH,gBAAAA,OAAOI,KAAK,qBAAZJ,cAAcE,KAAK,GAAGG;QAChDd,QAAQ;QACR,IAAIW,OAAO;gBACOF;YAAhBb,SAASe,QAAOF,iBAAAA,OAAOI,KAAK,qBAAZJ,eAAcM,QAAQ;YACtC;QACF;QACAX,UAASK,gBAAAA,OAAON,KAAK,YAAZM,gBAAgB;IAC3B;IAEA,qBACE,MAACnB;QACC0B,WAAU;QACVC,UAAUV;QACVW,SAAS;QACTC,IAAI;YAAEC,WAAW;YAAUC,YAAY;YAAUC,gBAAgB;YAAUC,IAAI;QAAE;;0BAEjF,KAAC/B;gBAAWgC,SAAQ;gBAAKR,WAAU;gBAAKG,IAAI;oBAAEM,WAAW;gBAAS;0BAC/D,CAAC,UAAU,EAAE3B,MAAM;;0BAEtB,KAACN;gBAAWgC,SAAQ;gBAAKE,OAAM;gBAAiBP,IAAI;oBAAEM,WAAW;gBAAS;0BAAG;;0BAG7E,KAAClC;gBACCsB,OAAOd;gBACP4B,UAAU,CAACnB,QAAUR,QAAQQ,MAAMoB,MAAM,CAACf,KAAK,CAACgB,OAAO,CAAC,OAAO,IAAIC,KAAK,CAAC,GAAG;gBAC5EC,SAAS;gBACTC,cAAa;gBACbC,aAAY;gBACZC,WAAW;oBACTC,WAAW;wBACTC,WAAW;wBACXC,SAAS;wBACTC,WAAW;wBACX,cAAc;wBACdC,OAAO;4BAAEd,WAAW;wBAAS;oBAC/B;gBACF;gBACAN,IAAI,CAACqB,QAAW,CAAA;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxB,WAAW,aAAKsB,MAAMG,UAAU,CAACC,EAAE;4BAAEC,eAAeL,MAAMtB,OAAO,CAAC;;oBACpE,CAAA;;YAEDf,sBACC,KAACf;gBAAM0D,UAAS;gBAAQ3B,IAAI;oBAAEsB,OAAO;oBAAQC,UAAU,CAACF,QAAUA,MAAMtB,OAAO,CAAC;gBAAI;0BACjFf;iBAED;0BACJ,KAACd;gBACC0D,MAAK;gBACLvB,SAAQ;gBACRwB,MAAK;gBACLC,UAAU,CAAC5C,SAASJ;gBACpBkB,IAAI,CAACqB,QAAW;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxBE,WAAWoB,MAAMtB,OAAO,CAAC;uBACtBsB,MAAMG,UAAU,CAACO,EAAE;0BAGvBjD,OAAO,aAAa,CAAC,KAAK,EAAEH,MAAM;;;;AAI3C"}
@@ -63,8 +63,14 @@ export interface PosDisplayResult<T> {
63
63
  }
64
64
  export declare function readStoredToken(): string | null;
65
65
  export declare function storeToken(token: string | null): void;
66
- export declare function pairDisplay(code: string): Promise<PosDisplayResult<{
66
+ /**
67
+ * Exchanges a register's code for this device's token. `mode` is the kind of
68
+ * screen this page is — a customer display, or a self-service kiosk
69
+ * (AGL-3623) — and a code made for the other kind is refused.
70
+ */
71
+ export declare function pairDisplay(code: string, mode?: CommerceModel.PosDeviceMode): Promise<PosDisplayResult<{
67
72
  token: string;
73
+ mode?: CommerceModel.PosDeviceMode;
68
74
  branding: PosDisplayBranding;
69
75
  }>>;
70
76
  export declare function pollDisplay(token: string, withBranding: boolean): Promise<PosDisplayResult<{
@@ -76,13 +76,18 @@ async function call(init, token) {
76
76
  };
77
77
  }
78
78
  }
79
- export function pairDisplay(code) {
79
+ /**
80
+ * Exchanges a register's code for this device's token. `mode` is the kind of
81
+ * screen this page is — a customer display, or a self-service kiosk
82
+ * (AGL-3623) — and a code made for the other kind is refused.
83
+ */ export function pairDisplay(code, mode = 'display') {
80
84
  return call({
81
85
  method: 'POST',
82
86
  body: {
83
87
  action: 'pair',
84
88
  code,
85
- label: 'Customer display'
89
+ mode,
90
+ label: mode === 'kiosk' ? 'Self-service kiosk' : 'Customer display'
86
91
  }
87
92
  }, null);
88
93
  }