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

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 (609) hide show
  1. package/package.json +13 -13
  2. package/src/index.d.ts +0 -1
  3. package/src/index.js +0 -1
  4. package/src/index.js.map +1 -1
  5. package/src/lib/barcode/barcode-decode.d.ts +71 -0
  6. package/src/lib/barcode/barcode-decode.js +498 -0
  7. package/src/lib/barcode/barcode-decode.js.map +1 -0
  8. package/src/lib/barcode/barcode-encode.d.ts +44 -0
  9. package/src/lib/barcode/barcode-encode.js +138 -0
  10. package/src/lib/barcode/barcode-encode.js.map +1 -0
  11. package/src/lib/barcode/barcode-scanner.component.d.ts +23 -0
  12. package/src/lib/barcode/barcode-scanner.component.js +260 -0
  13. package/src/lib/barcode/barcode-scanner.component.js.map +1 -0
  14. package/src/lib/barcode/scan-button.component.d.ts +10 -0
  15. package/src/lib/barcode/scan-button.component.js +62 -0
  16. package/src/lib/barcode/scan-button.component.js.map +1 -0
  17. package/src/lib/barcode/scanner-wedge.d.ts +35 -0
  18. package/src/lib/barcode/scanner-wedge.js +108 -0
  19. package/src/lib/barcode/scanner-wedge.js.map +1 -0
  20. package/src/lib/components/account.js +10 -1
  21. package/src/lib/components/account.js.map +1 -1
  22. package/src/lib/components/cart-extras.d.ts +45 -0
  23. package/src/lib/components/cart-extras.js +127 -0
  24. package/src/lib/components/cart-extras.js.map +1 -0
  25. package/src/lib/components/cart.js +82 -15
  26. package/src/lib/components/cart.js.map +1 -1
  27. package/src/lib/components/checkout-return-notice.d.ts +26 -0
  28. package/src/lib/components/checkout-return-notice.js +48 -0
  29. package/src/lib/components/checkout-return-notice.js.map +1 -0
  30. package/src/lib/components/commerce-console-page.js +124 -0
  31. package/src/lib/components/commerce-console-page.js.map +1 -1
  32. package/src/lib/components/commerce-console-sections.d.ts +1 -1
  33. package/src/lib/components/commerce-console-sections.js +4 -0
  34. package/src/lib/components/commerce-console-sections.js.map +1 -1
  35. package/src/lib/components/console/bulk-fulfill.d.ts +44 -0
  36. package/src/lib/components/console/bulk-fulfill.js +84 -0
  37. package/src/lib/components/console/bulk-fulfill.js.map +1 -0
  38. package/src/lib/components/console/catalog-organization-card.component.js +1 -0
  39. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  40. package/src/lib/components/console/customer-notifications-card.component.d.ts +19 -0
  41. package/src/lib/components/console/customer-notifications-card.component.js +149 -0
  42. package/src/lib/components/console/customer-notifications-card.component.js.map +1 -0
  43. package/src/lib/components/console/host-orders-card.component.js +88 -6
  44. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  45. package/src/lib/components/console/locations-card.component.js +164 -57
  46. package/src/lib/components/console/locations-card.component.js.map +1 -1
  47. package/src/lib/components/console/order-detail-dialog.component.js +209 -61
  48. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  49. package/src/lib/components/console/order-fulfillment-panel.component.d.ts +48 -0
  50. package/src/lib/components/console/order-fulfillment-panel.component.js +542 -0
  51. package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -0
  52. package/src/lib/components/console/order-invoice.component.d.ts +33 -0
  53. package/src/lib/components/console/order-invoice.component.js +81 -0
  54. package/src/lib/components/console/order-invoice.component.js.map +1 -0
  55. package/src/lib/components/console/order-receipt-resend.component.d.ts +21 -0
  56. package/src/lib/components/console/order-receipt-resend.component.js +203 -0
  57. package/src/lib/components/console/order-receipt-resend.component.js.map +1 -0
  58. package/src/lib/components/console/order-returns.component.d.ts +36 -0
  59. package/src/lib/components/console/order-returns.component.js +142 -0
  60. package/src/lib/components/console/order-returns.component.js.map +1 -0
  61. package/src/lib/components/console/order-shipping-actions.component.d.ts +54 -0
  62. package/src/lib/components/console/order-shipping-actions.component.js +149 -0
  63. package/src/lib/components/console/order-shipping-actions.component.js.map +1 -0
  64. package/src/lib/components/console/order-webhooks-card.component.d.ts +50 -0
  65. package/src/lib/components/console/order-webhooks-card.component.js +623 -0
  66. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -0
  67. package/src/lib/components/console/order-zones.d.ts +155 -0
  68. package/src/lib/components/console/order-zones.js +40 -0
  69. package/src/lib/components/console/order-zones.js.map +1 -0
  70. package/src/lib/components/console/payment-methods-card.component.d.ts +67 -0
  71. package/src/lib/components/console/payment-methods-card.component.js +395 -0
  72. package/src/lib/components/console/payment-methods-card.component.js.map +1 -0
  73. package/src/lib/components/console/pos/pos-api.d.ts +124 -0
  74. package/src/lib/components/console/pos/pos-api.js +101 -0
  75. package/src/lib/components/console/pos/pos-api.js.map +1 -0
  76. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +36 -0
  77. package/src/lib/components/console/pos/pos-cart-panel.component.js +160 -0
  78. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -0
  79. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +39 -0
  80. package/src/lib/components/console/pos/pos-item-dialog.component.js +352 -0
  81. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -0
  82. package/src/lib/components/console/pos/pos-product-grid.component.d.ts +47 -0
  83. package/src/lib/components/console/pos/pos-product-grid.component.js +272 -0
  84. package/src/lib/components/console/pos/pos-product-grid.component.js.map +1 -0
  85. package/src/lib/components/console/pos/pos-receipt-panel.component.d.ts +27 -0
  86. package/src/lib/components/console/pos/pos-receipt-panel.component.js +282 -0
  87. package/src/lib/components/console/pos/pos-receipt-panel.component.js.map +1 -0
  88. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +53 -0
  89. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +445 -0
  90. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -0
  91. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +31 -0
  92. package/src/lib/components/console/pos/pos-tender-panel.component.js +640 -0
  93. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -0
  94. package/src/lib/components/console/pos/use-pos-display.d.ts +43 -0
  95. package/src/lib/components/console/pos/use-pos-display.js +161 -0
  96. package/src/lib/components/console/pos/use-pos-display.js.map +1 -0
  97. package/src/lib/components/console/pos-devices-card.component.d.ts +14 -0
  98. package/src/lib/components/console/pos-devices-card.component.js +546 -0
  99. package/src/lib/components/console/pos-devices-card.component.js.map +1 -0
  100. package/src/lib/components/console/pos-display/brand-screen.d.ts +33 -0
  101. package/src/lib/components/console/pos-display/brand-screen.js +85 -0
  102. package/src/lib/components/console/pos-display/brand-screen.js.map +1 -0
  103. package/src/lib/components/console/pos-display/cart-screen.d.ts +29 -0
  104. package/src/lib/components/console/pos-display/cart-screen.js +166 -0
  105. package/src/lib/components/console/pos-display/cart-screen.js.map +1 -0
  106. package/src/lib/components/console/pos-display/pairing-screen.d.ts +24 -0
  107. package/src/lib/components/console/pos-display/pairing-screen.js +127 -0
  108. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -0
  109. package/src/lib/components/console/pos-display/pos-display-api.d.ts +90 -0
  110. package/src/lib/components/console/pos-display/pos-display-api.js +140 -0
  111. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -0
  112. package/src/lib/components/console/pos-display/receipt-screen.d.ts +35 -0
  113. package/src/lib/components/console/pos-display/receipt-screen.js +200 -0
  114. package/src/lib/components/console/pos-display/receipt-screen.js.map +1 -0
  115. package/src/lib/components/console/pos-display/tip-screen.d.ts +36 -0
  116. package/src/lib/components/console/pos-display/tip-screen.js +211 -0
  117. package/src/lib/components/console/pos-display/tip-screen.js.map +1 -0
  118. package/src/lib/components/console/pos-display-page.component.d.ts +16 -0
  119. package/src/lib/components/console/pos-display-page.component.js +407 -0
  120. package/src/lib/components/console/pos-display-page.component.js.map +1 -0
  121. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +40 -0
  122. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +289 -0
  123. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -0
  124. package/src/lib/components/console/pos-ops/pos-last-receipt.component.d.ts +34 -0
  125. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js +61 -0
  126. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js.map +1 -0
  127. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +38 -0
  128. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +129 -0
  129. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -0
  130. package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +37 -0
  131. package/src/lib/components/console/pos-ops/pos-ops-api.js +60 -0
  132. package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -0
  133. package/src/lib/components/console/pos-ops/pos-pin-pad.component.d.ts +48 -0
  134. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js +220 -0
  135. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js.map +1 -0
  136. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.d.ts +63 -0
  137. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js +186 -0
  138. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js.map +1 -0
  139. package/src/lib/components/console/pos-ops/pos-receipt.d.ts +39 -0
  140. package/src/lib/components/console/pos-ops/pos-receipt.js +182 -0
  141. package/src/lib/components/console/pos-ops/pos-receipt.js.map +1 -0
  142. package/src/lib/components/console/pos-ops/pos-return-dialog.component.d.ts +40 -0
  143. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js +465 -0
  144. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js.map +1 -0
  145. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.d.ts +29 -0
  146. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +253 -0
  147. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -0
  148. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +34 -0
  149. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +494 -0
  150. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -0
  151. package/src/lib/components/console/pos-ops/pos-shift-report.component.d.ts +37 -0
  152. package/src/lib/components/console/pos-ops/pos-shift-report.component.js +102 -0
  153. package/src/lib/components/console/pos-ops/pos-shift-report.component.js.map +1 -0
  154. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.d.ts +30 -0
  155. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js +277 -0
  156. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js.map +1 -0
  157. package/src/lib/components/console/pos-ops/register-ops.d.ts +28 -0
  158. package/src/lib/components/console/pos-ops/register-ops.js +28 -0
  159. package/src/lib/components/console/pos-ops/register-ops.js.map +1 -0
  160. package/src/lib/components/console/pos-ops/use-pos-cashier.d.ts +46 -0
  161. package/src/lib/components/console/pos-ops/use-pos-cashier.js +128 -0
  162. package/src/lib/components/console/pos-ops/use-pos-cashier.js.map +1 -0
  163. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.d.ts +36 -0
  164. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js +64 -0
  165. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js.map +1 -0
  166. package/src/lib/components/console/pos-page.component.d.ts +13 -5
  167. package/src/lib/components/console/pos-page.component.js +756 -654
  168. package/src/lib/components/console/pos-page.component.js.map +1 -1
  169. package/src/lib/components/console/pos-zones.d.ts +23 -0
  170. package/src/lib/components/console/pos-zones.js +31 -0
  171. package/src/lib/components/console/pos-zones.js.map +1 -0
  172. package/src/lib/components/console/product-editor-dialog.component.js +61 -71
  173. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  174. package/src/lib/components/console/product-labels-dialog.component.d.ts +13 -0
  175. package/src/lib/components/console/product-labels-dialog.component.js +197 -0
  176. package/src/lib/components/console/product-labels-dialog.component.js.map +1 -0
  177. package/src/lib/components/console/product-register-fields.component.d.ts +19 -0
  178. package/src/lib/components/console/product-register-fields.component.js +241 -0
  179. package/src/lib/components/console/product-register-fields.component.js.map +1 -0
  180. package/src/lib/components/console/product-zones.d.ts +44 -0
  181. package/src/lib/components/console/product-zones.js.map +1 -1
  182. package/src/lib/components/console/products-hub-card.component.js +23 -20
  183. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  184. package/src/lib/components/console/register-hardware-card.component.d.ts +33 -0
  185. package/src/lib/components/console/register-hardware-card.component.js +826 -0
  186. package/src/lib/components/console/register-hardware-card.component.js.map +1 -0
  187. package/src/lib/components/console/registers-card.component.js +24 -5
  188. package/src/lib/components/console/registers-card.component.js.map +1 -1
  189. package/src/lib/components/console/return-actions.d.ts +38 -0
  190. package/src/lib/components/console/return-actions.js +76 -0
  191. package/src/lib/components/console/return-actions.js.map +1 -0
  192. package/src/lib/components/console/return-detail-dialog.component.d.ts +34 -0
  193. package/src/lib/components/console/return-detail-dialog.component.js +718 -0
  194. package/src/lib/components/console/return-detail-dialog.component.js.map +1 -0
  195. package/src/lib/components/console/return-settings-card.component.d.ts +34 -0
  196. package/src/lib/components/console/return-settings-card.component.js +195 -0
  197. package/src/lib/components/console/return-settings-card.component.js.map +1 -0
  198. package/src/lib/components/console/return-zones.d.ts +87 -0
  199. package/src/lib/components/console/return-zones.js +31 -0
  200. package/src/lib/components/console/return-zones.js.map +1 -0
  201. package/src/lib/components/console/returns-card.component.d.ts +45 -0
  202. package/src/lib/components/console/returns-card.component.js +159 -0
  203. package/src/lib/components/console/returns-card.component.js.map +1 -0
  204. package/src/lib/components/console/shipping-settings-card.component.js +161 -5
  205. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  206. package/src/lib/components/console/shippingeasy-card.component.d.ts +59 -0
  207. package/src/lib/components/console/shippingeasy-card.component.js +378 -0
  208. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -0
  209. package/src/lib/components/console/shipstation-card.component.d.ts +35 -0
  210. package/src/lib/components/console/shipstation-card.component.js +345 -0
  211. package/src/lib/components/console/shipstation-card.component.js.map +1 -0
  212. package/src/lib/components/console/start-return-dialog.component.d.ts +40 -0
  213. package/src/lib/components/console/start-return-dialog.component.js +243 -0
  214. package/src/lib/components/console/start-return-dialog.component.js.map +1 -0
  215. package/src/lib/components/console/stock-movements-card.component.js +2 -1
  216. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  217. package/src/lib/components/console/store-settings-card.component.js +2 -66
  218. package/src/lib/components/console/store-settings-card.component.js.map +1 -1
  219. package/src/lib/components/console/store-zones.d.ts +42 -0
  220. package/src/lib/components/console/store-zones.js +39 -0
  221. package/src/lib/components/console/store-zones.js.map +1 -0
  222. package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
  223. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
  224. package/src/lib/components/order-status.d.ts +36 -0
  225. package/src/lib/components/order-status.js +502 -0
  226. package/src/lib/components/order-status.js.map +1 -0
  227. package/src/lib/components/product-detail.js +41 -2
  228. package/src/lib/components/product-detail.js.map +1 -1
  229. package/src/lib/components/return-request.d.ts +32 -0
  230. package/src/lib/components/return-request.js +576 -0
  231. package/src/lib/components/return-request.js.map +1 -0
  232. package/src/lib/components/storefront-payment-appearance.d.ts +32 -0
  233. package/src/lib/components/storefront-payment-appearance.js +114 -0
  234. package/src/lib/components/storefront-payment-appearance.js.map +1 -0
  235. package/src/lib/components/storefront-payment-element.d.ts +57 -1
  236. package/src/lib/components/storefront-payment-element.js +332 -33
  237. package/src/lib/components/storefront-payment-element.js.map +1 -1
  238. package/src/lib/constants/order-status.d.ts +22 -0
  239. package/src/lib/constants/order-status.js +22 -0
  240. package/src/lib/constants/order-status.js.map +1 -0
  241. package/src/lib/constants/return-request.d.ts +27 -0
  242. package/src/lib/constants/return-request.js +32 -0
  243. package/src/lib/constants/return-request.js.map +1 -0
  244. package/src/lib/constants/stock-movement-query.js +2 -1
  245. package/src/lib/constants/stock-movement-query.js.map +1 -1
  246. package/src/lib/declarations.console-server.js +9 -0
  247. package/src/lib/declarations.console-server.js.map +1 -1
  248. package/src/lib/declarations.server.d.ts +2 -1
  249. package/src/lib/declarations.server.js +68 -1
  250. package/src/lib/declarations.server.js.map +1 -1
  251. package/src/lib/model/buyer-notifications.d.ts +59 -0
  252. package/src/lib/model/buyer-notifications.js +97 -0
  253. package/src/lib/model/buyer-notifications.js.map +1 -0
  254. package/src/lib/model/commerce-orders.d.ts +171 -2
  255. package/src/lib/model/commerce-orders.js +26 -16
  256. package/src/lib/model/commerce-orders.js.map +1 -1
  257. package/src/lib/model/commerce-payment-methods.d.ts +146 -0
  258. package/src/lib/model/commerce-payment-methods.js +247 -0
  259. package/src/lib/model/commerce-payment-methods.js.map +1 -0
  260. package/src/lib/model/commerce-pos-ops.d.ts +437 -0
  261. package/src/lib/model/commerce-pos-ops.js +721 -0
  262. package/src/lib/model/commerce-pos-ops.js.map +1 -0
  263. package/src/lib/model/commerce-pos.d.ts +263 -0
  264. package/src/lib/model/commerce-pos.js +375 -0
  265. package/src/lib/model/commerce-pos.js.map +1 -0
  266. package/src/lib/model/commerce-printers.d.ts +211 -0
  267. package/src/lib/model/commerce-printers.js +181 -0
  268. package/src/lib/model/commerce-printers.js.map +1 -0
  269. package/src/lib/model/commerce-receipt.d.ts +97 -0
  270. package/src/lib/model/commerce-receipt.js +180 -0
  271. package/src/lib/model/commerce-receipt.js.map +1 -0
  272. package/src/lib/model/commerce-returns.d.ts +207 -0
  273. package/src/lib/model/commerce-returns.js +300 -0
  274. package/src/lib/model/commerce-returns.js.map +1 -0
  275. package/src/lib/model/commerce-shipping.d.ts +44 -1
  276. package/src/lib/model/commerce-shipping.js +53 -9
  277. package/src/lib/model/commerce-shipping.js.map +1 -1
  278. package/src/lib/model/commerce-tax-engine.d.ts +90 -0
  279. package/src/lib/model/commerce-tax-engine.js +129 -0
  280. package/src/lib/model/commerce-tax-engine.js.map +1 -0
  281. package/src/lib/model/commerce.d.ts +91 -2
  282. package/src/lib/model/commerce.js +89 -1
  283. package/src/lib/model/commerce.js.map +1 -1
  284. package/src/lib/model/index.d.ts +16 -0
  285. package/src/lib/model/index.js +16 -0
  286. package/src/lib/model/index.js.map +1 -1
  287. package/src/lib/model/order-events.d.ts +154 -0
  288. package/src/lib/model/order-events.js +153 -0
  289. package/src/lib/model/order-events.js.map +1 -0
  290. package/src/lib/model/order-fulfillment.d.ts +117 -0
  291. package/src/lib/model/order-fulfillment.js +217 -0
  292. package/src/lib/model/order-fulfillment.js.map +1 -0
  293. package/src/lib/model/order-history.d.ts +58 -0
  294. package/src/lib/model/order-history.js +22 -0
  295. package/src/lib/model/order-history.js.map +1 -0
  296. package/src/lib/model/order-list-fields.d.ts +9 -1
  297. package/src/lib/model/order-list-fields.js +7 -1
  298. package/src/lib/model/order-list-fields.js.map +1 -1
  299. package/src/lib/model/order-shipping-export.d.ts +91 -0
  300. package/src/lib/model/order-shipping-export.js +192 -0
  301. package/src/lib/model/order-shipping-export.js.map +1 -0
  302. package/src/lib/model/order-status-view.d.ts +103 -0
  303. package/src/lib/model/order-status-view.js +156 -0
  304. package/src/lib/model/order-status-view.js.map +1 -0
  305. package/src/lib/model/order-webhooks.d.ts +142 -0
  306. package/src/lib/model/order-webhooks.js +91 -0
  307. package/src/lib/model/order-webhooks.js.map +1 -0
  308. package/src/lib/model/product-channel.d.ts +56 -0
  309. package/src/lib/model/product-channel.js +86 -0
  310. package/src/lib/model/product-channel.js.map +1 -0
  311. package/src/lib/model/product-modifiers.d.ts +80 -0
  312. package/src/lib/model/product-modifiers.js +140 -0
  313. package/src/lib/model/product-modifiers.js.map +1 -0
  314. package/src/lib/model/product-write.d.ts +186 -0
  315. package/src/lib/model/product-write.js +116 -0
  316. package/src/lib/model/product-write.js.map +1 -0
  317. package/src/lib/model/shippingeasy.d.ts +94 -0
  318. package/src/lib/model/shippingeasy.js +267 -0
  319. package/src/lib/model/shippingeasy.js.map +1 -0
  320. package/src/lib/model/shipstation.d.ts +125 -0
  321. package/src/lib/model/shipstation.js +399 -0
  322. package/src/lib/model/shipstation.js.map +1 -0
  323. package/src/lib/model/smart-collection-reads.d.ts +32 -0
  324. package/src/lib/model/smart-collection-reads.js +63 -0
  325. package/src/lib/model/smart-collection-reads.js.map +1 -0
  326. package/src/lib/model/tracking-url.d.ts +74 -0
  327. package/src/lib/model/tracking-url.js +159 -0
  328. package/src/lib/model/tracking-url.js.map +1 -0
  329. package/src/lib/plugin-config.d.ts +13 -0
  330. package/src/lib/plugin-config.js +77 -5
  331. package/src/lib/plugin-config.js.map +1 -1
  332. package/src/lib/plugin.js +26 -0
  333. package/src/lib/plugin.js.map +1 -1
  334. package/src/lib/pos-ops-config.d.ts +39 -0
  335. package/src/lib/pos-ops-config.js +88 -0
  336. package/src/lib/pos-ops-config.js.map +1 -0
  337. package/src/lib/printing/print-document.d.ts +106 -0
  338. package/src/lib/printing/print-document.js +464 -0
  339. package/src/lib/printing/print-document.js.map +1 -0
  340. package/src/lib/printing/product-labels.d.ts +58 -0
  341. package/src/lib/printing/product-labels.js +116 -0
  342. package/src/lib/printing/product-labels.js.map +1 -0
  343. package/src/lib/printing/render-epson.d.ts +57 -0
  344. package/src/lib/printing/render-epson.js +135 -0
  345. package/src/lib/printing/render-epson.js.map +1 -0
  346. package/src/lib/printing/render-star.d.ts +45 -0
  347. package/src/lib/printing/render-star.js +100 -0
  348. package/src/lib/printing/render-star.js.map +1 -0
  349. package/src/lib/printing/render-text.d.ts +25 -0
  350. package/src/lib/printing/render-text.js +53 -0
  351. package/src/lib/printing/render-text.js.map +1 -0
  352. package/src/lib/server/api-v1/openapi.js +27 -4
  353. package/src/lib/server/api-v1/openapi.js.map +1 -1
  354. package/src/lib/server/api-v1/order-view.d.ts +67 -0
  355. package/src/lib/server/api-v1/order-view.js +120 -0
  356. package/src/lib/server/api-v1/order-view.js.map +1 -0
  357. package/src/lib/server/api-v1/orders-and-products.js +58 -65
  358. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  359. package/src/lib/server/billing-webhook.js +135 -28
  360. package/src/lib/server/billing-webhook.js.map +1 -1
  361. package/src/lib/server/cancel-order.js +29 -0
  362. package/src/lib/server/cancel-order.js.map +1 -1
  363. package/src/lib/server/carrier-rates-availability.d.ts +26 -0
  364. package/src/lib/server/carrier-rates-availability.js +76 -0
  365. package/src/lib/server/carrier-rates-availability.js.map +1 -0
  366. package/src/lib/server/carrier-shipping.d.ts +84 -0
  367. package/src/lib/server/carrier-shipping.js +135 -0
  368. package/src/lib/server/carrier-shipping.js.map +1 -0
  369. package/src/lib/server/cart-checkout.d.ts +2 -0
  370. package/src/lib/server/cart-checkout.js +226 -22
  371. package/src/lib/server/cart-checkout.js.map +1 -1
  372. package/src/lib/server/channel-order-updates.d.ts +50 -0
  373. package/src/lib/server/channel-order-updates.js +290 -0
  374. package/src/lib/server/channel-order-updates.js.map +1 -0
  375. package/src/lib/server/channel-orders.d.ts +85 -0
  376. package/src/lib/server/channel-orders.js +543 -0
  377. package/src/lib/server/channel-orders.js.map +1 -0
  378. package/src/lib/server/checkout-extras.d.ts +64 -0
  379. package/src/lib/server/checkout-extras.js +157 -0
  380. package/src/lib/server/checkout-extras.js.map +1 -0
  381. package/src/lib/server/{feed.d.ts → checkout-status.d.ts} +2 -7
  382. package/src/lib/server/checkout-status.js +111 -0
  383. package/src/lib/server/checkout-status.js.map +1 -0
  384. package/src/lib/server/checkout.js +86 -9
  385. package/src/lib/server/checkout.js.map +1 -1
  386. package/src/lib/server/draft-order.js +34 -5
  387. package/src/lib/server/draft-order.js.map +1 -1
  388. package/src/lib/server/fulfill-order.d.ts +127 -10
  389. package/src/lib/server/fulfill-order.js +451 -49
  390. package/src/lib/server/fulfill-order.js.map +1 -1
  391. package/src/lib/server/legacy-feed.d.ts +28 -0
  392. package/src/lib/server/legacy-feed.js +52 -0
  393. package/src/lib/server/legacy-feed.js.map +1 -0
  394. package/src/lib/server/native-checkout.d.ts +34 -15
  395. package/src/lib/server/native-checkout.js +32 -17
  396. package/src/lib/server/native-checkout.js.map +1 -1
  397. package/src/lib/server/order-event-host-emit.d.ts +23 -0
  398. package/src/lib/server/order-event-host-emit.js +30 -0
  399. package/src/lib/server/order-event-host-emit.js.map +1 -0
  400. package/src/lib/server/order-event-triggers.d.ts +37 -0
  401. package/src/lib/server/order-event-triggers.js +119 -0
  402. package/src/lib/server/order-event-triggers.js.map +1 -0
  403. package/src/lib/server/order-events.d.ts +62 -0
  404. package/src/lib/server/order-events.js +109 -0
  405. package/src/lib/server/order-events.js.map +1 -0
  406. package/src/lib/server/order-history.d.ts +23 -0
  407. package/src/lib/server/order-history.js +65 -0
  408. package/src/lib/server/order-history.js.map +1 -0
  409. package/src/lib/server/order-notifications.d.ts +185 -0
  410. package/src/lib/server/order-notifications.js +567 -0
  411. package/src/lib/server/order-notifications.js.map +1 -0
  412. package/src/lib/server/order-receipt-send.d.ts +39 -0
  413. package/src/lib/server/order-receipt-send.js +151 -0
  414. package/src/lib/server/order-receipt-send.js.map +1 -0
  415. package/src/lib/server/order-status-token.d.ts +31 -0
  416. package/src/lib/server/order-status-token.js +75 -0
  417. package/src/lib/server/order-status-token.js.map +1 -0
  418. package/src/lib/server/order-status.d.ts +58 -0
  419. package/src/lib/server/order-status.js +141 -0
  420. package/src/lib/server/order-status.js.map +1 -0
  421. package/src/lib/server/order-webhooks.d.ts +108 -0
  422. package/src/lib/server/order-webhooks.js +622 -0
  423. package/src/lib/server/order-webhooks.js.map +1 -0
  424. package/src/lib/server/orders-shipping-prepare.d.ts +26 -0
  425. package/src/lib/server/orders-shipping-prepare.js +121 -0
  426. package/src/lib/server/orders-shipping-prepare.js.map +1 -0
  427. package/src/lib/server/payment-method-domains.d.ts +209 -0
  428. package/src/lib/server/payment-method-domains.js +444 -0
  429. package/src/lib/server/payment-method-domains.js.map +1 -0
  430. package/src/lib/server/payment-methods.d.ts +77 -0
  431. package/src/lib/server/payment-methods.js +284 -0
  432. package/src/lib/server/payment-methods.js.map +1 -0
  433. package/src/lib/server/pos-auth.d.ts +50 -0
  434. package/src/lib/server/pos-auth.js +121 -0
  435. package/src/lib/server/pos-auth.js.map +1 -0
  436. package/src/lib/server/pos-customer.d.ts +49 -0
  437. package/src/lib/server/pos-customer.js +257 -0
  438. package/src/lib/server/pos-customer.js.map +1 -0
  439. package/src/lib/server/pos-display.d.ts +57 -0
  440. package/src/lib/server/pos-display.js +419 -0
  441. package/src/lib/server/pos-display.js.map +1 -0
  442. package/src/lib/server/pos-fee-month.d.ts +34 -0
  443. package/src/lib/server/pos-fee-month.js +36 -0
  444. package/src/lib/server/pos-fee-month.js.map +1 -0
  445. package/src/lib/server/pos-ops-gate.d.ts +161 -0
  446. package/src/lib/server/pos-ops-gate.js +295 -0
  447. package/src/lib/server/pos-ops-gate.js.map +1 -0
  448. package/src/lib/server/pos-ops-routes.d.ts +22 -0
  449. package/src/lib/server/pos-ops-routes.js +36 -0
  450. package/src/lib/server/pos-ops-routes.js.map +1 -0
  451. package/src/lib/server/pos-order.d.ts +1 -18
  452. package/src/lib/server/pos-order.js +222 -42
  453. package/src/lib/server/pos-order.js.map +1 -1
  454. package/src/lib/server/pos-payment.d.ts +39 -0
  455. package/src/lib/server/pos-payment.js +922 -0
  456. package/src/lib/server/pos-payment.js.map +1 -0
  457. package/src/lib/server/pos-print.d.ts +82 -0
  458. package/src/lib/server/pos-print.js +193 -0
  459. package/src/lib/server/pos-print.js.map +1 -0
  460. package/src/lib/server/pos-readers.d.ts +27 -0
  461. package/src/lib/server/pos-readers.js +276 -0
  462. package/src/lib/server/pos-readers.js.map +1 -0
  463. package/src/lib/server/pos-refund-authority.d.ts +60 -0
  464. package/src/lib/server/pos-refund-authority.js +72 -0
  465. package/src/lib/server/pos-refund-authority.js.map +1 -0
  466. package/src/lib/server/pos-return.d.ts +58 -0
  467. package/src/lib/server/pos-return.js +891 -0
  468. package/src/lib/server/pos-return.js.map +1 -0
  469. package/src/lib/server/pos-sale-stamp.d.ts +66 -0
  470. package/src/lib/server/pos-sale-stamp.js +84 -0
  471. package/src/lib/server/pos-sale-stamp.js.map +1 -0
  472. package/src/lib/server/pos-sale.d.ts +170 -0
  473. package/src/lib/server/pos-sale.js +461 -0
  474. package/src/lib/server/pos-sale.js.map +1 -0
  475. package/src/lib/server/pos-shift.d.ts +45 -0
  476. package/src/lib/server/pos-shift.js +484 -0
  477. package/src/lib/server/pos-shift.js.map +1 -0
  478. package/src/lib/server/pos-staff-pin.d.ts +26 -0
  479. package/src/lib/server/pos-staff-pin.js +339 -0
  480. package/src/lib/server/pos-staff-pin.js.map +1 -0
  481. package/src/lib/server/pos-stripe.d.ts +91 -0
  482. package/src/lib/server/pos-stripe.js +129 -0
  483. package/src/lib/server/pos-stripe.js.map +1 -0
  484. package/src/lib/server/pos-terminal-connection-token.d.ts +48 -0
  485. package/src/lib/server/pos-terminal-connection-token.js +166 -0
  486. package/src/lib/server/pos-terminal-connection-token.js.map +1 -0
  487. package/src/lib/server/pos-terminal.d.ts +218 -0
  488. package/src/lib/server/pos-terminal.js +1014 -0
  489. package/src/lib/server/pos-terminal.js.map +1 -0
  490. package/src/lib/server/print-queue.d.ts +124 -0
  491. package/src/lib/server/print-queue.js +301 -0
  492. package/src/lib/server/print-queue.js.map +1 -0
  493. package/src/lib/server/printer-poll.d.ts +75 -0
  494. package/src/lib/server/printer-poll.js +325 -0
  495. package/src/lib/server/printer-poll.js.map +1 -0
  496. package/src/lib/server/printer-secret.d.ts +39 -0
  497. package/src/lib/server/printer-secret.js +56 -0
  498. package/src/lib/server/printer-secret.js.map +1 -0
  499. package/src/lib/server/printers.d.ts +114 -0
  500. package/src/lib/server/printers.js +546 -0
  501. package/src/lib/server/printers.js.map +1 -0
  502. package/src/lib/server/product-catalog.d.ts +42 -0
  503. package/src/lib/server/product-catalog.js +309 -0
  504. package/src/lib/server/product-catalog.js.map +1 -0
  505. package/src/lib/server/product-drafts.d.ts +5 -1
  506. package/src/lib/server/product-drafts.js +3 -3
  507. package/src/lib/server/product-drafts.js.map +1 -1
  508. package/src/lib/server/product-writer.d.ts +19 -0
  509. package/src/lib/server/product-writer.js +261 -0
  510. package/src/lib/server/product-writer.js.map +1 -0
  511. package/src/lib/server/products-write.d.ts +61 -0
  512. package/src/lib/server/products-write.js +375 -0
  513. package/src/lib/server/products-write.js.map +1 -0
  514. package/src/lib/server/refund.js +110 -45
  515. package/src/lib/server/refund.js.map +1 -1
  516. package/src/lib/server/reserve.js +2 -0
  517. package/src/lib/server/reserve.js.map +1 -1
  518. package/src/lib/server/return-status-action.d.ts +37 -0
  519. package/src/lib/server/return-status-action.js +57 -0
  520. package/src/lib/server/return-status-action.js.map +1 -0
  521. package/src/lib/server/returns.d.ts +119 -0
  522. package/src/lib/server/returns.js +938 -0
  523. package/src/lib/server/returns.js.map +1 -0
  524. package/src/lib/server/shipment-records.d.ts +36 -0
  525. package/src/lib/server/shipment-records.js +289 -0
  526. package/src/lib/server/shipment-records.js.map +1 -0
  527. package/src/lib/server/shipping-connector-gates.d.ts +40 -0
  528. package/src/lib/server/shipping-connector-gates.js +97 -0
  529. package/src/lib/server/shipping-connector-gates.js.map +1 -0
  530. package/src/lib/server/shipping-connectors.d.ts +29 -0
  531. package/src/lib/server/shipping-connectors.js +236 -0
  532. package/src/lib/server/shipping-connectors.js.map +1 -0
  533. package/src/lib/server/shippingeasy.d.ts +238 -0
  534. package/src/lib/server/shippingeasy.js +787 -0
  535. package/src/lib/server/shippingeasy.js.map +1 -0
  536. package/src/lib/server/shipstation.d.ts +129 -0
  537. package/src/lib/server/shipstation.js +483 -0
  538. package/src/lib/server/shipstation.js.map +1 -0
  539. package/src/lib/server/site-page-resolver.d.ts +5 -0
  540. package/src/lib/server/site-page-resolver.js +156 -1
  541. package/src/lib/server/site-page-resolver.js.map +1 -1
  542. package/src/lib/server/stock-levels.d.ts +21 -0
  543. package/src/lib/server/stock-levels.js +263 -0
  544. package/src/lib/server/stock-levels.js.map +1 -0
  545. package/src/lib/server/stripe-refund.d.ts +47 -0
  546. package/src/lib/server/stripe-refund.js +87 -0
  547. package/src/lib/server/stripe-refund.js.map +1 -0
  548. package/src/lib/server/supplier-update.js +46 -5
  549. package/src/lib/server/supplier-update.js.map +1 -1
  550. package/src/lib/server/tax-engine-quote.d.ts +47 -0
  551. package/src/lib/server/tax-engine-quote.js +105 -0
  552. package/src/lib/server/tax-engine-quote.js.map +1 -0
  553. package/src/lib/server.js +143 -2
  554. package/src/lib/server.js.map +1 -1
  555. package/src/lib/site.js +12 -0
  556. package/src/lib/site.js.map +1 -1
  557. package/src/lib/subprocessors.d.ts +26 -0
  558. package/src/lib/subprocessors.js +50 -0
  559. package/src/lib/subprocessors.js.map +1 -0
  560. package/src/lib/tenant-emails.js +461 -3
  561. package/src/lib/tenant-emails.js.map +1 -1
  562. package/src/lib/testing/fake-firestore.d.ts +45 -0
  563. package/src/lib/testing/fake-firestore.js +189 -0
  564. package/src/lib/testing/fake-firestore.js.map +1 -0
  565. package/src/lib/testing/memory-firestore.d.ts +136 -0
  566. package/src/lib/testing/memory-firestore.js +282 -0
  567. package/src/lib/testing/memory-firestore.js.map +1 -0
  568. package/src/lib/testing/pos-ops-harness.d.ts +50 -0
  569. package/src/lib/testing/pos-ops-harness.js +184 -0
  570. package/src/lib/testing/pos-ops-harness.js.map +1 -0
  571. package/src/lib/testing/pos-ops-memory-firestore.d.ts +55 -0
  572. package/src/lib/testing/pos-ops-memory-firestore.js +376 -0
  573. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -0
  574. package/src/lib/transfer/products.server.d.ts +5 -0
  575. package/src/lib/transfer/products.server.js +2 -2
  576. package/src/lib/transfer/products.server.js.map +1 -1
  577. package/src/lib/transfer/records-transfer.d.ts +11 -1
  578. package/src/lib/transfer/records-transfer.js +127 -5
  579. package/src/lib/transfer/records-transfer.js.map +1 -1
  580. package/src/lib/transfer/records.server.d.ts +9 -2
  581. package/src/lib/transfer/records.server.js +58 -7
  582. package/src/lib/transfer/records.server.js.map +1 -1
  583. package/src/lib/transfer/register-transfer-resources.js +40 -1
  584. package/src/lib/transfer/register-transfer-resources.js.map +1 -1
  585. package/src/lib/transfer/register-transfer-ui.js +4 -1
  586. package/src/lib/transfer/register-transfer-ui.js.map +1 -1
  587. package/src/lib/transfer/shipping-presets.d.ts +23 -0
  588. package/src/lib/transfer/shipping-presets.js +156 -0
  589. package/src/lib/transfer/shipping-presets.js.map +1 -0
  590. package/src/lib/transfer/tracking-transfer.d.ts +101 -0
  591. package/src/lib/transfer/tracking-transfer.js +546 -0
  592. package/src/lib/transfer/tracking-transfer.js.map +1 -0
  593. package/src/lib/transfer/tracking.server.d.ts +37 -0
  594. package/src/lib/transfer/tracking.server.js +393 -0
  595. package/src/lib/transfer/tracking.server.js.map +1 -0
  596. package/src/lib/transfer/transfer-keys.d.ts +2 -1
  597. package/src/lib/transfer/transfer-keys.js +6 -2
  598. package/src/lib/transfer/transfer-keys.js.map +1 -1
  599. package/src/lib/utils/code128.d.ts +37 -0
  600. package/src/lib/utils/code128.js +199 -0
  601. package/src/lib/utils/code128.js.map +1 -0
  602. package/src/lib/utils/order-invoice.d.ts +55 -0
  603. package/src/lib/utils/order-invoice.js +127 -0
  604. package/src/lib/utils/order-invoice.js.map +1 -0
  605. package/src/lib/utils/use-checkout-return-notice.d.ts +34 -0
  606. package/src/lib/utils/use-checkout-return-notice.js +78 -0
  607. package/src/lib/utils/use-checkout-return-notice.js.map +1 -0
  608. package/src/lib/server/feed.js +0 -69
  609. package/src/lib/server/feed.js.map +0 -1
@@ -19,22 +19,30 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
19
19
  import * as Aglyn from "@aglyn/aglyn";
20
20
  import * as CommerceModel from "../../model/index.js";
21
21
  import { PRODUCT_LIST_BASE, PRODUCT_LIST_QUERY } from "../../constants/product-list-query.js";
22
- import { escapeHtml } from "../../utils/escape-html.js";
23
22
  import { NextPageTitle } from "@aglyn/shared-ui-next/contexts/next-page-title-provider";
24
23
  import { useSnackbar } from "@aglyn/shared-ui-snackstack";
25
- import { ListQueryNotices } from "@aglyn/shared-ui-jsx/components/list-query-notices.component";
26
24
  import { planListQuery } from "@aglyn/shared-ui-jsx/const/list-query-plan";
25
+ import { useViewportFill } from "@aglyn/shared-ui-jsx/hooks/use-viewport-fill";
27
26
  import { nameSearchNormalizers } from "@aglyn/aglyn/app-utils/name-search";
28
- import { Alert, Box, Button, Card, CardActionArea, Chip, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Stack, TextField, Typography } from "@mui/material";
29
- import { QRCodeSVG } from "qrcode.react";
27
+ import { Badge, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Drawer, MenuItem, Stack, TextField, Typography, useMediaQuery, useTheme } from "@mui/material";
30
28
  import { collection, getDocs, limit, query, where } from "firebase/firestore";
31
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
29
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
32
30
  import { useFirestore, useUser } from "@aglyn/tenant-feature-instance";
33
31
  import { useFirestoreCollection } from "@aglyn/tenant-feature-instance";
34
32
  import { listQueryConstraints } from "@aglyn/tenant-feature-instance/hooks/use-list-query";
35
33
  import { useOrgPlan } from "@aglyn/tenant-feature-instance";
36
- import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
37
- const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
34
+ import { newAttemptKey, openPosSale, posRegisterContext, PosRequestError, usd } from "./pos/pos-api.js";
35
+ import { PosCartPanel } from "./pos/pos-cart-panel.component.js";
36
+ import { ScanAdornment } from "../../barcode/scan-button.component.js";
37
+ import { useScannerWedge } from "../../barcode/scanner-wedge.js";
38
+ import { PosCustomerLookup, PosLastReceipt, PosOperationsBar, usePosCashier, usePosOpsSettings } from "./pos-ops/register-ops.js";
39
+ import { POS_QUICK_KEYS, POS_TOUCH_PX, PosProductGrid } from "./pos/pos-product-grid.component.js";
40
+ import { PosItemDialog, posItemNeedsChoice } from "./pos/pos-item-dialog.component.js";
41
+ import { PosReceiptPanel } from "./pos/pos-receipt-panel.component.js";
42
+ import { PosTenderPanel } from "./pos/pos-tender-panel.component.js";
43
+ import { posDisplayTipCents, usePosDisplay } from "./pos/use-pos-display.js";
44
+ import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
45
+ import { POS_ORDERS_ZONE } from "./pos-zones.js";
38
46
  /** The till sells active products only; every read of the catalog asks it. */ const SELLABLE = {
39
47
  field: 'status',
40
48
  op: 'equals',
@@ -53,7 +61,7 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
53
61
  */ export function posProductPlan(options) {
54
62
  var _options_search;
55
63
  const typed = (_options_search = options.search) == null ? void 0 : _options_search.trim();
56
- return planListQuery(PRODUCT_LIST_QUERY, {
64
+ const plan = planListQuery(POS_GRID_QUERY, {
57
65
  base: PRODUCT_LIST_BASE,
58
66
  clauses: [
59
67
  SELLABLE,
@@ -63,19 +71,68 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
63
71
  op: 'contains',
64
72
  value: options.code.value
65
73
  }
74
+ ] : [],
75
+ ...options.categoryId ? [
76
+ {
77
+ field: 'categoryIds',
78
+ op: 'contains',
79
+ value: options.categoryId
80
+ }
66
81
  ] : []
67
82
  ],
68
- search: typed ? [
83
+ // A chip and a typed word are both array clauses, and Firestore takes
84
+ // one: with a chip on, the word narrows by name prefix instead.
85
+ search: typed && !options.categoryId ? [
69
86
  typed
70
87
  ] : []
71
88
  }, nameSearchNormalizers);
89
+ // The Quick keys chip (AGL-3607) is a boolean equality the list planner
90
+ // does not model, added beside the scope and status it composes with —
91
+ // `deletedAt ==, status ==, posQuickKey ==, nameLower ASC` is declared in
92
+ // the index file. A typed word searches the whole catalog instead: a
93
+ // cashier who types is looking past the quick keys.
94
+ if (options.quickKeys && !typed && !options.code) {
95
+ return _extends({}, plan, {
96
+ filters: [
97
+ ...plan.filters,
98
+ {
99
+ path: 'posQuickKey',
100
+ op: '==',
101
+ value: true
102
+ }
103
+ ]
104
+ });
105
+ }
106
+ return plan;
72
107
  }
73
108
  /**
74
- * POS register (AGL-312): touch-first full-screen sale surface —
75
- * product grid with search/barcode (keyboard-wedge scanners type into
76
- * the search box and press Enter), a register cart with a whole-sale
77
- * discount, and cash / QR-card / reservation-folio settlement through
78
- * the server-priced pos-order API. Receipts print via the browser.
109
+ * The grid's query: the products hub's, plus the category a chip picks
110
+ * (AGL-3607). `categoryIds CONTAINS, nameLower ASC` is a composite the
111
+ * storefront catalog already declares.
112
+ */ export const POS_GRID_QUERY = _extends({}, PRODUCT_LIST_QUERY, {
113
+ fields: [
114
+ ...PRODUCT_LIST_QUERY.fields,
115
+ {
116
+ column: 'categoryIds',
117
+ kind: 'exact',
118
+ path: 'categoryIds',
119
+ tokensPath: 'categoryIds',
120
+ operators: [
121
+ 'contains'
122
+ ]
123
+ }
124
+ ]
125
+ });
126
+ /**
127
+ * POS register (AGL-312, AGL-3607): a tablet-first sale surface — the
128
+ * product grid with search, scan and category chips, the basket, and a
129
+ * tender panel that takes one or more payments against an open sale (cash,
130
+ * card reader, a native Tap to Pay bridge, a typed card, the QR link, gift
131
+ * cards and room charges) until the balance is zero. A paired customer
132
+ * display mirrors the basket and takes the tip and the receipt (AGL-3608).
133
+ *
134
+ * On a wide screen (900px and up) the grid and the register sit side by
135
+ * side; below that the register is a bottom sheet behind a sticky total bar.
79
136
  */ /*
80
137
  * `managePos` is NOT read here. The nav item in `plugin.ts` declares it and
81
138
  * the shell refuses the route before this component is constructed, so a
@@ -85,31 +142,90 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
85
142
  * Re-adding a check off the `permissions` prop would be a second answer to a
86
143
  * settled question, and a laxer one: a prop absent because the map has not
87
144
  * landed reads as permitted here, while the shell holds the route on that
88
- * same condition rather than guessing. `server/pos-order.ts` remains the
89
- * enforcement point for the sale itself.
90
- */ export function PosConsolePage({ hostId }) {
91
- var _ref;
92
- var _usableRegisters_;
145
+ * same condition rather than guessing. The server routes remain the
146
+ * enforcement point for every sale and every payment.
147
+ */ /** Where a register device remembers the category chip it was left on. */ const POS_CATEGORY_KEY = 'aglyn.pos.category';
148
+ /** The basket line an item-sheet choice makes: label and estimate from the product. */ export function registerLineFor(product, choice) {
149
+ var _variant_options, _variant_options1;
150
+ const { variant, modifiers, quantity } = choice;
151
+ const resolved = CommerceModel.resolveLineModifiers(product, modifiers);
152
+ const picked = resolved.ok ? resolved.modifiers : [];
153
+ const label = CommerceModel.lineLabelWithModifiers(Object.keys((_variant_options = variant.options) != null ? _variant_options : {}).length ? Object.values((_variant_options1 = variant.options) != null ? _variant_options1 : {}).join(' / ') : undefined, picked);
154
+ return _extends({
155
+ productId: product.$id
156
+ }, variant.id !== 'default' ? {
157
+ variantId: variant.id
158
+ } : {}, {
159
+ name: product.name
160
+ }, label ? {
161
+ variantLabel: label
162
+ } : {}, {
163
+ unitAmountCents: Math.round(Number(variant.priceUsd) * 100) + (resolved.ok ? resolved.extraCents : 0),
164
+ quantity
165
+ }, modifiers.length ? {
166
+ modifiers
167
+ } : {});
168
+ }
169
+ /** Same product, variant and choices: the lines that merge into one. */ function lineKey(line) {
170
+ var _line_variantId;
171
+ return `${line.productId}:${(_line_variantId = line.variantId) != null ? _line_variantId : ''}:${CommerceModel.modifierSelectionKey(line.modifiers)}`;
172
+ }
173
+ /**
174
+ * The register's zone (AGL-3644), drawn again only when what it is handed
175
+ * changes: the till redraws on every tap, and the shell's renderer is not
176
+ * memoized (the order dialog's reasoning).
177
+ */ const PosOrdersZone = /*#__PURE__*/ memo(function PosOrdersZone(props) {
178
+ const { renderer: Renderer, hostId, registerId } = props;
179
+ return /*#__PURE__*/ _jsx(Renderer, {
180
+ slot: POS_ORDERS_ZONE.id,
181
+ hostId: hostId,
182
+ orgId: undefined,
183
+ registerId: registerId
184
+ });
185
+ });
186
+ export function PosConsolePage({ hostId }) {
187
+ var _ref, _ref1, _ref2, _ref3, _ref4;
188
+ var _usableRegisters_find, _usableRegisters_;
189
+ const WidgetSlot = useConsoleWidgetSlot();
93
190
  const firestore = useFirestore();
94
191
  const { data: user } = useUser();
95
192
  const { enqueueSnackbar } = useSnackbar();
193
+ const theme = useTheme();
194
+ const wide = useMediaQuery(theme.breakpoints.up('md'));
96
195
  const [search, setSearch] = useState('');
97
- const gridPlan = useMemo(()=>posProductPlan({
98
- search
196
+ // The chip a register opens on is remembered per device: a counter that
197
+ // rings from its quick keys reopens on them.
198
+ const [categoryId, setCategoryIdState] = useState(()=>{
199
+ try {
200
+ var _window_localStorage_getItem;
201
+ return (_window_localStorage_getItem = window.localStorage.getItem(POS_CATEGORY_KEY)) != null ? _window_localStorage_getItem : '';
202
+ } catch (unused) {
203
+ return '';
204
+ }
205
+ });
206
+ const setCategoryId = useCallback((id)=>{
207
+ setCategoryIdState(id);
208
+ try {
209
+ window.localStorage.setItem(POS_CATEGORY_KEY, id);
210
+ } catch (unused) {
211
+ // Storage blocked: the chip still works for this visit.
212
+ }
213
+ }, []);
214
+ const gridPlan = useMemo(()=>categoryId === POS_QUICK_KEYS ? posProductPlan({
215
+ search,
216
+ quickKeys: true
217
+ }) : posProductPlan({
218
+ search,
219
+ categoryId
99
220
  }), [
100
- search
221
+ search,
222
+ categoryId
101
223
  ]);
102
224
  const { data: productDocs } = useFirestoreCollection(/*
103
225
  * The till's grid, narrowed by the QUERY rather than by the rows it
104
- * happened to fetch (AGL-2501, AGL-2292, AGL-3321).
105
- *
106
- * `limit(500)` with no `orderBy` was document-id order over
107
- * `createResourceUid()` — an arbitrary five hundred, filtered afterwards
108
- * for status, deletion and the typed search. All three are the query's
109
- * now (`posProductPlan`), so the window is the first five hundred
110
- * SELLABLE products by name and a typed name reaches the whole catalog.
111
- * The scan does not come through here at all — see `handleSearchEnter`,
112
- * which is a lookup rather than a filter.
226
+ * happened to fetch (AGL-2501, AGL-2292, AGL-3321): the first five
227
+ * hundred SELLABLE products by name, and a typed name reaches the whole
228
+ * catalog. The scan does not come through here — see `handleSearchEnter`.
113
229
  */ ()=>query(collection(firestore, 'hosts', hostId, 'products'), ...listQueryConstraints(gridPlan), limit(POS_GRID_CEILING)), [
114
230
  firestore,
115
231
  hostId,
@@ -117,6 +233,12 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
117
233
  ], {
118
234
  idField: '$id'
119
235
  });
236
+ const { data: categoryDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'productCategories'), limit(30)), [
237
+ firestore,
238
+ hostId
239
+ ], {
240
+ idField: '$id'
241
+ });
120
242
  const { data: locationDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'locations'), limit(25)), [
121
243
  firestore,
122
244
  hostId
@@ -136,24 +258,13 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
136
258
  var _a_name, _b_name;
137
259
  return String((_a_name = a.name) != null ? _a_name : '').localeCompare(String((_b_name = b.name) != null ? _b_name : ''));
138
260
  });
139
- // Only registers within the plan cap can transact (pos-order.ts enforces
140
- // this at sale time by creation rank, AGL-482) — offer only those.
141
- //
142
- // Not until the org doc has arrived (AGL-1064): an absent org resolves to
143
- // the free tier's `posRegisters: 0`, which empties this list and tells a
144
- // paying seller their registers exceed a plan nobody has read yet.
145
- // Per SITE (AGL-1775): the plan's cap plus the register seats the org has
146
- // allocated to this host out of the purchased pool. `checkQuota` on the
147
- // org-level `posRegisters` no longer carries the pool and would hide
148
- // registers this site is paying for.
261
+ // Only registers within the plan cap can transact (AGL-482), and not until
262
+ // the org doc has arrived (AGL-1064). Per SITE (AGL-1775).
149
263
  const registerCap = Aglyn.checkHostRegisterQuota(org, hostId, registers.length).limit;
150
264
  const withinCap = CommerceModel.registersWithinCap(registers, registerCap);
151
265
  const usableRegisters = planReady ? registers.filter((r)=>withinCap.has(r.$id)) : [];
152
266
  /*
153
- * The stays a sale can be charged to, asked for BY STATUS (AGL-3321). This
154
- * read the first hundred reservations in document-id order and kept the
155
- * checked-in ones, so a guest in the house was missing from the folio
156
- * picker whenever a hundred other bookings sorted before theirs.
267
+ * The stays a sale can be charged to, asked for BY STATUS (AGL-3321).
157
268
  */ const { data: reservationDocs } = useFirestoreCollection(()=>query(collection(firestore, 'hosts', hostId, 'reservations'), where('status', '==', 'checked_in'), limit(100)), [
158
269
  firestore,
159
270
  hostId
@@ -163,13 +274,11 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
163
274
  const openStays = reservationDocs != null ? reservationDocs : [];
164
275
  const [lines, setLines] = useState([]);
165
276
  const [discountPct, setDiscountPct] = useState(0);
166
- const [customerEmail, setCustomerEmail] = useState('');
277
+ // The customer the lookup attached (AGL-3609); their email is the sale's.
278
+ const [customer, setCustomer] = useState(null);
279
+ const customerEmail = (_ref = customer == null ? void 0 : customer.email) != null ? _ref : '';
167
280
  const [locationId, setLocationId] = useState('');
168
- // Register (AGL-472): a sale must run through a named register so the
169
- // `posRegisters` cap is meaningful and takings are attributable.
170
281
  const [registerId, setRegisterId] = useState('');
171
- // Default to the first register once they load; if that register pins a
172
- // location, adopt it (the cashier can still override below).
173
282
  useEffect(()=>{
174
283
  if (registerId || usableRegisters.length === 0) return;
175
284
  const first = usableRegisters[0];
@@ -179,88 +288,73 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
179
288
  usableRegisters,
180
289
  registerId
181
290
  ]);
182
- // `paying` routes the settlement DIALOGS — nothing else. It is deliberately
183
- // not the tender `settle` acts on (AGL-1682): it used to be both, and the
184
- // Card button had to `setPaying('link')` and call `settle()` in one handler,
185
- // where `settle` still closed over the pre-click `null` and returned at its
186
- // own guard. Card has no dialog of its own — the QR dialog is gated on
187
- // `cardUrl` — so the card path sets nothing here at all.
188
- const [paying, setPaying] = useState(null);
189
- const [cashReceived, setCashReceived] = useState('');
190
- const [folioReservation, setFolioReservation] = useState('');
191
- const [cardUrl, setCardUrl] = useState('');
192
- const [busy, setBusy] = useState(false);
193
- // Re-entrancy guard for `settle`, deliberately a ref and not `busy`. `busy`
194
- // is for RENDERING (it disables the settle buttons); a second tap arriving
195
- // before React has re-rendered would read the pre-click `false` out of the
196
- // handler's closure exactly the way `paying` was read above. The ref is
197
- // written and read synchronously, so it holds whatever the scheduler does.
198
- // It is no longer the last line of defence — the server dedupes on the
199
- // attempt key below (AGL-1691) — but it is still the cheap one, and it stops
200
- // the redundant round trip rather than merely making it harmless.
201
- const inFlight = useRef(false);
291
+ const registerName = String((_ref1 = (_usableRegisters_find = usableRegisters.find((register)=>register.$id === registerId)) == null ? void 0 : _usableRegisters_find.name) != null ? _ref1 : '');
292
+ // Who is ringing (AGL-3609): a PIN-switched cashier, and the idle lock.
293
+ const opsSettings = usePosOpsSettings(hostId);
294
+ const cashier = usePosCashier({
295
+ hostId,
296
+ registerId,
297
+ autoLockMinutes: opsSettings.autoLockMinutes
298
+ });
299
+ // The last completed sale, whose receipt can still be printed (AGL-3609).
300
+ const [lastReceipt, setLastReceipt] = useState(null);
301
+ const [context, setContext] = useState(null);
302
+ // Keyed on the uid, not the user object: a session refresh hands back a
303
+ // new object for the same person, and re-reading the context on every one
304
+ // would re-render the register in a loop.
305
+ const userRef = useRef(user);
306
+ userRef.current = user;
307
+ const uid = (_ref2 = user == null ? void 0 : user.uid) != null ? _ref2 : '';
308
+ useEffect(()=>{
309
+ const signedIn = userRef.current;
310
+ if (!signedIn) return;
311
+ let active = true;
312
+ posRegisterContext(signedIn, hostId).then((answer)=>{
313
+ // Only a whole answer: a register that half-knows its tenders would
314
+ // offer one the server then refuses.
315
+ if (active && (answer == null ? void 0 : answer.settings) && (answer == null ? void 0 : answer.terminal)) setContext(answer);
316
+ }).catch(()=>undefined);
317
+ return ()=>{
318
+ active = false;
319
+ };
320
+ }, [
321
+ uid,
322
+ hostId
323
+ ]);
324
+ /** The open sale, once the basket has been priced and payment started. */ const [sale, setSale] = useState(null);
325
+ const [saleLines, setSaleLines] = useState([]);
326
+ const [opening, setOpening] = useState(false);
327
+ const [sheetOpen, setSheetOpen] = useState(false);
328
+ const [pairing, setPairing] = useState(null);
329
+ const display = usePosDisplay(user, hostId, registerId);
202
330
  /**
203
- * Idempotency key for ONE settlement attempt (AGL-1691).
204
- *
205
- * The guards above are all client-side and none of them survives a reload, a
206
- * lost response, or a retry. `/api/commerce/pos-order` now dedupes on this
207
- * key, but only if the key is right, and the key is the whole design:
208
- *
209
- * - Minted lazily on the first settle of a basket, NOT per `settle()` call.
210
- * Per-call would defeat the point — two taps would mint two keys and the
211
- * server would see two distinct sales.
212
- * - Retired whenever the register's contents change (the effect below),
213
- * which covers the sale completing and clearing the lines. So a cashier
214
- * ringing the same coffee twice gets a NEW key and a real second order —
215
- * de-duplicating that would be a worse bug than the one being fixed.
331
+ * One key per basket (AGL-1691): minted on the first Charge and retired
332
+ * whenever the basket changes, so a retried Charge finds the same sale and
333
+ * ringing the same coffee twice is two sales.
216
334
  */ const attemptKey = useRef('');
335
+ const fill = useViewportFill({
336
+ min: 480
337
+ });
217
338
  useEffect(()=>{
218
- // A different basket is a different attempt. Also fires when `settle`
219
- // clears the lines, which is what retires a spent key.
220
339
  attemptKey.current = '';
221
340
  }, [
222
341
  lines,
223
342
  discountPct
224
343
  ]);
225
- const [lastReceipt, setLastReceipt] = useState(null);
226
- const products = useMemo(()=>// Status, deletion and the search are all the query's (`posProductPlan`).
227
- [
344
+ const products = useMemo(()=>[
228
345
  ...productDocs != null ? productDocs : []
229
346
  ].map((product)=>_extends({}, CommerceModel.liftLegacyProduct(product), {
230
347
  $id: product.$id
231
348
  })), [
232
349
  productDocs
233
350
  ]);
234
- /*
235
- * The grid is what the query returned. Re-filtering it by the same text
236
- * would narrow it AGAIN and more strictly: the server matches a word prefix
237
- * ("cof" finds "Coffee"), the old compare wanted the whole typed string as a
238
- * substring, so "flat white" was sent as "flat" and then hidden again by a
239
- * row that never contained "flat white". Rows found, then dropped.
240
- */ const visible = products;
241
351
  const productsById = useMemo(()=>new Map(products.map((product)=>[
242
352
  product.$id,
243
353
  product
244
354
  ])), [
245
355
  products
246
356
  ]);
247
- /**
248
- * WHAT THE COUNT SAYS, at the line the cashier is looking at (AGL-2357).
249
- *
250
- * The register ignored `oversellPolicy` entirely — `pos-order.ts` had no
251
- * `canPurchase` call — so a merchant who chose "deny" in the product editor
252
- * silently got "backorder" at the counter. That silence is the defect.
253
- *
254
- * WARNS, NEVER BLOCKS (the decision on AGL-2357). Nothing here touches
255
- * `disabled` on the settle buttons, and nothing gates `settle`: a till is the
256
- * wrong place for a stale number to stop a real sale, because the cashier is
257
- * holding the goods. Honouring the policy behind a manager override is the
258
- * post-launch shape (AGL-2372).
259
- *
260
- * Indexed alongside `lines` rather than keyed, because the line list is
261
- * rendered by index and two lines of the same product/variant cannot exist —
262
- * `addProduct` merges them into one quantity.
263
- */ const shortfalls = useMemo(()=>lines.map((line)=>{
357
+ /** AGL-2357: warns, never blocks. */ const shortfalls = useMemo(()=>lines.map((line)=>{
264
358
  var _line_variantId;
265
359
  var _product_variants_, _product_variants;
266
360
  const product = productsById.get(line.productId);
@@ -272,60 +366,76 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
272
366
  ]);
273
367
  const itemsCents = lines.reduce((sum, line)=>sum + line.unitAmountCents * line.quantity, 0);
274
368
  const discountCents = Math.round(itemsCents * discountPct / 100);
275
- const dueCents = itemsCents - discountCents;
276
- const addProduct = useCallback((product, variant)=>{
277
- const pick = variant != null ? variant : product.variants[0];
369
+ const estimateCents = itemsCents - discountCents;
370
+ const units = lines.reduce((sum, line)=>sum + line.quantity, 0);
371
+ const notify = useCallback((message, variant)=>{
372
+ enqueueSnackbar(message, {
373
+ variant,
374
+ persist: false,
375
+ allowDuplicate: true
376
+ });
377
+ }, [
378
+ enqueueSnackbar
379
+ ]);
380
+ /**
381
+ * Adds a line, or more of an identical one: the same product, variant and
382
+ * modifiers merge, so two oat lattes are one line of two and an oat latte
383
+ * beside a whole-milk one stays two lines.
384
+ */ const addProduct = useCallback((product, variant, modifiers = [], quantity = 1)=>{
385
+ const next = registerLineFor(product, {
386
+ variant: variant != null ? variant : product.variants[0],
387
+ modifiers,
388
+ quantity
389
+ });
278
390
  setLines((prev)=>{
279
- var _pick_options, _pick_options1;
280
- const key = `${product.$id}:${pick.id}`;
281
- const existing = prev.find((line)=>{
282
- var _line_variantId;
283
- return `${line.productId}:${(_line_variantId = line.variantId) != null ? _line_variantId : pick.id}` === key;
284
- });
391
+ const existing = prev.find((line)=>lineKey(line) === lineKey(next));
285
392
  if (existing) {
286
393
  return prev.map((line)=>line === existing ? _extends({}, line, {
287
- quantity: line.quantity + 1
394
+ quantity: Math.min(99, line.quantity + next.quantity)
288
395
  }) : line);
289
396
  }
290
397
  return [
291
398
  ...prev,
292
- _extends({
293
- productId: product.$id
294
- }, pick.id !== 'default' ? {
295
- variantId: pick.id
296
- } : {}, {
297
- name: product.name
298
- }, Object.keys((_pick_options = pick.options) != null ? _pick_options : {}).length ? {
299
- variantLabel: Object.values((_pick_options1 = pick.options) != null ? _pick_options1 : {}).join(' / ')
300
- } : {}, {
301
- unitAmountCents: Math.round(Number(pick.priceUsd) * 100),
302
- quantity: 1
303
- })
399
+ next
304
400
  ];
305
401
  });
306
402
  }, []);
403
+ /** The item sheet: a product to add, or a basket line to change. */ const [itemSheet, setItemSheet] = useState(null);
404
+ // Every product rung up this sale, so a line can be reopened after the
405
+ // grid has moved on to another category or search.
406
+ const productCache = useRef(new Map());
407
+ const tapProduct = useCallback((product, variant)=>{
408
+ productCache.current.set(product.$id, product);
409
+ if (posItemNeedsChoice(product) && !(variant && CommerceModel.productModifierGroups(product).length === 0)) {
410
+ setItemSheet(_extends({
411
+ product
412
+ }, variant ? {
413
+ initial: {
414
+ variantId: variant.id,
415
+ quantity: 1
416
+ }
417
+ } : {}));
418
+ return;
419
+ }
420
+ addProduct(product, variant);
421
+ }, [
422
+ addProduct
423
+ ]);
424
+ const basketCounts = useMemo(()=>{
425
+ var _counts_get;
426
+ const counts = new Map();
427
+ for (const line of lines)counts.set(line.productId, ((_counts_get = counts.get(line.productId)) != null ? _counts_get : 0) + line.quantity);
428
+ return counts;
429
+ }, [
430
+ lines
431
+ ]);
307
432
  /**
308
- * The barcode wedge: a scanner types the code and presses Enter.
309
- *
310
- * A LOOKUP against the whole catalog, not a scan of the rows on screen
311
- * (AGL-2501). It used to walk `products` — the grid's `limit(500)` window —
312
- * so a shop whose catalog was larger than that had items whose barcode
313
- * simply did nothing when scanned. At a till, holding the goods, with a
314
- * customer waiting.
315
- *
316
- * `barcodes` and `skus` are top-level arrays the write path flattens out of
317
- * `variants`, because Firestore cannot query a field inside an array of
318
- * objects. Barcode is tried first: it is what the scanner produced, and a
319
- * SKU that happens to equal another product's barcode should not win over
320
- * the code actually scanned.
321
- *
322
- * ⚠️ A MISS NOW SAYS SO. The old loop returned silently, so an unknown code
323
- * and a code outside the window were indistinguishable from a scanner that
324
- * had not fired — the cashier's only signal was that nothing happened.
325
- */ const handleSearchEnter = useCallback(async ()=>{
433
+ * The barcode wedge: a LOOKUP against the whole catalog (AGL-2501),
434
+ * barcode first, and a miss says so.
435
+ */ const lookupCode = useCallback(async (scanned)=>{
326
436
  var _product_variants_find;
327
- const needle = search.trim().toLowerCase();
328
- if (!needle) return;
437
+ const needle = scanned.trim().toLowerCase();
438
+ if (!needle || sale) return;
329
439
  const lookup = async (field)=>{
330
440
  const found = await getDocs(query(collection(firestore, 'hosts', hostId, 'products'), ...listQueryConstraints(posProductPlan({
331
441
  code: {
@@ -341,17 +451,9 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
341
451
  hit = (_ref = await lookup('barcodes')) != null ? _ref : await lookup('skus');
342
452
  } catch (error) {
343
453
  console.error(error);
344
- return void enqueueSnackbar('Could not reach the catalog — try again', {
345
- variant: 'warning',
346
- persist: false
347
- });
348
- }
349
- if (!hit) {
350
- return void enqueueSnackbar(`No product matches “${search.trim()}”`, {
351
- variant: 'warning',
352
- persist: false
353
- });
454
+ return void notify('Could not reach the catalog — try again', 'warning');
354
455
  }
456
+ if (!hit) return void notify(`No product matches “${scanned.trim()}”`, 'warning');
355
457
  const product = _extends({}, CommerceModel.liftLegacyProduct(hit.data()), {
356
458
  $id: hit.id
357
459
  });
@@ -359,149 +461,397 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
359
461
  var _item_barcode, _item_sku;
360
462
  return ((_item_barcode = item.barcode) == null ? void 0 : _item_barcode.trim().toLowerCase()) === needle || ((_item_sku = item.sku) == null ? void 0 : _item_sku.trim().toLowerCase()) === needle;
361
463
  })) != null ? _product_variants_find : product.variants[0];
362
- addProduct(product, variant);
464
+ // A scanned variant is the variant; a product with modifiers still asks
465
+ // for them, with that variant already picked.
466
+ tapProduct(product, variant);
363
467
  setSearch('');
364
468
  }, [
365
- search,
469
+ sale,
366
470
  firestore,
367
471
  hostId,
368
- addProduct,
369
- enqueueSnackbar
472
+ tapProduct,
473
+ notify
370
474
  ]);
371
- /**
372
- * Take payment. The tender is an ARGUMENT, never read back out of state
373
- * (AGL-1682) — every caller already knows which button was pressed, and the
374
- * one caller that had to announce it through `setPaying` first could not
375
- * then observe its own write.
376
- */ const settle = useCallback(async (tender)=>{
377
- if (inFlight.current || lines.length === 0) return;
378
- if (!registerId) {
379
- return void enqueueSnackbar('Select a register before taking payment', {
380
- variant: 'warning',
381
- persist: false
382
- });
383
- }
384
- inFlight.current = true;
385
- setBusy(true);
386
- // Reuse the key across retries of this basket; mint one if this is the
387
- // first attempt (AGL-1691). `randomUUID` needs a secure context, which the
388
- // console always is, but fall back rather than throw on a settle.
389
- if (!attemptKey.current) {
390
- var _ref;
391
- var _globalThis_crypto_randomUUID, _globalThis_crypto;
392
- attemptKey.current = (_ref = (_globalThis_crypto = globalThis.crypto) == null ? void 0 : (_globalThis_crypto_randomUUID = _globalThis_crypto.randomUUID) == null ? void 0 : _globalThis_crypto_randomUUID.call(_globalThis_crypto)) != null ? _ref : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
393
- }
475
+ const handleSearchEnter = useCallback(()=>lookupCode(search), [
476
+ lookupCode,
477
+ search
478
+ ]);
479
+ // A scanner fired while focus is on a product or a button (AGL-3619), and
480
+ // the camera; neither while a sale is taking payment or an item is open.
481
+ useScannerWedge((code)=>void lookupCode(code), !sale && !itemSheet);
482
+ const scanAdornment = useMemo(()=>/*#__PURE__*/ _jsx(ScanAdornment, {
483
+ label: "Scan a barcode with the camera",
484
+ onScan: (code)=>void lookupCode(code)
485
+ }), [
486
+ lookupCode
487
+ ]);
488
+ /** Prices the basket on the server and opens the sale for payment. */ // A ref, not `opening`: two taps inside one React batch both read the
489
+ // pre-click state, and only a ref is written before the second reads it
490
+ // (the AGL-1682 lesson).
491
+ const chargeInFlight = useRef(false);
492
+ const charge = useCallback(async ()=>{
493
+ if (chargeInFlight.current || lines.length === 0 || !user) return;
494
+ if (!registerId) return void notify('Select a register before taking payment', 'warning');
495
+ if (!attemptKey.current) attemptKey.current = newAttemptKey();
496
+ chargeInFlight.current = true;
497
+ setOpening(true);
394
498
  try {
395
- var _ref1, _payload_changeCents;
396
- var _payload_totals;
397
- const response = await authorizedFetch(user, '/api/commerce/pos-order', {
398
- method: 'POST',
399
- headers: {
400
- 'Content-Type': 'application/json',
401
- 'Idempotency-Key': attemptKey.current
402
- },
403
- body: JSON.stringify({
404
- hostId,
405
- lines,
406
- discountPct,
407
- payment: tender,
408
- registerId,
409
- customerEmail: customerEmail || undefined,
410
- locationId: locationId || undefined,
411
- cashReceivedCents: Math.round(Number(cashReceived) * 100) || 0,
412
- reservationId: tender === 'folio' ? folioReservation : undefined
413
- })
414
- });
415
- const payload = await response.json();
416
- if (!response.ok) {
417
- var _ref2;
418
- return void enqueueSnackbar((_ref2 = payload == null ? void 0 : payload.error) != null ? _ref2 : 'Sale failed', {
419
- variant: 'error',
420
- allowDuplicate: true
421
- });
422
- }
423
- if (tender === 'link' && payload.url) {
424
- setCardUrl(payload.url);
425
- return;
426
- }
427
- setLastReceipt({
499
+ const opened = await openPosSale(user, attemptKey.current, _extends({
500
+ hostId,
501
+ registerId,
428
502
  lines,
429
- totalCents: (_ref1 = (_payload_totals = payload.totals) == null ? void 0 : _payload_totals.totalCents) != null ? _ref1 : dueCents,
430
- changeCents: (_payload_changeCents = payload.changeCents) != null ? _payload_changeCents : 0
431
- });
432
- setLines([]);
433
- setDiscountPct(0);
434
- setCustomerEmail('');
435
- setCashReceived('');
436
- setPaying(null);
437
- enqueueSnackbar(payload.changeCents > 0 ? `Paid — change ${usd(payload.changeCents)}` : 'Paid', {
438
- variant: 'success',
439
- persist: false
503
+ discountPct
504
+ }, customerEmail ? {
505
+ customerEmail
506
+ } : {}, customer ? {
507
+ customer
508
+ } : {}, cashier.assertion ? {
509
+ cashierAssertion: cashier.assertion
510
+ } : {}, locationId ? {
511
+ locationId
512
+ } : {}));
513
+ setSaleLines(lines);
514
+ setSale({
515
+ orderId: opened.orderId,
516
+ status: 'pending',
517
+ totalCents: opened.totals.totalCents,
518
+ paidCents: 0,
519
+ dueCents: opened.totals.totalCents,
520
+ tenderableCents: opened.totals.totalCents,
521
+ tipCents: 0,
522
+ payments: []
440
523
  });
524
+ setSheetOpen(true);
525
+ } catch (error) {
526
+ notify(error instanceof PosRequestError ? error.message : 'Sale failed', 'error');
441
527
  } finally{
442
- inFlight.current = false;
443
- setBusy(false);
528
+ chargeInFlight.current = false;
529
+ setOpening(false);
444
530
  }
445
531
  }, [
446
532
  lines,
447
- registerId,
448
533
  user,
534
+ registerId,
449
535
  hostId,
450
536
  discountPct,
451
537
  customerEmail,
538
+ customer,
539
+ cashier.assertion,
452
540
  locationId,
453
- cashReceived,
454
- folioReservation,
455
- dueCents,
456
- enqueueSnackbar
541
+ notify
457
542
  ]);
458
- /**
459
- * Close the card QR dialog. Clears the cart, because by the time this dialog
460
- * exists the order is already on the server awaiting the webhook — leaving
461
- * the lines behind meant a backdrop click or Escape dropped the cashier back
462
- * on a full register that would mint a SECOND pending order and a SECOND
463
- * Checkout session for the same basket on the next tap (AGL-1682). `Done`
464
- * always did this; `onClose` did not, and only `onClose` can fire by
465
- * accident.
466
- */ const closeCardDialog = useCallback(()=>{
467
- setCardUrl('');
543
+ const resetSale = useCallback(()=>{
544
+ if ((sale == null ? void 0 : sale.status) === 'paid') setLastReceipt({
545
+ orderId: sale.orderId
546
+ });
547
+ setSale(null);
548
+ setSaleLines([]);
468
549
  setLines([]);
469
- setPaying(null);
470
- }, []);
471
- const printReceipt = useCallback(()=>{
472
- if (!lastReceipt) return;
473
- const win = window.open('', '_blank', 'width=320,height=600');
474
- if (!win) return;
475
- // ESCAPED (AGL-2283), the same construction as the packing slip: a
476
- // `document.write` into an `about:blank` popup that inherits the console's
477
- // origin. These names are merchant-authored rather than shopper-typed, so
478
- // the reach is a merchant's own session — still not a reason to build
479
- // markup out of unescaped product text.
480
- win.document.write(`<pre style="font-family:monospace;font-size:12px">` + lastReceipt.lines.map((line)=>`${escapeHtml(line.quantity)}x ${escapeHtml(line.name)}${line.variantLabel ? ` (${escapeHtml(line.variantLabel)})` : ''}` + ` ${usd(line.unitAmountCents * line.quantity)}`).join('\n') + `\n\nTOTAL ${usd(lastReceipt.totalCents)}` + (lastReceipt.changeCents ? `\nCHANGE ${usd(lastReceipt.changeCents)}` : '') + `\n${new Date().toLocaleString()}` + `</pre>`);
481
- win.document.close();
482
- // Print from HERE, not from a `<script>` written into the receipt
483
- // (AGL-523). `window.open('')` yields an about:blank document that
484
- // INHERITS the opener's CSP, so an injected inline script has no nonce and
485
- // `strict-dynamic` means `'self'` will not save it either. Under the
486
- // enforcing policy that script is blocked, the receipt window opens, and
487
- // the print dialog never appears — a silent break of the one action the
488
- // window exists for.
489
- //
490
- // This call is in the opener, whose script Next has already nonced.
491
- win.focus();
492
- win.print();
550
+ setDiscountPct(0);
551
+ setCustomer(null);
552
+ setSheetOpen(false);
553
+ }, [
554
+ sale
555
+ ]);
556
+ // The customer display mirrors the basket while nothing else is on it.
557
+ const mirrored = sale ? saleLines : lines;
558
+ // Whether the display was last left showing a basket. A paid sale leaves it
559
+ // on the thank-you the server wrote, which an empty new basket must not
560
+ // cut short with the idle screen; the next item added takes it over.
561
+ // True at first, so a register that opens empty clears whatever a previous
562
+ // session left on the screen.
563
+ const displayShowsBasket = useRef(true);
564
+ // The tip picked for the payment about to be taken; the ledger has it only
565
+ // once that payment is recorded. Gone with the sale.
566
+ const [pendingTipCents, setPendingTipCents] = useState(0);
567
+ useEffect(()=>{
568
+ if (!sale || sale.status === 'paid') setPendingTipCents(0);
569
+ }, [
570
+ sale
571
+ ]);
572
+ useEffect(()=>{
573
+ if ((sale == null ? void 0 : sale.status) === 'paid') displayShowsBasket.current = false;
493
574
  }, [
494
- lastReceipt
575
+ sale == null ? void 0 : sale.status
495
576
  ]);
577
+ useEffect(()=>{
578
+ if (!display.connected || display.asking) return;
579
+ if (sale == null ? void 0 : sale.payments.some((payment)=>payment.status === 'pending' && payment.method === 'card_present')) {
580
+ return;
581
+ }
582
+ if ((sale == null ? void 0 : sale.status) === 'paid') return;
583
+ if (!mirrored.length && !displayShowsBasket.current) return;
584
+ const timer = setTimeout(()=>{
585
+ displayShowsBasket.current = mirrored.length > 0;
586
+ void display.show(mirrored.length ? {
587
+ mode: 'cart',
588
+ cart: _extends({
589
+ lines: mirrored.map((line)=>_extends({
590
+ name: line.name
591
+ }, line.variantLabel ? {
592
+ variantLabel: line.variantLabel
593
+ } : {}, {
594
+ quantity: line.quantity,
595
+ amountCents: line.unitAmountCents * line.quantity
596
+ })),
597
+ itemsCents,
598
+ discountCents,
599
+ taxCents: sale ? Math.max(0, sale.totalCents - estimateCents) : 0,
600
+ totalCents: sale ? sale.totalCents : estimateCents
601
+ }, sale ? {
602
+ paidCents: sale.paidCents,
603
+ dueCents: sale.dueCents,
604
+ tipCents: posDisplayTipCents(sale, pendingTipCents)
605
+ } : {})
606
+ } : {
607
+ mode: 'idle'
608
+ });
609
+ }, 400);
610
+ return ()=>clearTimeout(timer);
611
+ }, [
612
+ display,
613
+ mirrored,
614
+ sale,
615
+ itemsCents,
616
+ discountCents,
617
+ estimateCents,
618
+ pendingTipCents
619
+ ]);
620
+ const registerPicker = !planReady ? /*#__PURE__*/ _jsx(Typography, {
621
+ variant: "body2",
622
+ color: "text.secondary",
623
+ children: 'Checking your plan…'
624
+ }) : usableRegisters.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
625
+ variant: "body2",
626
+ color: "warning.main",
627
+ children: registers.length > 0 ? 'Your registers exceed your plan — remove extras or upgrade in Billing to take payments.' : 'No POS register yet. Add one under Commerce → Settings → POS registers before taking payments.'
628
+ }) : usableRegisters.length > 1 ? /*#__PURE__*/ _jsx(TextField, {
629
+ label: "Register",
630
+ value: registerId,
631
+ onChange: (event)=>setRegisterId(event.target.value),
632
+ size: "small",
633
+ select: true,
634
+ disabled: Boolean(sale),
635
+ children: usableRegisters.map((register)=>/*#__PURE__*/ _jsx(MenuItem, {
636
+ value: register.$id,
637
+ children: register.name
638
+ }, register.$id))
639
+ }) : /*#__PURE__*/ _jsx(Typography, {
640
+ variant: "body2",
641
+ color: "text.secondary",
642
+ children: (_usableRegisters_ = usableRegisters[0]) == null ? void 0 : _usableRegisters_.name
643
+ });
644
+ /**
645
+ * On a narrow screen the register's bar owns the bottom edge, so it moves
646
+ * the console's floating launchers clear of itself through the shell's
647
+ * `--aglyn-dock-inset-bottom` seam; a launcher left in the corner sat on
648
+ * top of Charge.
649
+ */ const bottomBarRef = useRef(null);
650
+ useEffect(()=>{
651
+ const node = bottomBarRef.current;
652
+ if (wide || !node) return undefined;
653
+ const root = document.documentElement;
654
+ const property = '--aglyn-dock-inset-bottom';
655
+ const publish = ()=>{
656
+ root.style.setProperty(property, `${Math.round(node.getBoundingClientRect().height) + 20}px`);
657
+ };
658
+ publish();
659
+ const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(publish);
660
+ observer == null ? void 0 : observer.observe(node);
661
+ return ()=>{
662
+ observer == null ? void 0 : observer.disconnect();
663
+ root.style.removeProperty(property);
664
+ };
665
+ }, [
666
+ wide
667
+ ]);
668
+ const registerPanel = /*#__PURE__*/ _jsxs(Stack, {
669
+ spacing: 1.5,
670
+ sx: {
671
+ minHeight: 0,
672
+ flex: 1
673
+ },
674
+ children: [
675
+ /*#__PURE__*/ _jsxs(Stack, {
676
+ direction: "row",
677
+ spacing: 1,
678
+ sx: {
679
+ alignItems: 'center'
680
+ },
681
+ children: [
682
+ /*#__PURE__*/ _jsx(Typography, {
683
+ variant: "h6",
684
+ sx: {
685
+ flex: 1
686
+ },
687
+ children: 'Register'
688
+ }),
689
+ registerId ? /*#__PURE__*/ _jsx(Button, {
690
+ size: "small",
691
+ onClick: async ()=>{
692
+ try {
693
+ setPairing(await display.pairingCode());
694
+ } catch (error) {
695
+ notify(error instanceof PosRequestError ? error.message : 'Could not make a code', 'error');
696
+ }
697
+ },
698
+ children: display.connected ? 'Display connected' : 'Pair display'
699
+ }) : null
700
+ ]
701
+ }),
702
+ registerPicker,
703
+ ((_ref3 = locationDocs == null ? void 0 : locationDocs.length) != null ? _ref3 : 0) > 1 ? /*#__PURE__*/ _jsx(TextField, {
704
+ label: "Location",
705
+ value: locationId,
706
+ onChange: (event)=>setLocationId(event.target.value),
707
+ size: "small",
708
+ select: true,
709
+ disabled: Boolean(sale),
710
+ children: (locationDocs != null ? locationDocs : []).map((location)=>/*#__PURE__*/ _jsx(MenuItem, {
711
+ value: location.$id,
712
+ children: location.name
713
+ }, location.$id))
714
+ }) : null,
715
+ registerId ? /*#__PURE__*/ _jsx(PosOperationsBar, _extends({
716
+ hostId: hostId,
717
+ registerId: registerId
718
+ }, registerName ? {
719
+ registerName
720
+ } : {}, {
721
+ cashier: cashier,
722
+ onExchange: (returned)=>{
723
+ var _returned_name;
724
+ return setCustomer(returned.email || returned.name ? {
725
+ kind: 'none',
726
+ id: '',
727
+ name: (_returned_name = returned.name) != null ? _returned_name : '',
728
+ email: returned.email,
729
+ phone: null
730
+ } : null);
731
+ }
732
+ })) : null,
733
+ /*#__PURE__*/ _jsx(PosCartPanel, {
734
+ lines: sale ? saleLines : lines,
735
+ shortfalls: sale ? [] : shortfalls,
736
+ onQuantity: (index, quantity)=>setLines((prev)=>quantity <= 0 ? prev.filter((_line, at)=>at !== index) : prev.map((line, at)=>at === index ? _extends({}, line, {
737
+ quantity: Math.min(99, quantity)
738
+ }) : line)),
739
+ onRemove: (index)=>setLines((prev)=>prev.filter((_line, at)=>at !== index)),
740
+ onEdit: (index)=>{
741
+ var _productCache_current_get;
742
+ const line = lines[index];
743
+ const product = line ? (_productCache_current_get = productCache.current.get(line.productId)) != null ? _productCache_current_get : productsById.get(line.productId) : undefined;
744
+ if (!line || !product) return;
745
+ setItemSheet({
746
+ product,
747
+ editIndex: index,
748
+ initial: _extends({}, line.variantId ? {
749
+ variantId: line.variantId
750
+ } : {}, line.modifiers ? {
751
+ modifiers: line.modifiers
752
+ } : {}, {
753
+ quantity: line.quantity
754
+ })
755
+ });
756
+ },
757
+ discountPct: discountPct,
758
+ onDiscountPct: setDiscountPct,
759
+ customer: sale ? null : /*#__PURE__*/ _jsx(PosCustomerLookup, {
760
+ hostId: hostId,
761
+ value: customer,
762
+ onChange: setCustomer
763
+ }),
764
+ locked: Boolean(sale)
765
+ }),
766
+ sale && user ? sale.status === 'paid' ? /*#__PURE__*/ _jsx(PosReceiptPanel, _extends({
767
+ user: user,
768
+ hostId: hostId,
769
+ sale: sale,
770
+ context: context,
771
+ display: display,
772
+ onNewSale: resetSale,
773
+ registerId: registerId
774
+ }, registerName ? {
775
+ registerName
776
+ } : {}, cashier.cashier ? {
777
+ cashierName: cashier.cashier.name
778
+ } : {}, {
779
+ notify: notify
780
+ })) : /*#__PURE__*/ _jsx(PosTenderPanel, _extends({
781
+ user: user,
782
+ hostId: hostId,
783
+ registerId: registerId,
784
+ sale: sale,
785
+ context: context,
786
+ stays: openStays,
787
+ display: display,
788
+ onSale: setSale,
789
+ onVoided: ()=>{
790
+ setSale(null);
791
+ setSaleLines([]);
792
+ },
793
+ onTipChange: setPendingTipCents
794
+ }, cashier.assertion ? {
795
+ cashierAssertion: cashier.assertion
796
+ } : {}, {
797
+ notify: notify
798
+ })) : /*#__PURE__*/ _jsxs(_Fragment, {
799
+ children: [
800
+ /*#__PURE__*/ _jsxs(Box, {
801
+ sx: {
802
+ display: 'flex',
803
+ justifyContent: 'space-between'
804
+ },
805
+ children: [
806
+ /*#__PURE__*/ _jsx(Typography, {
807
+ variant: "h6",
808
+ children: 'Due'
809
+ }),
810
+ /*#__PURE__*/ _jsx(Typography, {
811
+ variant: "h6",
812
+ children: usd(estimateCents)
813
+ })
814
+ ]
815
+ }),
816
+ /*#__PURE__*/ _jsx(Typography, {
817
+ variant: "caption",
818
+ color: "text.secondary",
819
+ children: 'Tax is added when you charge.'
820
+ }),
821
+ /*#__PURE__*/ _jsx(Button, {
822
+ variant: "contained",
823
+ size: "large",
824
+ disabled: opening || lines.length === 0 || !registerId,
825
+ onClick: ()=>void charge(),
826
+ sx: {
827
+ minHeight: 56
828
+ },
829
+ children: opening ? 'Pricing…' : `Charge ${usd(estimateCents)}`
830
+ }),
831
+ lastReceipt ? /*#__PURE__*/ _jsx(PosLastReceipt, _extends({
832
+ hostId: hostId,
833
+ orderId: lastReceipt.orderId
834
+ }, registerName ? {
835
+ registerName
836
+ } : {}, cashier.cashier ? {
837
+ cashierName: cashier.cashier.name
838
+ } : {})) : null
839
+ ]
840
+ })
841
+ ]
842
+ });
496
843
  return /*#__PURE__*/ _jsxs(_Fragment, {
497
844
  children: [
498
845
  /*#__PURE__*/ _jsx(NextPageTitle, {
499
846
  screen: 'POS'
500
847
  }),
501
848
  /*#__PURE__*/ _jsxs(Box, {
849
+ ref: fill.ref,
502
850
  sx: {
503
851
  display: 'flex',
504
- height: '100vh',
852
+ // From under the console's header, nav and page title to the
853
+ // bottom of the window, not a whole window tall below them.
854
+ height: fill.height,
505
855
  overflow: 'hidden'
506
856
  },
507
857
  children: [
@@ -509,399 +859,155 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
509
859
  sx: {
510
860
  flex: 1,
511
861
  p: 2,
512
- overflowY: 'auto'
862
+ overflowY: 'auto',
863
+ pb: wide ? 2 : 12
513
864
  },
514
865
  children: [
515
- /*#__PURE__*/ _jsx(TextField, {
516
- placeholder: "Search or scan barcode…",
517
- value: search,
518
- onChange: (event)=>setSearch(event.target.value),
519
- onKeyDown: (event)=>{
520
- if (event.key === 'Enter') void handleSearchEnter();
521
- },
522
- size: "small",
523
- fullWidth: true,
524
- autoFocus: true,
525
- sx: {
526
- mb: 2
866
+ WidgetSlot ? /*#__PURE__*/ _jsx(PosOrdersZone, {
867
+ renderer: WidgetSlot,
868
+ hostId: hostId,
869
+ registerId: registerId || null
870
+ }) : null,
871
+ /*#__PURE__*/ _jsx(PosProductGrid, {
872
+ search: search,
873
+ onSearch: setSearch,
874
+ onSearchEnter: ()=>void handleSearchEnter(),
875
+ scanAdornment: scanAdornment,
876
+ categories: (categoryDocs != null ? categoryDocs : []).map((category)=>{
877
+ var _category_name;
878
+ return {
879
+ $id: category.$id,
880
+ name: String((_category_name = category.name) != null ? _category_name : 'Category')
881
+ };
882
+ }),
883
+ categoryId: categoryId,
884
+ onCategory: setCategoryId,
885
+ notices: gridPlan.notices,
886
+ hostId: hostId,
887
+ products: products,
888
+ basketCounts: basketCounts,
889
+ onTap: (product)=>{
890
+ if (sale) return void notify('Finish or void the open sale first', 'info');
891
+ tapProduct(product);
527
892
  }
528
- }),
529
- /*#__PURE__*/ _jsx(Box, {
530
- sx: {
531
- mb: gridPlan.notices.length ? 2 : 0
532
- },
533
- children: /*#__PURE__*/ _jsx(ListQueryNotices, {
534
- refused: [],
535
- notices: gridPlan.notices
536
- })
537
- }),
538
- /*#__PURE__*/ _jsx(Box, {
539
- sx: {
540
- display: 'grid',
541
- gap: 1.5,
542
- gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))'
543
- },
544
- children: visible.map((product)=>{
545
- var _ref;
546
- var _product_variants_;
547
- return /*#__PURE__*/ _jsxs(Card, {
548
- variant: "outlined",
549
- children: [
550
- /*#__PURE__*/ _jsxs(CardActionArea, {
551
- onClick: ()=>addProduct(product),
552
- sx: {
553
- p: 1.5,
554
- minHeight: 88
555
- },
556
- children: [
557
- /*#__PURE__*/ _jsx(Typography, {
558
- variant: "body2",
559
- sx: {
560
- fontWeight: 600
561
- },
562
- noWrap: true,
563
- children: product.name
564
- }),
565
- /*#__PURE__*/ _jsxs(Typography, {
566
- variant: "caption",
567
- color: "text.secondary",
568
- children: [
569
- `$${(_ref = (_product_variants_ = product.variants[0]) == null ? void 0 : _product_variants_.priceUsd) != null ? _ref : 0}`,
570
- product.variants.length > 1 ? ` · ${product.variants.length} variants` : ''
571
- ]
572
- })
573
- ]
574
- }),
575
- product.variants.length > 1 ? /*#__PURE__*/ _jsx(Box, {
576
- sx: {
577
- display: 'flex',
578
- flexWrap: 'wrap',
579
- gap: 0.5,
580
- p: 0.5
581
- },
582
- children: product.variants.slice(0, 6).map((variant)=>{
583
- var _variant_options;
584
- return /*#__PURE__*/ _jsx(Chip, {
585
- label: Object.values((_variant_options = variant.options) != null ? _variant_options : {}).join('/') || 'Default',
586
- size: "small",
587
- onClick: ()=>addProduct(product, variant)
588
- }, variant.id);
589
- })
590
- }) : null
591
- ]
592
- }, product.$id);
593
- })
594
893
  })
595
894
  ]
596
895
  }),
597
- /*#__PURE__*/ _jsxs(Box, {
896
+ wide ? /*#__PURE__*/ _jsx(Box, {
598
897
  sx: {
599
- width: 380,
898
+ width: {
899
+ md: 400,
900
+ lg: 440
901
+ },
600
902
  borderLeft: 1,
601
903
  borderColor: 'divider',
602
904
  display: 'flex',
603
905
  flexDirection: 'column',
604
906
  p: 2,
605
- gap: 1
907
+ overflowY: 'auto'
908
+ },
909
+ children: registerPanel
910
+ }) : null
911
+ ]
912
+ }),
913
+ !wide ? /*#__PURE__*/ _jsxs(_Fragment, {
914
+ children: [
915
+ /*#__PURE__*/ _jsxs(Box, {
916
+ ref: bottomBarRef,
917
+ sx: {
918
+ position: 'fixed',
919
+ left: 0,
920
+ right: 0,
921
+ bottom: 0,
922
+ p: 1.5,
923
+ bgcolor: 'background.paper',
924
+ borderTop: 1,
925
+ borderColor: 'divider',
926
+ display: 'flex',
927
+ gap: 1,
928
+ alignItems: 'center',
929
+ zIndex: theme.zIndex.appBar
606
930
  },
607
931
  children: [
932
+ /*#__PURE__*/ _jsx(Badge, {
933
+ badgeContent: units,
934
+ color: "primary",
935
+ children: /*#__PURE__*/ _jsx(Button, {
936
+ variant: "outlined",
937
+ onClick: ()=>setSheetOpen(true),
938
+ sx: {
939
+ minHeight: POS_TOUCH_PX
940
+ },
941
+ children: sale ? 'Payment' : 'Cart'
942
+ })
943
+ }),
608
944
  /*#__PURE__*/ _jsx(Typography, {
609
945
  variant: "h6",
610
- children: 'Register'
611
- }),
612
- !planReady ? /*#__PURE__*/ _jsx(Typography, {
613
- variant: "body2",
614
- color: "text.secondary",
615
- children: 'Checking your plan…'
616
- }) : usableRegisters.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
617
- variant: "body2",
618
- color: "warning.main",
619
- children: registers.length > 0 ? 'Your registers exceed your plan — remove extras or ' + 'upgrade in Billing to take payments.' : 'No POS register yet. Add one under Commerce → Settings → ' + 'POS registers before taking payments.'
620
- }) : usableRegisters.length > 1 ? /*#__PURE__*/ _jsx(TextField, {
621
- label: "Register",
622
- value: registerId,
623
- onChange: (event)=>setRegisterId(event.target.value),
624
- size: "small",
625
- select: true,
626
- children: usableRegisters.map((register)=>/*#__PURE__*/ _jsx(MenuItem, {
627
- value: register.$id,
628
- children: register.name
629
- }, register.$id))
630
- }) : /*#__PURE__*/ _jsx(Typography, {
631
- variant: "body2",
632
- color: "text.secondary",
633
- children: (_usableRegisters_ = usableRegisters[0]) == null ? void 0 : _usableRegisters_.name
634
- }),
635
- ((_ref = locationDocs == null ? void 0 : locationDocs.length) != null ? _ref : 0) > 1 ? /*#__PURE__*/ _jsx(TextField, {
636
- label: "Location",
637
- value: locationId,
638
- onChange: (event)=>setLocationId(event.target.value),
639
- size: "small",
640
- select: true,
641
- children: (locationDocs != null ? locationDocs : []).map((location)=>/*#__PURE__*/ _jsx(MenuItem, {
642
- value: location.$id,
643
- children: location.name
644
- }, location.$id))
645
- }) : null,
646
- /*#__PURE__*/ _jsx(Box, {
647
946
  sx: {
648
947
  flex: 1,
649
- overflowY: 'auto'
948
+ textAlign: 'right'
650
949
  },
651
- children: lines.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
652
- variant: "body2",
653
- color: "text.secondary",
654
- children: 'Tap products to add them.'
655
- }) : lines.map((line, index)=>{
656
- var _shortfalls_index;
657
- return /*#__PURE__*/ _jsxs(Box, {
658
- sx: {
659
- py: 0.5
660
- },
661
- children: [
662
- /*#__PURE__*/ _jsxs(Stack, {
663
- direction: "row",
664
- spacing: 1,
665
- sx: {
666
- alignItems: 'center'
667
- },
668
- children: [
669
- /*#__PURE__*/ _jsxs(Typography, {
670
- variant: "body2",
671
- sx: {
672
- flex: 1
673
- },
674
- noWrap: true,
675
- children: [
676
- `${line.quantity}× ${line.name}`,
677
- line.variantLabel ? ` (${line.variantLabel})` : ''
678
- ]
679
- }),
680
- /*#__PURE__*/ _jsx(Typography, {
681
- variant: "body2",
682
- children: usd(line.unitAmountCents * line.quantity)
683
- }),
684
- /*#__PURE__*/ _jsx(Button, {
685
- size: "small",
686
- color: "error",
687
- onClick: ()=>setLines((prev)=>prev.filter((_item, itemIndex)=>itemIndex !== index)),
688
- children: '✕'
689
- })
690
- ]
691
- }),
692
- shortfalls[index] ? // AGL-2357: said, not enforced. The cashier reads it and
693
- // rings the sale through — the settle buttons below are
694
- // untouched by this.
695
- /*#__PURE__*/ _jsx(Typography, {
696
- variant: "caption",
697
- color: "warning.main",
698
- children: `Only ${(_shortfalls_index = shortfalls[index]) == null ? void 0 : _shortfalls_index.available} in stock — selling ${line.quantity}`
699
- }) : null
700
- ]
701
- }, index);
702
- })
703
- }),
704
- /*#__PURE__*/ _jsxs(Stack, {
705
- direction: "row",
706
- spacing: 1,
707
- children: [
708
- /*#__PURE__*/ _jsx(TextField, {
709
- label: "Discount %",
710
- value: discountPct || '',
711
- onChange: (event)=>setDiscountPct(Math.min(100, Math.max(0, Number(event.target.value) || 0))),
712
- size: "small",
713
- sx: {
714
- width: 110
715
- },
716
- slotProps: {
717
- htmlInput: {
718
- inputMode: 'numeric'
719
- }
720
- }
721
- }),
722
- /*#__PURE__*/ _jsx(TextField, {
723
- label: "Customer email",
724
- value: customerEmail,
725
- onChange: (event)=>setCustomerEmail(event.target.value),
726
- size: "small",
727
- sx: {
728
- flex: 1
729
- }
730
- })
731
- ]
950
+ children: usd(sale ? sale.dueCents : estimateCents)
732
951
  }),
733
- /*#__PURE__*/ _jsxs(Box, {
952
+ !sale ? /*#__PURE__*/ _jsx(Button, {
953
+ variant: "contained",
954
+ disabled: opening || lines.length === 0 || !registerId,
955
+ onClick: ()=>void charge(),
734
956
  sx: {
735
- display: 'flex',
736
- justifyContent: 'space-between'
957
+ minHeight: POS_TOUCH_PX
737
958
  },
738
- children: [
739
- /*#__PURE__*/ _jsx(Typography, {
740
- variant: "h6",
741
- children: 'Due'
742
- }),
743
- /*#__PURE__*/ _jsx(Typography, {
744
- variant: "h6",
745
- children: usd(dueCents)
746
- })
747
- ]
748
- }),
749
- /*#__PURE__*/ _jsxs(Stack, {
750
- direction: "row",
751
- spacing: 1,
752
- children: [
753
- /*#__PURE__*/ _jsx(Button, {
754
- variant: "contained",
755
- color: "primary",
756
- disabled: lines.length === 0,
757
- onClick: ()=>setPaying('cash'),
758
- sx: {
759
- flex: 1
760
- },
761
- children: 'Cash'
762
- }),
763
- /*#__PURE__*/ _jsx(Button, {
764
- variant: "contained",
765
- disabled: busy || lines.length === 0,
766
- onClick: ()=>void settle('link'),
767
- sx: {
768
- flex: 1
769
- },
770
- children: 'Card (QR)'
771
- }),
772
- /*#__PURE__*/ _jsx(Button, {
773
- variant: "outlined",
774
- disabled: lines.length === 0 || openStays.length === 0,
775
- onClick: ()=>setPaying('folio'),
776
- sx: {
777
- flex: 1
778
- },
779
- children: 'Room'
780
- })
781
- ]
782
- }),
783
- lastReceipt ? /*#__PURE__*/ _jsx(Button, {
784
- size: "small",
785
- onClick: printReceipt,
786
- children: 'Print last receipt'
959
+ children: 'Charge'
787
960
  }) : null
788
961
  ]
789
- })
790
- ]
791
- }),
792
- /*#__PURE__*/ _jsxs(Dialog, {
793
- open: paying === 'cash',
794
- onClose: ()=>setPaying(null),
795
- maxWidth: "xs",
796
- fullWidth: true,
797
- children: [
798
- /*#__PURE__*/ _jsx(DialogTitle, {
799
- children: `Cash — due ${usd(dueCents)}`
800
962
  }),
801
- /*#__PURE__*/ _jsxs(DialogContent, {
802
- sx: {
803
- display: 'flex',
804
- flexDirection: 'column',
805
- gap: 2
806
- },
807
- children: [
808
- /*#__PURE__*/ _jsx(TextField, {
809
- label: "Cash received ($)",
810
- value: cashReceived,
811
- onChange: (event)=>setCashReceived(event.target.value.replace(/[^0-9.]/g, '')),
812
- size: "small",
813
- autoFocus: true,
963
+ /*#__PURE__*/ _jsx(Drawer, {
964
+ anchor: "bottom",
965
+ open: sheetOpen,
966
+ onClose: ()=>setSheetOpen(false),
967
+ slotProps: {
968
+ paper: {
814
969
  sx: {
815
- mt: 1
816
- },
817
- slotProps: {
818
- htmlInput: {
819
- inputMode: 'decimal'
820
- }
970
+ maxHeight: '90dvh',
971
+ p: 2,
972
+ borderTopLeftRadius: 16,
973
+ borderTopRightRadius: 16
821
974
  }
822
- }),
823
- Number(cashReceived) * 100 >= dueCents && cashReceived ? /*#__PURE__*/ _jsx(Alert, {
824
- severity: "success",
825
- children: `Change: ${usd(Math.round(Number(cashReceived) * 100) - dueCents)}`
826
- }) : null
827
- ]
828
- }),
829
- /*#__PURE__*/ _jsxs(DialogActions, {
830
- children: [
831
- /*#__PURE__*/ _jsx(Button, {
832
- onClick: ()=>setPaying(null),
833
- children: 'Cancel'
834
- }),
835
- /*#__PURE__*/ _jsx(Button, {
836
- variant: "contained",
837
- color: "primary",
838
- disabled: busy || Math.round(Number(cashReceived) * 100) < dueCents,
839
- // `onClick={settle}` would hand MUI's click event to `tender`.
840
- onClick: ()=>void settle('cash'),
841
- children: 'Complete sale'
842
- })
843
- ]
844
- })
845
- ]
846
- }),
847
- /*#__PURE__*/ _jsxs(Dialog, {
848
- open: paying === 'folio',
849
- onClose: ()=>setPaying(null),
850
- maxWidth: "xs",
851
- fullWidth: true,
852
- children: [
853
- /*#__PURE__*/ _jsx(DialogTitle, {
854
- children: `Charge to room — ${usd(dueCents)}`
855
- }),
856
- /*#__PURE__*/ _jsx(DialogContent, {
857
- sx: {
858
- display: 'flex',
859
- flexDirection: 'column',
860
- gap: 2
975
+ }
861
976
  },
862
- children: /*#__PURE__*/ _jsx(TextField, {
863
- label: "Checked-in stay",
864
- value: folioReservation,
865
- onChange: (event)=>setFolioReservation(event.target.value),
866
- size: "small",
867
- select: true,
868
- sx: {
869
- mt: 1
870
- },
871
- children: openStays.map((stay)=>{
872
- var _ref, _stay_guestName;
873
- return /*#__PURE__*/ _jsx(MenuItem, {
874
- value: stay.$id,
875
- children: (_ref = (_stay_guestName = stay.guestName) != null ? _stay_guestName : stay.guestEmail) != null ? _ref : stay.$id
876
- }, stay.$id);
877
- })
878
- })
879
- }),
880
- /*#__PURE__*/ _jsxs(DialogActions, {
881
- children: [
882
- /*#__PURE__*/ _jsx(Button, {
883
- onClick: ()=>setPaying(null),
884
- children: 'Cancel'
885
- }),
886
- /*#__PURE__*/ _jsx(Button, {
887
- variant: "contained",
888
- color: "primary",
889
- disabled: busy || !folioReservation,
890
- onClick: ()=>void settle('folio'),
891
- children: 'Charge folio'
892
- })
893
- ]
977
+ children: registerPanel
894
978
  })
895
979
  ]
896
- }),
980
+ }) : null,
981
+ /*#__PURE__*/ _jsx(PosItemDialog, _extends({
982
+ product: (_ref4 = itemSheet == null ? void 0 : itemSheet.product) != null ? _ref4 : null,
983
+ initial: itemSheet == null ? void 0 : itemSheet.initial,
984
+ onClose: ()=>setItemSheet(null),
985
+ onConfirm: (choice)=>{
986
+ const sheet = itemSheet;
987
+ setItemSheet(null);
988
+ if (!sheet) return;
989
+ if (sheet.editIndex === undefined) {
990
+ addProduct(sheet.product, choice.variant, choice.modifiers, choice.quantity);
991
+ return;
992
+ }
993
+ const at = sheet.editIndex;
994
+ setLines((prev)=>prev.map((line, index)=>index === at ? registerLineFor(sheet.product, choice) : line));
995
+ }
996
+ }, (itemSheet == null ? void 0 : itemSheet.editIndex) !== undefined ? {
997
+ onRemove: ()=>{
998
+ const at = itemSheet.editIndex;
999
+ setItemSheet(null);
1000
+ setLines((prev)=>prev.filter((_line, index)=>index !== at));
1001
+ }
1002
+ } : {})),
897
1003
  /*#__PURE__*/ _jsxs(Dialog, {
898
- open: Boolean(cardUrl),
899
- onClose: closeCardDialog,
1004
+ open: Boolean(pairing),
1005
+ onClose: ()=>setPairing(null),
900
1006
  maxWidth: "xs",
901
1007
  fullWidth: true,
902
1008
  children: [
903
1009
  /*#__PURE__*/ _jsx(DialogTitle, {
904
- children: 'Customer pays by card'
1010
+ children: 'Pair a customer display'
905
1011
  }),
906
1012
  /*#__PURE__*/ _jsxs(DialogContent, {
907
1013
  sx: {
@@ -916,33 +1022,29 @@ const usd = (cents)=>`$${(cents / 100).toFixed(2)}`;
916
1022
  sx: {
917
1023
  mt: 1
918
1024
  },
919
- children: 'Show this QR (or open the link on the customer display); the ' + 'order completes automatically once paid. Stripe Terminal ' + 'readers can replace this step later.'
1025
+ children: 'On the tablet facing your customer, open this address and enter the code. ' + 'The code works once and expires in 10 minutes.'
920
1026
  }),
921
- /*#__PURE__*/ _jsx(Box, {
1027
+ /*#__PURE__*/ _jsx(Typography, {
1028
+ variant: "body1",
922
1029
  sx: {
923
- display: 'flex',
924
- justifyContent: 'center'
1030
+ wordBreak: 'break-all'
925
1031
  },
926
- children: /*#__PURE__*/ _jsx(QRCodeSVG, {
927
- value: cardUrl,
928
- size: 256,
929
- level: "L",
930
- marginSize: 4,
931
- title: "Payment QR",
932
- role: "img"
933
- })
1032
+ children: `${typeof window === 'undefined' ? '' : window.location.origin}/kiosk/commerce/pos-display`
934
1033
  }),
935
- /*#__PURE__*/ _jsx(Button, {
936
- size: "small",
937
- href: cardUrl,
938
- target: "_blank",
939
- children: 'Open payment page'
1034
+ /*#__PURE__*/ _jsx(Typography, {
1035
+ variant: "h3",
1036
+ component: "p",
1037
+ sx: {
1038
+ textAlign: 'center',
1039
+ letterSpacing: 8
1040
+ },
1041
+ children: pairing == null ? void 0 : pairing.code
940
1042
  })
941
1043
  ]
942
1044
  }),
943
1045
  /*#__PURE__*/ _jsx(DialogActions, {
944
1046
  children: /*#__PURE__*/ _jsx(Button, {
945
- onClick: closeCardDialog,
1047
+ onClick: ()=>setPairing(null),
946
1048
  children: 'Done'
947
1049
  })
948
1050
  })