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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/cart-extras.d.ts +6 -0
  3. package/src/lib/components/cart-extras.js +4 -1
  4. package/src/lib/components/cart-extras.js.map +1 -1
  5. package/src/lib/components/cart-fulfillment.d.ts +117 -0
  6. package/src/lib/components/cart-fulfillment.js +367 -0
  7. package/src/lib/components/cart-fulfillment.js.map +1 -0
  8. package/src/lib/components/cart.js +52 -10
  9. package/src/lib/components/cart.js.map +1 -1
  10. package/src/lib/components/commerce-console-page.js +42 -1
  11. package/src/lib/components/commerce-console-page.js.map +1 -1
  12. package/src/lib/components/console/catalog-organization-card.component.js +1 -0
  13. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  14. package/src/lib/components/console/host-orders-card.component.js +42 -11
  15. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  16. package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
  17. package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
  18. package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
  19. package/src/lib/components/console/locations-card.component.js +177 -3
  20. package/src/lib/components/console/locations-card.component.js.map +1 -1
  21. package/src/lib/components/console/order-detail-dialog.component.js +10 -0
  22. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  23. package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
  24. package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
  25. package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
  26. package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
  27. package/src/lib/components/console/order-offline-notice.component.js +53 -0
  28. package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
  29. package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
  30. package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
  31. package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
  32. package/src/lib/components/console/pos/pos-api.d.ts +24 -1
  33. package/src/lib/components/console/pos/pos-api.js +13 -0
  34. package/src/lib/components/console/pos/pos-api.js.map +1 -1
  35. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
  36. package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
  37. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
  38. package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
  39. package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
  40. package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
  41. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
  42. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
  43. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
  44. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
  45. package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
  46. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
  47. package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
  48. package/src/lib/components/console/pos/use-pos-display.js +3 -2
  49. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  50. package/src/lib/components/console/pos-devices-card.component.js +2 -2
  51. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  52. package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
  53. package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
  54. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
  55. package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
  56. package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
  57. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  58. package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
  59. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
  60. package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
  61. package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
  62. package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
  63. package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
  64. package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
  65. package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
  66. package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
  67. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
  68. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
  69. package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
  70. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
  71. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
  72. package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
  73. package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
  74. package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
  75. package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
  76. package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
  77. package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
  78. package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
  79. package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
  80. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
  81. package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
  82. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
  83. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
  84. package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
  85. package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
  86. package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
  87. package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
  88. package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
  89. package/src/lib/components/console/pos-offline/register-offline.js +24 -0
  90. package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
  91. package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
  92. package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
  93. package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
  94. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
  95. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
  96. package/src/lib/components/console/pos-page.component.js +228 -51
  97. package/src/lib/components/console/pos-page.component.js.map +1 -1
  98. package/src/lib/components/console/pos-zones.d.ts +23 -0
  99. package/src/lib/components/console/pos-zones.js +31 -0
  100. package/src/lib/components/console/pos-zones.js.map +1 -0
  101. package/src/lib/components/console/product-editor-dialog.component.js +10 -64
  102. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  103. package/src/lib/components/console/products-hub-card.component.js +46 -30
  104. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  105. package/src/lib/components/console/shipping-settings-card.component.js +1 -1
  106. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  107. package/src/lib/components/console/stock-movements-card.component.js +48 -16
  108. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  109. package/src/lib/components/console/store-zones.d.ts +8 -1
  110. package/src/lib/components/console/store-zones.js +11 -1
  111. package/src/lib/components/console/store-zones.js.map +1 -1
  112. package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
  113. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
  114. package/src/lib/components/order-status.js +66 -0
  115. package/src/lib/components/order-status.js.map +1 -1
  116. package/src/lib/components/product-detail.js +42 -15
  117. package/src/lib/components/product-detail.js.map +1 -1
  118. package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
  119. package/src/lib/constants/local-fulfillment-list-query.js +84 -0
  120. package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
  121. package/src/lib/constants/orders-list-query.d.ts +7 -2
  122. package/src/lib/constants/orders-list-query.js +89 -8
  123. package/src/lib/constants/orders-list-query.js.map +1 -1
  124. package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
  125. package/src/lib/constants/pos-shift-list-query.js +115 -0
  126. package/src/lib/constants/pos-shift-list-query.js.map +1 -0
  127. package/src/lib/constants/product-list-query.d.ts +6 -1
  128. package/src/lib/constants/product-list-query.js +77 -8
  129. package/src/lib/constants/product-list-query.js.map +1 -1
  130. package/src/lib/constants/stock-movement-query.d.ts +3 -2
  131. package/src/lib/constants/stock-movement-query.js +52 -8
  132. package/src/lib/constants/stock-movement-query.js.map +1 -1
  133. package/src/lib/declarations.server.js +21 -0
  134. package/src/lib/declarations.server.js.map +1 -1
  135. package/src/lib/model/buyer-notifications.d.ts +5 -3
  136. package/src/lib/model/buyer-notifications.js +25 -4
  137. package/src/lib/model/buyer-notifications.js.map +1 -1
  138. package/src/lib/model/commerce-orders.d.ts +103 -1
  139. package/src/lib/model/commerce-orders.js +2 -1
  140. package/src/lib/model/commerce-orders.js.map +1 -1
  141. package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
  142. package/src/lib/model/commerce-pos-kiosk.js +147 -0
  143. package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
  144. package/src/lib/model/commerce-pos-offline.d.ts +234 -0
  145. package/src/lib/model/commerce-pos-offline.js +301 -0
  146. package/src/lib/model/commerce-pos-offline.js.map +1 -0
  147. package/src/lib/model/commerce-pos-ops.d.ts +16 -6
  148. package/src/lib/model/commerce-pos-ops.js +12 -4
  149. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  150. package/src/lib/model/commerce-pos.d.ts +13 -1
  151. package/src/lib/model/commerce-pos.js +5 -4
  152. package/src/lib/model/commerce-pos.js.map +1 -1
  153. package/src/lib/model/commerce-stock-holds.d.ts +24 -3
  154. package/src/lib/model/commerce-stock-holds.js +26 -8
  155. package/src/lib/model/commerce-stock-holds.js.map +1 -1
  156. package/src/lib/model/commerce.d.ts +7 -1
  157. package/src/lib/model/commerce.js.map +1 -1
  158. package/src/lib/model/index.d.ts +5 -0
  159. package/src/lib/model/index.js +5 -0
  160. package/src/lib/model/index.js.map +1 -1
  161. package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
  162. package/src/lib/model/local-fulfillment-settings.js +361 -0
  163. package/src/lib/model/local-fulfillment-settings.js.map +1 -0
  164. package/src/lib/model/order-list-fields.d.ts +10 -1
  165. package/src/lib/model/order-list-fields.js +1 -0
  166. package/src/lib/model/order-list-fields.js.map +1 -1
  167. package/src/lib/model/order-local-fulfillment.d.ts +131 -0
  168. package/src/lib/model/order-local-fulfillment.js +125 -0
  169. package/src/lib/model/order-local-fulfillment.js.map +1 -0
  170. package/src/lib/model/order-shipping-export.js +4 -0
  171. package/src/lib/model/order-shipping-export.js.map +1 -1
  172. package/src/lib/model/order-status-view.d.ts +20 -1
  173. package/src/lib/model/order-status-view.js +60 -6
  174. package/src/lib/model/order-status-view.js.map +1 -1
  175. package/src/lib/model/product-write.d.ts +186 -0
  176. package/src/lib/model/product-write.js +116 -0
  177. package/src/lib/model/product-write.js.map +1 -0
  178. package/src/lib/plugin-config.js +6 -2
  179. package/src/lib/plugin-config.js.map +1 -1
  180. package/src/lib/plugin.js +11 -0
  181. package/src/lib/plugin.js.map +1 -1
  182. package/src/lib/pos-kiosk-config.d.ts +26 -0
  183. package/src/lib/pos-kiosk-config.js +59 -0
  184. package/src/lib/pos-kiosk-config.js.map +1 -0
  185. package/src/lib/server/api-v1/openapi.js +8 -0
  186. package/src/lib/server/api-v1/openapi.js.map +1 -1
  187. package/src/lib/server/api-v1/order-view.d.ts +19 -0
  188. package/src/lib/server/api-v1/order-view.js +35 -0
  189. package/src/lib/server/api-v1/order-view.js.map +1 -1
  190. package/src/lib/server/billing-webhook.js +238 -87
  191. package/src/lib/server/billing-webhook.js.map +1 -1
  192. package/src/lib/server/cart-checkout.d.ts +2 -0
  193. package/src/lib/server/cart-checkout.js +173 -13
  194. package/src/lib/server/cart-checkout.js.map +1 -1
  195. package/src/lib/server/channel-order-updates.d.ts +50 -0
  196. package/src/lib/server/channel-order-updates.js +290 -0
  197. package/src/lib/server/channel-order-updates.js.map +1 -0
  198. package/src/lib/server/channel-orders.d.ts +85 -0
  199. package/src/lib/server/channel-orders.js +543 -0
  200. package/src/lib/server/channel-orders.js.map +1 -0
  201. package/src/lib/server/checkout-extras.js +18 -4
  202. package/src/lib/server/checkout-extras.js.map +1 -1
  203. package/src/lib/server/checkout.js +71 -14
  204. package/src/lib/server/checkout.js.map +1 -1
  205. package/src/lib/server/local-fulfillment-status.d.ts +86 -0
  206. package/src/lib/server/local-fulfillment-status.js +379 -0
  207. package/src/lib/server/local-fulfillment-status.js.map +1 -0
  208. package/src/lib/server/local-fulfillment.d.ts +190 -0
  209. package/src/lib/server/local-fulfillment.js +580 -0
  210. package/src/lib/server/local-fulfillment.js.map +1 -0
  211. package/src/lib/server/membership-register.js +3 -1
  212. package/src/lib/server/membership-register.js.map +1 -1
  213. package/src/lib/server/order-notifications.js +61 -0
  214. package/src/lib/server/order-notifications.js.map +1 -1
  215. package/src/lib/server/pos-display.d.ts +27 -1
  216. package/src/lib/server/pos-display.js +50 -9
  217. package/src/lib/server/pos-display.js.map +1 -1
  218. package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
  219. package/src/lib/server/pos-kiosk-principal.js +42 -0
  220. package/src/lib/server/pos-kiosk-principal.js.map +1 -0
  221. package/src/lib/server/pos-kiosk.d.ts +54 -0
  222. package/src/lib/server/pos-kiosk.js +972 -0
  223. package/src/lib/server/pos-kiosk.js.map +1 -0
  224. package/src/lib/server/pos-offline-sync.d.ts +85 -0
  225. package/src/lib/server/pos-offline-sync.js +765 -0
  226. package/src/lib/server/pos-offline-sync.js.map +1 -0
  227. package/src/lib/server/pos-order.js +22 -4
  228. package/src/lib/server/pos-order.js.map +1 -1
  229. package/src/lib/server/pos-payment.d.ts +6 -0
  230. package/src/lib/server/pos-payment.js +225 -6
  231. package/src/lib/server/pos-payment.js.map +1 -1
  232. package/src/lib/server/pos-print.js +5 -0
  233. package/src/lib/server/pos-print.js.map +1 -1
  234. package/src/lib/server/pos-return.js +27 -0
  235. package/src/lib/server/pos-return.js.map +1 -1
  236. package/src/lib/server/pos-sale.d.ts +6 -0
  237. package/src/lib/server/pos-sale.js +2 -0
  238. package/src/lib/server/pos-sale.js.map +1 -1
  239. package/src/lib/server/pos-shift.js +8 -1
  240. package/src/lib/server/pos-shift.js.map +1 -1
  241. package/src/lib/server/product-catalog.js +5 -1
  242. package/src/lib/server/product-catalog.js.map +1 -1
  243. package/src/lib/server/product-drafts.d.ts +5 -1
  244. package/src/lib/server/product-drafts.js +3 -3
  245. package/src/lib/server/product-drafts.js.map +1 -1
  246. package/src/lib/server/product-writer.d.ts +19 -0
  247. package/src/lib/server/product-writer.js +261 -0
  248. package/src/lib/server/product-writer.js.map +1 -0
  249. package/src/lib/server/products-write.d.ts +61 -0
  250. package/src/lib/server/products-write.js +375 -0
  251. package/src/lib/server/products-write.js.map +1 -0
  252. package/src/lib/server/refund.js +3 -0
  253. package/src/lib/server/refund.js.map +1 -1
  254. package/src/lib/server/stock-hold.d.ts +9 -1
  255. package/src/lib/server/stock-hold.js +15 -7
  256. package/src/lib/server/stock-hold.js.map +1 -1
  257. package/src/lib/server.js +21 -0
  258. package/src/lib/server.js.map +1 -1
  259. package/src/lib/tenant-emails.js +161 -0
  260. package/src/lib/tenant-emails.js.map +1 -1
  261. package/src/lib/testing/memory-firestore.d.ts +16 -3
  262. package/src/lib/testing/memory-firestore.js +11 -3
  263. package/src/lib/testing/memory-firestore.js.map +1 -1
  264. package/src/lib/transfer/products.server.d.ts +5 -0
  265. package/src/lib/transfer/products.server.js +2 -2
  266. package/src/lib/transfer/products.server.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-page.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport type { ConsolePluginPageProps } from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport {\n PRODUCT_LIST_BASE,\n PRODUCT_LIST_QUERY,\n} from '../../constants/product-list-query'\nimport { NextPageTitle } from '@aglyn/shared-ui-next/contexts/next-page-title-provider'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport type { ListFilterRequest } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { planListQuery } from '@aglyn/shared-ui-jsx/const/list-query-plan'\nimport { nameSearchNormalizers } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Drawer,\n MenuItem,\n Stack,\n TextField,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport {\n collection,\n getDocs,\n limit,\n query,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport { useFirestoreCollection } from '@aglyn/tenant-feature-instance'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport { useOrgPlan } from '@aglyn/tenant-feature-instance'\nimport {\n newAttemptKey,\n openPosSale,\n posRegisterContext,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n} from './pos/pos-api'\nimport { PosCartPanel, type RegisterLine } from './pos/pos-cart-panel.component'\nimport { ScanAdornment } from '../../barcode/scan-button.component'\nimport { useScannerWedge } from '../../barcode/scanner-wedge'\nimport {\n PosCustomerLookup,\n PosLastReceipt,\n PosOperationsBar,\n usePosCashier,\n usePosOpsSettings,\n type PosSelectedCustomer,\n} from './pos-ops/register-ops'\nimport { POS_QUICK_KEYS, POS_TOUCH_PX, PosProductGrid } from './pos/pos-product-grid.component'\nimport { PosItemDialog, posItemNeedsChoice, type PosItemChoice } from './pos/pos-item-dialog.component'\nimport { PosReceiptPanel } from './pos/pos-receipt-panel.component'\nimport { PosTenderPanel } from './pos/pos-tender-panel.component'\nimport { posDisplayTipCents, usePosDisplay } from './pos/use-pos-display'\n\n/** The till sells active products only; every read of the catalog asks it. */\nconst SELLABLE: ListFilterRequest = { field: 'status', op: 'equals', value: 'active' }\n\n/**\n * How many products the till's grid shows. The grid is a picker, not the\n * catalog: typing narrows it on the query, so a name reaches every product.\n */\nconst POS_GRID_CEILING = 500\n\n/**\n * The products hub's query (AGL-3321), narrowed to what the till may sell:\n * live products (`deletedAt == null`, the list's scope), `status == active`,\n * and any typed word as the search on `nameTokens` — or, for a scan, the\n * whole scanned code as a SKU or barcode clause. Every shape is one the hub's\n * composites already serve.\n */\nexport function posProductPlan(options: {\n search?: string\n code?: { field: 'barcodes' | 'skus'; value: string }\n /** A category chip (AGL-3607): served by the storefront's own composite. */\n categoryId?: string\n /** The Quick keys chip (AGL-3607): products marked `posQuickKey`. */\n quickKeys?: boolean\n}) {\n const typed = options.search?.trim()\n const plan = planListQuery(\n POS_GRID_QUERY,\n {\n base: PRODUCT_LIST_BASE,\n clauses: [\n SELLABLE,\n ...(options.code\n ? [{ field: options.code.field, op: 'contains', value: options.code.value }]\n : []),\n ...(options.categoryId\n ? [{ field: 'categoryIds', op: 'contains', value: options.categoryId }]\n : []),\n ],\n // A chip and a typed word are both array clauses, and Firestore takes\n // one: with a chip on, the word narrows by name prefix instead.\n search: typed && !options.categoryId ? [typed] : [],\n },\n nameSearchNormalizers,\n )\n // The Quick keys chip (AGL-3607) is a boolean equality the list planner\n // does not model, added beside the scope and status it composes with —\n // `deletedAt ==, status ==, posQuickKey ==, nameLower ASC` is declared in\n // the index file. A typed word searches the whole catalog instead: a\n // cashier who types is looking past the quick keys.\n if (options.quickKeys && !typed && !options.code) {\n return {\n ...plan,\n filters: [...plan.filters, { path: 'posQuickKey', op: '==', value: true }],\n } as typeof plan\n }\n return plan\n}\n\n/**\n * The grid's query: the products hub's, plus the category a chip picks\n * (AGL-3607). `categoryIds CONTAINS, nameLower ASC` is a composite the\n * storefront catalog already declares.\n */\nexport const POS_GRID_QUERY = {\n ...PRODUCT_LIST_QUERY,\n fields: [\n ...PRODUCT_LIST_QUERY.fields,\n {\n column: 'categoryIds',\n kind: 'exact' as const,\n path: 'categoryIds',\n tokensPath: 'categoryIds',\n operators: ['contains'],\n },\n ],\n} as typeof PRODUCT_LIST_QUERY\n\n/**\n * POS register (AGL-312, AGL-3607): a tablet-first sale surface — the\n * product grid with search, scan and category chips, the basket, and a\n * tender panel that takes one or more payments against an open sale (cash,\n * card reader, a native Tap to Pay bridge, a typed card, the QR link, gift\n * cards and room charges) until the balance is zero. A paired customer\n * display mirrors the basket and takes the tip and the receipt (AGL-3608).\n *\n * On a wide screen (900px and up) the grid and the register sit side by\n * side; below that the register is a bottom sheet behind a sticky total bar.\n */\n/*\n * `managePos` is NOT read here. The nav item in `plugin.ts` declares it and\n * the shell refuses the route before this component is constructed, so a\n * reader without the key never reaches this file and there is no unpermitted\n * state for it to render — the same arrangement the entitlement gate has.\n *\n * Re-adding a check off the `permissions` prop would be a second answer to a\n * settled question, and a laxer one: a prop absent because the map has not\n * landed reads as permitted here, while the shell holds the route on that\n * same condition rather than guessing. The server routes remain the\n * enforcement point for every sale and every payment.\n */\n/** Where a register device remembers the category chip it was left on. */\nconst POS_CATEGORY_KEY = 'aglyn.pos.category'\n\n/** The basket line an item-sheet choice makes: label and estimate from the product. */\nexport function registerLineFor(\n product: any,\n choice: PosItemChoice,\n): RegisterLine {\n const { variant, modifiers, quantity } = choice\n const resolved = CommerceModel.resolveLineModifiers(product, modifiers)\n const picked = resolved.ok ? resolved.modifiers : []\n const label = CommerceModel.lineLabelWithModifiers(\n Object.keys(variant.options ?? {}).length\n ? Object.values(variant.options ?? {}).join(' / ')\n : undefined,\n picked,\n )\n return {\n productId: product.$id,\n ...(variant.id !== 'default' ? { variantId: variant.id } : {}),\n name: product.name,\n ...(label ? { variantLabel: label } : {}),\n unitAmountCents:\n Math.round(Number(variant.priceUsd) * 100) + (resolved.ok ? resolved.extraCents : 0),\n quantity,\n ...(modifiers.length ? { modifiers } : {}),\n }\n}\n\n/** Same product, variant and choices: the lines that merge into one. */\nfunction lineKey(line: Pick<RegisterLine, 'productId' | 'variantId' | 'modifiers'>): string {\n return `${line.productId}:${line.variantId ?? ''}:${CommerceModel.modifierSelectionKey(line.modifiers)}`\n}\n\nexport function PosConsolePage({ hostId }: ConsolePluginPageProps) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const theme = useTheme()\n const wide = useMediaQuery(theme.breakpoints.up('md'))\n\n const [search, setSearch] = useState('')\n // The chip a register opens on is remembered per device: a counter that\n // rings from its quick keys reopens on them.\n const [categoryId, setCategoryIdState] = useState(() => {\n try {\n return window.localStorage.getItem(POS_CATEGORY_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const setCategoryId = useCallback((id: string) => {\n setCategoryIdState(id)\n try {\n window.localStorage.setItem(POS_CATEGORY_KEY, id)\n } catch {\n // Storage blocked: the chip still works for this visit.\n }\n }, [])\n const gridPlan = useMemo(\n () =>\n categoryId === POS_QUICK_KEYS\n ? posProductPlan({ search, quickKeys: true })\n : posProductPlan({ search, categoryId }),\n [search, categoryId],\n )\n const { data: productDocs } = useFirestoreCollection<any>(\n /*\n * The till's grid, narrowed by the QUERY rather than by the rows it\n * happened to fetch (AGL-2501, AGL-2292, AGL-3321): the first five\n * hundred SELLABLE products by name, and a typed name reaches the whole\n * catalog. The scan does not come through here — see `handleSearchEnter`.\n */\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'products'),\n ...listQueryConstraints(gridPlan),\n limit(POS_GRID_CEILING),\n ),\n [firestore, hostId, gridPlan],\n { idField: '$id' },\n )\n const { data: categoryDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'productCategories'), limit(30)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { data: locationDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'locations'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { org, ready: planReady } = useOrgPlan(hostId)\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n // Only registers within the plan cap can transact (AGL-482), and not until\n // the org doc has arrived (AGL-1064). Per SITE (AGL-1775).\n const registerCap = Aglyn.checkHostRegisterQuota(org, hostId, registers.length).limit\n const withinCap = CommerceModel.registersWithinCap(registers, registerCap)\n const usableRegisters = planReady ? registers.filter((r: any) => withinCap.has(r.$id)) : []\n /*\n * The stays a sale can be charged to, asked for BY STATUS (AGL-3321).\n */\n const { data: reservationDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('status', '==', 'checked_in'),\n limit(100),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const openStays = reservationDocs ?? []\n\n const [lines, setLines] = useState<RegisterLine[]>([])\n const [discountPct, setDiscountPct] = useState(0)\n // The customer the lookup attached (AGL-3609); their email is the sale's.\n const [customer, setCustomer] = useState<PosSelectedCustomer | null>(null)\n const customerEmail = customer?.email ?? ''\n const [locationId, setLocationId] = useState('')\n const [registerId, setRegisterId] = useState('')\n useEffect(() => {\n if (registerId || usableRegisters.length === 0) return\n const first = usableRegisters[0]\n setRegisterId(first.$id)\n if (first.locationId) setLocationId(first.locationId)\n }, [usableRegisters, registerId])\n const registerName = String(\n usableRegisters.find((register: any) => register.$id === registerId)?.name ?? '',\n )\n // Who is ringing (AGL-3609): a PIN-switched cashier, and the idle lock.\n const opsSettings = usePosOpsSettings(hostId)\n const cashier = usePosCashier({\n hostId,\n registerId,\n autoLockMinutes: opsSettings.autoLockMinutes,\n })\n // The last completed sale, whose receipt can still be printed (AGL-3609).\n const [lastReceipt, setLastReceipt] = useState<{ orderId: string } | null>(null)\n\n const [context, setContext] = useState<PosRegisterContext | null>(null)\n // Keyed on the uid, not the user object: a session refresh hands back a\n // new object for the same person, and re-reading the context on every one\n // would re-render the register in a loop.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? ''\n useEffect(() => {\n const signedIn = userRef.current\n if (!signedIn) return\n let active = true\n posRegisterContext(signedIn, hostId)\n .then((answer) => {\n // Only a whole answer: a register that half-knows its tenders would\n // offer one the server then refuses.\n if (active && answer?.settings && answer?.terminal) setContext(answer)\n })\n .catch(() => undefined)\n return () => {\n active = false\n }\n }, [uid, hostId])\n\n /** The open sale, once the basket has been priced and payment started. */\n const [sale, setSale] = useState<PosSaleSummary | null>(null)\n const [saleLines, setSaleLines] = useState<RegisterLine[]>([])\n const [opening, setOpening] = useState(false)\n const [sheetOpen, setSheetOpen] = useState(false)\n const [pairing, setPairing] = useState<{ code: string; expiresAtMs: number } | null>(null)\n const display = usePosDisplay(user, hostId, registerId)\n\n /**\n * One key per basket (AGL-1691): minted on the first Charge and retired\n * whenever the basket changes, so a retried Charge finds the same sale and\n * ringing the same coffee twice is two sales.\n */\n const attemptKey = useRef('')\n useEffect(() => {\n attemptKey.current = ''\n }, [lines, discountPct])\n\n const products = useMemo(\n () =>\n [...(productDocs ?? [])].map((product: any) => ({\n ...CommerceModel.liftLegacyProduct(product),\n $id: product.$id,\n })),\n [productDocs],\n )\n const productsById = useMemo(\n () => new Map(products.map((product: any) => [product.$id, product])),\n [products],\n )\n /** AGL-2357: warns, never blocks. */\n const shortfalls = useMemo(\n () =>\n lines.map((line) => {\n const product: any = productsById.get(line.productId)\n if (!product) return null\n return CommerceModel.stockShortfall(\n product,\n line.variantId ?? product.variants?.[0]?.id,\n line.quantity,\n )\n }),\n [lines, productsById],\n )\n\n const itemsCents = lines.reduce((sum, line) => sum + line.unitAmountCents * line.quantity, 0)\n const discountCents = Math.round((itemsCents * discountPct) / 100)\n const estimateCents = itemsCents - discountCents\n const units = lines.reduce((sum, line) => sum + line.quantity, 0)\n\n const notify = useCallback(\n (message: string, variant: 'success' | 'error' | 'warning' | 'info') => {\n enqueueSnackbar(message, { variant, persist: false, allowDuplicate: true })\n },\n [enqueueSnackbar],\n )\n\n /**\n * Adds a line, or more of an identical one: the same product, variant and\n * modifiers merge, so two oat lattes are one line of two and an oat latte\n * beside a whole-milk one stays two lines.\n */\n const addProduct = useCallback(\n (product: any, variant?: any, modifiers: CommerceModel.ModifierSelection[] = [], quantity = 1) => {\n const next = registerLineFor(product, {\n variant: variant ?? product.variants[0],\n modifiers,\n quantity,\n })\n setLines((prev) => {\n const existing = prev.find((line) => lineKey(line) === lineKey(next))\n if (existing) {\n return prev.map((line) =>\n line === existing\n ? { ...line, quantity: Math.min(99, line.quantity + next.quantity) }\n : line,\n )\n }\n return [...prev, next]\n })\n },\n [],\n )\n\n /** The item sheet: a product to add, or a basket line to change. */\n const [itemSheet, setItemSheet] = useState<{\n product: any\n editIndex?: number\n initial?: { variantId?: string; modifiers?: CommerceModel.ModifierSelection[]; quantity: number }\n } | null>(null)\n // Every product rung up this sale, so a line can be reopened after the\n // grid has moved on to another category or search.\n const productCache = useRef(new Map<string, any>())\n const tapProduct = useCallback(\n (product: any, variant?: any) => {\n productCache.current.set(product.$id, product)\n if (posItemNeedsChoice(product) && !(variant && CommerceModel.productModifierGroups(product).length === 0)) {\n setItemSheet({\n product,\n ...(variant ? { initial: { variantId: variant.id, quantity: 1 } } : {}),\n })\n return\n }\n addProduct(product, variant)\n },\n [addProduct],\n )\n const basketCounts = useMemo(() => {\n const counts = new Map<string, number>()\n for (const line of lines) counts.set(line.productId, (counts.get(line.productId) ?? 0) + line.quantity)\n return counts\n }, [lines])\n\n /**\n * The barcode wedge: a LOOKUP against the whole catalog (AGL-2501),\n * barcode first, and a miss says so.\n */\n const lookupCode = useCallback(async (scanned: string) => {\n const needle = scanned.trim().toLowerCase()\n if (!needle || sale) return\n const lookup = async (field: 'barcodes' | 'skus') => {\n const found = await getDocs(\n query(\n collection(firestore, 'hosts', hostId, 'products'),\n ...listQueryConstraints(posProductPlan({ code: { field, value: needle } })),\n limit(1),\n ),\n )\n return found.docs[0]\n }\n let hit: Awaited<ReturnType<typeof lookup>>\n try {\n hit = (await lookup('barcodes')) ?? (await lookup('skus'))\n } catch (error) {\n console.error(error)\n return void notify('Could not reach the catalog — try again', 'warning')\n }\n if (!hit) return void notify(`No product matches “${scanned.trim()}”`, 'warning')\n const product = { ...CommerceModel.liftLegacyProduct(hit.data() as any), $id: hit.id }\n const variant =\n product.variants.find(\n (item: any) =>\n item.barcode?.trim().toLowerCase() === needle || item.sku?.trim().toLowerCase() === needle,\n ) ?? product.variants[0]\n // A scanned variant is the variant; a product with modifiers still asks\n // for them, with that variant already picked.\n tapProduct(product, variant)\n setSearch('')\n }, [sale, firestore, hostId, tapProduct, notify])\n const handleSearchEnter = useCallback(() => lookupCode(search), [lookupCode, search])\n // A scanner fired while focus is on a product or a button (AGL-3619), and\n // the camera; neither while a sale is taking payment or an item is open.\n useScannerWedge((code) => void lookupCode(code), !sale && !itemSheet)\n const scanAdornment = useMemo(\n () => <ScanAdornment label=\"Scan a barcode with the camera\" onScan={(code) => void lookupCode(code)} />,\n [lookupCode],\n )\n\n /** Prices the basket on the server and opens the sale for payment. */\n // A ref, not `opening`: two taps inside one React batch both read the\n // pre-click state, and only a ref is written before the second reads it\n // (the AGL-1682 lesson).\n const chargeInFlight = useRef(false)\n const charge = useCallback(async () => {\n if (chargeInFlight.current || lines.length === 0 || !user) return\n if (!registerId) return void notify('Select a register before taking payment', 'warning')\n if (!attemptKey.current) attemptKey.current = newAttemptKey()\n chargeInFlight.current = true\n setOpening(true)\n try {\n const opened = await openPosSale(user, attemptKey.current, {\n hostId,\n registerId,\n lines,\n discountPct,\n ...(customerEmail ? { customerEmail } : {}),\n ...(customer ? { customer } : {}),\n ...(cashier.assertion ? { cashierAssertion: cashier.assertion } : {}),\n ...(locationId ? { locationId } : {}),\n })\n setSaleLines(lines)\n setSale({\n orderId: opened.orderId,\n status: 'pending',\n totalCents: opened.totals.totalCents,\n paidCents: 0,\n dueCents: opened.totals.totalCents,\n tenderableCents: opened.totals.totalCents,\n tipCents: 0,\n payments: [],\n })\n setSheetOpen(true)\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Sale failed', 'error')\n } finally {\n chargeInFlight.current = false\n setOpening(false)\n }\n }, [lines, user, registerId, hostId, discountPct, customerEmail, customer, cashier.assertion, locationId, notify])\n\n const resetSale = useCallback(() => {\n if (sale?.status === 'paid') setLastReceipt({ orderId: sale.orderId })\n setSale(null)\n setSaleLines([])\n setLines([])\n setDiscountPct(0)\n setCustomer(null)\n setSheetOpen(false)\n }, [sale])\n\n // The customer display mirrors the basket while nothing else is on it.\n const mirrored = sale ? saleLines : lines\n // Whether the display was last left showing a basket. A paid sale leaves it\n // on the thank-you the server wrote, which an empty new basket must not\n // cut short with the idle screen; the next item added takes it over.\n // True at first, so a register that opens empty clears whatever a previous\n // session left on the screen.\n const displayShowsBasket = useRef(true)\n // The tip picked for the payment about to be taken; the ledger has it only\n // once that payment is recorded. Gone with the sale.\n const [pendingTipCents, setPendingTipCents] = useState(0)\n useEffect(() => {\n if (!sale || sale.status === 'paid') setPendingTipCents(0)\n }, [sale])\n useEffect(() => {\n if (sale?.status === 'paid') displayShowsBasket.current = false\n }, [sale?.status])\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (sale?.payments.some((payment) => payment.status === 'pending' && payment.method === 'card_present')) {\n return\n }\n if (sale?.status === 'paid') return\n if (!mirrored.length && !displayShowsBasket.current) return\n const timer = setTimeout(() => {\n displayShowsBasket.current = mirrored.length > 0\n void display.show(\n mirrored.length\n ? {\n mode: 'cart',\n cart: {\n lines: mirrored.map((line) => ({\n name: line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n quantity: line.quantity,\n amountCents: line.unitAmountCents * line.quantity,\n })),\n itemsCents,\n discountCents,\n taxCents: sale ? Math.max(0, sale.totalCents - estimateCents) : 0,\n totalCents: sale ? sale.totalCents : estimateCents,\n ...(sale\n ? {\n paidCents: sale.paidCents,\n dueCents: sale.dueCents,\n tipCents: posDisplayTipCents(sale, pendingTipCents),\n }\n : {}),\n },\n }\n : { mode: 'idle' },\n )\n }, 400)\n return () => clearTimeout(timer)\n }, [display, mirrored, sale, itemsCents, discountCents, estimateCents, pendingTipCents])\n\n const registerPicker = !planReady ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Checking your plan…'}\n </Typography>\n ) : usableRegisters.length === 0 ? (\n <Typography variant=\"body2\" color=\"warning.main\">\n {registers.length > 0\n ? 'Your registers exceed your plan — remove extras or upgrade in Billing to take payments.'\n : 'No POS register yet. Add one under Commerce → Settings → POS registers before taking payments.'}\n </Typography>\n ) : usableRegisters.length > 1 ? (\n <TextField\n label=\"Register\"\n value={registerId}\n onChange={(event) => setRegisterId(event.target.value)}\n size=\"small\"\n select\n disabled={Boolean(sale)}\n >\n {usableRegisters.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {usableRegisters[0]?.name}\n </Typography>\n )\n\n /**\n * On a narrow screen the register's bar owns the bottom edge, so it moves\n * the console's floating launchers clear of itself through the shell's\n * `--aglyn-dock-inset-bottom` seam; a launcher left in the corner sat on\n * top of Charge.\n */\n const bottomBarRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const node = bottomBarRef.current\n if (wide || !node) return undefined\n const root = document.documentElement\n const property = '--aglyn-dock-inset-bottom'\n const publish = () => {\n root.style.setProperty(property, `${Math.round(node.getBoundingClientRect().height) + 20}px`)\n }\n publish()\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(publish)\n observer?.observe(node)\n return () => {\n observer?.disconnect()\n root.style.removeProperty(property)\n }\n }, [wide])\n\n const registerPanel = (\n <Stack spacing={1.5} sx={{ minHeight: 0, flex: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"h6\" sx={{ flex: 1 }}>\n {'Register'}\n </Typography>\n {registerId ? (\n <Button\n size=\"small\"\n onClick={async () => {\n try {\n setPairing(await display.pairingCode())\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not make a code', 'error')\n }\n }}\n >\n {display.connected ? 'Display connected' : 'Pair display'}\n </Button>\n ) : null}\n </Stack>\n {registerPicker}\n {(locationDocs?.length ?? 0) > 1 ? (\n <TextField\n label=\"Location\"\n value={locationId}\n onChange={(event) => setLocationId(event.target.value)}\n size=\"small\"\n select\n disabled={Boolean(sale)}\n >\n {(locationDocs ?? []).map((location: any) => (\n <MenuItem key={location.$id} value={location.$id}>\n {location.name}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {registerId ? (\n <PosOperationsBar\n hostId={hostId}\n registerId={registerId}\n {...(registerName ? { registerName } : {})}\n cashier={cashier}\n onExchange={(returned) =>\n setCustomer(\n returned.email || returned.name\n ? { kind: 'none', id: '', name: returned.name ?? '', email: returned.email, phone: null }\n : null,\n )\n }\n />\n ) : null}\n <PosCartPanel\n lines={sale ? saleLines : lines}\n shortfalls={sale ? [] : shortfalls}\n onQuantity={(index, quantity) =>\n setLines((prev) =>\n quantity <= 0\n ? prev.filter((_line, at) => at !== index)\n : prev.map((line, at) => (at === index ? { ...line, quantity: Math.min(99, quantity) } : line)),\n )\n }\n onRemove={(index) => setLines((prev) => prev.filter((_line, at) => at !== index))}\n onEdit={(index) => {\n const line = lines[index]\n const product = line\n ? (productCache.current.get(line.productId) ?? productsById.get(line.productId))\n : undefined\n if (!line || !product) return\n setItemSheet({\n product,\n editIndex: index,\n initial: {\n ...(line.variantId ? { variantId: line.variantId } : {}),\n ...(line.modifiers ? { modifiers: line.modifiers } : {}),\n quantity: line.quantity,\n },\n })\n }}\n discountPct={discountPct}\n onDiscountPct={setDiscountPct}\n customer={\n sale ? null : <PosCustomerLookup hostId={hostId} value={customer} onChange={setCustomer} />\n }\n locked={Boolean(sale)}\n />\n {sale && user ? (\n sale.status === 'paid' ? (\n <PosReceiptPanel\n user={user}\n hostId={hostId}\n sale={sale}\n context={context}\n display={display}\n onNewSale={resetSale}\n registerId={registerId}\n {...(registerName ? { registerName } : {})}\n {...(cashier.cashier ? { cashierName: cashier.cashier.name } : {})}\n notify={notify}\n />\n ) : (\n <PosTenderPanel\n user={user}\n hostId={hostId}\n registerId={registerId}\n sale={sale}\n context={context}\n stays={openStays}\n display={display}\n onSale={setSale}\n onVoided={() => {\n setSale(null)\n setSaleLines([])\n }}\n onTipChange={setPendingTipCents}\n {...(cashier.assertion ? { cashierAssertion: cashier.assertion } : {})}\n notify={notify}\n />\n )\n ) : (\n <>\n <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>\n <Typography variant=\"h6\">{'Due'}</Typography>\n <Typography variant=\"h6\">{usd(estimateCents)}</Typography>\n </Box>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Tax is added when you charge.'}\n </Typography>\n <Button\n variant=\"contained\"\n size=\"large\"\n disabled={opening || lines.length === 0 || !registerId}\n onClick={() => void charge()}\n sx={{ minHeight: 56 }}\n >\n {opening ? 'Pricing…' : `Charge ${usd(estimateCents)}`}\n </Button>\n {lastReceipt ? (\n <PosLastReceipt\n hostId={hostId}\n orderId={lastReceipt.orderId}\n {...(registerName ? { registerName } : {})}\n {...(cashier.cashier ? { cashierName: cashier.cashier.name } : {})}\n />\n ) : null}\n </>\n )}\n </Stack>\n )\n\n return (\n <>\n <NextPageTitle screen={'POS'} />\n <Box\n sx={{\n display: 'flex',\n height: '100dvh',\n overflow: 'hidden',\n }}\n >\n <Box sx={{ flex: 1, p: 2, overflowY: 'auto', pb: wide ? 2 : 12 }}>\n <PosProductGrid\n search={search}\n onSearch={setSearch}\n onSearchEnter={() => void handleSearchEnter()}\n scanAdornment={scanAdornment}\n categories={(categoryDocs ?? []).map((category: any) => ({\n $id: category.$id,\n name: String(category.name ?? 'Category'),\n }))}\n categoryId={categoryId}\n onCategory={setCategoryId}\n notices={gridPlan.notices}\n hostId={hostId}\n products={products}\n basketCounts={basketCounts}\n onTap={(product) => {\n if (sale) return void notify('Finish or void the open sale first', 'info')\n tapProduct(product)\n }}\n />\n </Box>\n {wide ? (\n <Box\n sx={{\n width: { md: 400, lg: 440 },\n borderLeft: 1,\n borderColor: 'divider',\n display: 'flex',\n flexDirection: 'column',\n p: 2,\n overflowY: 'auto',\n }}\n >\n {registerPanel}\n </Box>\n ) : null}\n </Box>\n {!wide ? (\n <>\n <Box\n ref={bottomBarRef}\n sx={{\n position: 'fixed',\n left: 0,\n right: 0,\n bottom: 0,\n p: 1.5,\n bgcolor: 'background.paper',\n borderTop: 1,\n borderColor: 'divider',\n display: 'flex',\n gap: 1,\n alignItems: 'center',\n zIndex: theme.zIndex.appBar,\n }}\n >\n <Badge badgeContent={units} color=\"primary\">\n <Button\n variant=\"outlined\"\n onClick={() => setSheetOpen(true)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {sale ? 'Payment' : 'Cart'}\n </Button>\n </Badge>\n <Typography variant=\"h6\" sx={{ flex: 1, textAlign: 'right' }}>\n {usd(sale ? sale.dueCents : estimateCents)}\n </Typography>\n {!sale ? (\n <Button\n variant=\"contained\"\n disabled={opening || lines.length === 0 || !registerId}\n onClick={() => void charge()}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {'Charge'}\n </Button>\n ) : null}\n </Box>\n <Drawer\n anchor=\"bottom\"\n open={sheetOpen}\n onClose={() => setSheetOpen(false)}\n slotProps={{ paper: { sx: { maxHeight: '90dvh', p: 2, borderTopLeftRadius: 16, borderTopRightRadius: 16 } } }}\n >\n {registerPanel}\n </Drawer>\n </>\n ) : null}\n <PosItemDialog\n product={itemSheet?.product ?? null}\n initial={itemSheet?.initial}\n onClose={() => setItemSheet(null)}\n onConfirm={(choice) => {\n const sheet = itemSheet\n setItemSheet(null)\n if (!sheet) return\n if (sheet.editIndex === undefined) {\n addProduct(sheet.product, choice.variant, choice.modifiers, choice.quantity)\n return\n }\n const at = sheet.editIndex\n setLines((prev) =>\n prev.map((line, index) => (index === at ? registerLineFor(sheet.product, choice) : line)),\n )\n }}\n {...(itemSheet?.editIndex !== undefined\n ? {\n onRemove: () => {\n const at = itemSheet.editIndex\n setItemSheet(null)\n setLines((prev) => prev.filter((_line, index) => index !== at))\n },\n }\n : {})}\n />\n <Dialog open={Boolean(pairing)} onClose={() => setPairing(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Pair a customer display'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'On the tablet facing your customer, open this address and enter the code. ' +\n 'The code works once and expires in 10 minutes.'}\n </Typography>\n <Typography variant=\"body1\" sx={{ wordBreak: 'break-all' }}>\n {`${typeof window === 'undefined' ? '' : window.location.origin}/kiosk/commerce/pos-display`}\n </Typography>\n <Typography variant=\"h3\" component=\"p\" sx={{ textAlign: 'center', letterSpacing: 8 }}>\n {pairing?.code}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setPairing(null)}>{'Done'}</Button>\n </DialogActions>\n </Dialog>\n </>\n )\n}\nPosConsolePage.displayName = 'PosConsolePage'\n\nexport default PosConsolePage\n"],"names":["Aglyn","CommerceModel","PRODUCT_LIST_BASE","PRODUCT_LIST_QUERY","NextPageTitle","useSnackbar","planListQuery","nameSearchNormalizers","Badge","Box","Button","Dialog","DialogActions","DialogContent","DialogTitle","Drawer","MenuItem","Stack","TextField","Typography","useMediaQuery","useTheme","collection","getDocs","limit","query","where","useCallback","useEffect","useMemo","useRef","useState","useFirestore","useUser","useFirestoreCollection","listQueryConstraints","useOrgPlan","newAttemptKey","openPosSale","posRegisterContext","PosRequestError","usd","PosCartPanel","ScanAdornment","useScannerWedge","PosCustomerLookup","PosLastReceipt","PosOperationsBar","usePosCashier","usePosOpsSettings","POS_QUICK_KEYS","POS_TOUCH_PX","PosProductGrid","PosItemDialog","posItemNeedsChoice","PosReceiptPanel","PosTenderPanel","posDisplayTipCents","usePosDisplay","SELLABLE","field","op","value","POS_GRID_CEILING","posProductPlan","options","typed","search","trim","plan","POS_GRID_QUERY","base","clauses","code","categoryId","quickKeys","filters","path","fields","column","kind","tokensPath","operators","POS_CATEGORY_KEY","registerLineFor","product","choice","variant","modifiers","quantity","resolved","resolveLineModifiers","picked","ok","label","lineLabelWithModifiers","Object","keys","length","values","join","undefined","productId","$id","id","variantId","name","variantLabel","unitAmountCents","Math","round","Number","priceUsd","extraCents","lineKey","line","modifierSelectionKey","PosConsolePage","hostId","usableRegisters","firestore","data","user","enqueueSnackbar","theme","wide","breakpoints","up","setSearch","setCategoryIdState","window","localStorage","getItem","setCategoryId","setItem","gridPlan","productDocs","idField","categoryDocs","locationDocs","registerDocs","org","ready","planReady","registers","sort","a","b","String","localeCompare","registerCap","checkHostRegisterQuota","withinCap","registersWithinCap","filter","r","has","reservationDocs","openStays","lines","setLines","discountPct","setDiscountPct","customer","setCustomer","customerEmail","email","locationId","setLocationId","registerId","setRegisterId","first","registerName","find","register","opsSettings","cashier","autoLockMinutes","lastReceipt","setLastReceipt","context","setContext","userRef","current","uid","signedIn","active","then","answer","settings","terminal","catch","sale","setSale","saleLines","setSaleLines","opening","setOpening","sheetOpen","setSheetOpen","pairing","setPairing","display","attemptKey","products","map","liftLegacyProduct","productsById","Map","shortfalls","get","stockShortfall","variants","itemsCents","reduce","sum","discountCents","estimateCents","units","notify","message","persist","allowDuplicate","addProduct","next","prev","existing","min","itemSheet","setItemSheet","productCache","tapProduct","set","productModifierGroups","initial","basketCounts","counts","lookupCode","scanned","needle","toLowerCase","lookup","found","docs","hit","error","console","item","barcode","sku","handleSearchEnter","scanAdornment","onScan","chargeInFlight","charge","opened","assertion","cashierAssertion","orderId","status","totalCents","totals","paidCents","dueCents","tenderableCents","tipCents","payments","resetSale","mirrored","displayShowsBasket","pendingTipCents","setPendingTipCents","connected","asking","some","payment","method","timer","setTimeout","show","mode","cart","amountCents","taxCents","max","clearTimeout","registerPicker","color","onChange","event","target","size","select","disabled","Boolean","bottomBarRef","node","root","document","documentElement","property","publish","style","setProperty","getBoundingClientRect","height","observer","ResizeObserver","observe","disconnect","removeProperty","registerPanel","spacing","sx","minHeight","flex","direction","alignItems","onClick","pairingCode","location","onExchange","returned","phone","onQuantity","index","_line","at","onRemove","onEdit","editIndex","onDiscountPct","locked","onNewSale","cashierName","stays","onSale","onVoided","onTipChange","justifyContent","screen","overflow","p","overflowY","pb","onSearch","onSearchEnter","categories","category","onCategory","notices","onTap","width","md","lg","borderLeft","borderColor","flexDirection","ref","position","left","right","bottom","bgcolor","borderTop","gap","zIndex","appBar","badgeContent","textAlign","anchor","open","onClose","slotProps","paper","maxHeight","borderTopLeftRadius","borderTopRightRadius","onConfirm","sheet","maxWidth","fullWidth","mt","wordBreak","origin","component","letterSpacing","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-page.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport type { ConsolePluginPageProps } from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport {\n PRODUCT_LIST_BASE,\n PRODUCT_LIST_QUERY,\n} from '../../constants/product-list-query'\nimport { NextPageTitle } from '@aglyn/shared-ui-next/contexts/next-page-title-provider'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport type { ListFilterRequest } from '@aglyn/shared-ui-jsx/const/list-filter'\nimport { planListQuery } from '@aglyn/shared-ui-jsx/const/list-query-plan'\nimport { useViewportFill } from '@aglyn/shared-ui-jsx/hooks/use-viewport-fill'\nimport { nameSearchNormalizers } from '@aglyn/aglyn/app-utils/name-search'\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Drawer,\n MenuItem,\n Stack,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@mui/material'\nimport {\n collection,\n getDocs,\n limit,\n query,\n where,\n} from 'firebase/firestore'\nimport { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useFirestore, useUser } from '@aglyn/tenant-feature-instance'\nimport { useFirestoreCollection } from '@aglyn/tenant-feature-instance'\nimport { listQueryConstraints } from '@aglyn/tenant-feature-instance/hooks/use-list-query'\nimport { useOrgPlan } from '@aglyn/tenant-feature-instance'\nimport {\n newAttemptKey,\n openPosSale,\n posRegisterContext,\n posTender,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n} from './pos/pos-api'\nimport { PosCartPanel, type RegisterLine } from './pos/pos-cart-panel.component'\nimport { ScanAdornment } from '../../barcode/scan-button.component'\nimport { useScannerWedge } from '../../barcode/scanner-wedge'\nimport {\n PosCustomerLookup,\n PosLastReceipt,\n PosOperationsBar,\n usePosCashier,\n usePosOpsSettings,\n type PosSelectedCustomer,\n} from './pos-ops/register-ops'\nimport { POS_QUICK_KEYS, POS_TOUCH_PX, PosProductGrid } from './pos/pos-product-grid.component'\nimport { PosItemDialog, posItemNeedsChoice, type PosItemChoice } from './pos/pos-item-dialog.component'\nimport { PosReceiptPanel } from './pos/pos-receipt-panel.component'\nimport { PosTenderPanel } from './pos/pos-tender-panel.component'\nimport { PosKioskQueue } from './pos/pos-kiosk-queue.component'\nimport { posDisplayTipCents, usePosDisplay } from './pos/use-pos-display'\nimport {\n type ConsoleWidgetSlotRenderer,\n useConsoleWidgetSlot,\n} from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport { POS_ORDERS_ZONE } from './pos-zones'\nimport { PosOfflineBanner, PosOfflineCheckout, usePosOffline } from './pos-offline/register-offline'\n\n/** The till sells active products only; every read of the catalog asks it. */\nconst SELLABLE: ListFilterRequest = { field: 'status', op: 'equals', value: 'active' }\n\n/**\n * How many products the till's grid shows. The grid is a picker, not the\n * catalog: typing narrows it on the query, so a name reaches every product.\n */\nconst POS_GRID_CEILING = 500\n\n/**\n * The products hub's query (AGL-3321), narrowed to what the till may sell:\n * live products (`deletedAt == null`, the list's scope), `status == active`,\n * and any typed word as the search on `nameTokens` — or, for a scan, the\n * whole scanned code as a SKU or barcode clause. Every shape is one the hub's\n * composites already serve.\n */\nexport function posProductPlan(options: {\n search?: string\n code?: { field: 'barcodes' | 'skus'; value: string }\n /** A category chip (AGL-3607): served by the storefront's own composite. */\n categoryId?: string\n /** The Quick keys chip (AGL-3607): products marked `posQuickKey`. */\n quickKeys?: boolean\n}) {\n const typed = options.search?.trim()\n const plan = planListQuery(\n POS_GRID_QUERY,\n {\n base: PRODUCT_LIST_BASE,\n clauses: [\n SELLABLE,\n ...(options.code\n ? [{ field: options.code.field, op: 'contains', value: options.code.value }]\n : []),\n ...(options.categoryId\n ? [{ field: 'categoryIds', op: 'contains', value: options.categoryId }]\n : []),\n ],\n // A chip and a typed word are both array clauses, and Firestore takes\n // one: with a chip on, the word narrows by name prefix instead.\n search: typed && !options.categoryId ? [typed] : [],\n },\n nameSearchNormalizers,\n )\n // The Quick keys chip (AGL-3607) is a boolean equality the list planner\n // does not model, added beside the scope and status it composes with —\n // `deletedAt ==, status ==, posQuickKey ==, nameLower ASC` is declared in\n // the index file. A typed word searches the whole catalog instead: a\n // cashier who types is looking past the quick keys.\n if (options.quickKeys && !typed && !options.code) {\n return {\n ...plan,\n filters: [...plan.filters, { path: 'posQuickKey', op: '==', value: true }],\n } as typeof plan\n }\n return plan\n}\n\n/**\n * The grid's query: the products hub's, plus the category a chip picks\n * (AGL-3607). `categoryIds CONTAINS, nameLower ASC` is a composite the\n * storefront catalog already declares.\n */\nexport const POS_GRID_QUERY = {\n ...PRODUCT_LIST_QUERY,\n fields: [\n ...PRODUCT_LIST_QUERY.fields,\n {\n column: 'categoryIds',\n kind: 'exact' as const,\n path: 'categoryIds',\n tokensPath: 'categoryIds',\n operators: ['contains'],\n },\n ],\n} as typeof PRODUCT_LIST_QUERY\n\n/**\n * POS register (AGL-312, AGL-3607): a tablet-first sale surface — the\n * product grid with search, scan and category chips, the basket, and a\n * tender panel that takes one or more payments against an open sale (cash,\n * card reader, a native Tap to Pay bridge, a typed card, the QR link, gift\n * cards and room charges) until the balance is zero. A paired customer\n * display mirrors the basket and takes the tip and the receipt (AGL-3608).\n *\n * On a wide screen (900px and up) the grid and the register sit side by\n * side; below that the register is a bottom sheet behind a sticky total bar.\n */\n/*\n * `managePos` is NOT read here. The nav item in `plugin.ts` declares it and\n * the shell refuses the route before this component is constructed, so a\n * reader without the key never reaches this file and there is no unpermitted\n * state for it to render — the same arrangement the entitlement gate has.\n *\n * Re-adding a check off the `permissions` prop would be a second answer to a\n * settled question, and a laxer one: a prop absent because the map has not\n * landed reads as permitted here, while the shell holds the route on that\n * same condition rather than guessing. The server routes remain the\n * enforcement point for every sale and every payment.\n */\n/** Where a register device remembers the category chip it was left on. */\nconst POS_CATEGORY_KEY = 'aglyn.pos.category'\n\n/** The basket line an item-sheet choice makes: label and estimate from the product. */\nexport function registerLineFor(\n product: any,\n choice: PosItemChoice,\n): RegisterLine {\n const { variant, modifiers, quantity } = choice\n const resolved = CommerceModel.resolveLineModifiers(product, modifiers)\n const picked = resolved.ok ? resolved.modifiers : []\n const label = CommerceModel.lineLabelWithModifiers(\n Object.keys(variant.options ?? {}).length\n ? Object.values(variant.options ?? {}).join(' / ')\n : undefined,\n picked,\n )\n return {\n productId: product.$id,\n ...(variant.id !== 'default' ? { variantId: variant.id } : {}),\n name: product.name,\n ...(label ? { variantLabel: label } : {}),\n unitAmountCents:\n Math.round(Number(variant.priceUsd) * 100) + (resolved.ok ? resolved.extraCents : 0),\n quantity,\n ...(modifiers.length ? { modifiers } : {}),\n }\n}\n\n/** Same product, variant and choices: the lines that merge into one. */\nfunction lineKey(line: Pick<RegisterLine, 'productId' | 'variantId' | 'modifiers'>): string {\n return `${line.productId}:${line.variantId ?? ''}:${CommerceModel.modifierSelectionKey(line.modifiers)}`\n}\n\n/**\n * The register's zone (AGL-3644), drawn again only when what it is handed\n * changes: the till redraws on every tap, and the shell's renderer is not\n * memoized (the order dialog's reasoning).\n */\nconst PosOrdersZone = memo(function PosOrdersZone(props: {\n renderer: ConsoleWidgetSlotRenderer\n hostId: string\n registerId: string | null\n}) {\n const { renderer: Renderer, hostId, registerId } = props\n return <Renderer slot={POS_ORDERS_ZONE.id} hostId={hostId} orgId={undefined} registerId={registerId} />\n})\n\nexport function PosConsolePage({ hostId }: ConsolePluginPageProps) {\n const WidgetSlot = useConsoleWidgetSlot()\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const theme = useTheme()\n const wide = useMediaQuery(theme.breakpoints.up('md'))\n\n const [search, setSearch] = useState('')\n // The chip a register opens on is remembered per device: a counter that\n // rings from its quick keys reopens on them.\n const [categoryId, setCategoryIdState] = useState(() => {\n try {\n return window.localStorage.getItem(POS_CATEGORY_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const setCategoryId = useCallback((id: string) => {\n setCategoryIdState(id)\n try {\n window.localStorage.setItem(POS_CATEGORY_KEY, id)\n } catch {\n // Storage blocked: the chip still works for this visit.\n }\n }, [])\n const gridPlan = useMemo(\n () =>\n categoryId === POS_QUICK_KEYS\n ? posProductPlan({ search, quickKeys: true })\n : posProductPlan({ search, categoryId }),\n [search, categoryId],\n )\n const { data: productDocs } = useFirestoreCollection<any>(\n /*\n * The till's grid, narrowed by the QUERY rather than by the rows it\n * happened to fetch (AGL-2501, AGL-2292, AGL-3321): the first five\n * hundred SELLABLE products by name, and a typed name reaches the whole\n * catalog. The scan does not come through here — see `handleSearchEnter`.\n */\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'products'),\n ...listQueryConstraints(gridPlan),\n limit(POS_GRID_CEILING),\n ),\n [firestore, hostId, gridPlan],\n { idField: '$id' },\n )\n const { data: categoryDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'productCategories'), limit(30)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { data: locationDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'locations'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { org, ready: planReady } = useOrgPlan(hostId)\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n // Only registers within the plan cap can transact (AGL-482), and not until\n // the org doc has arrived (AGL-1064). Per SITE (AGL-1775).\n const registerCap = Aglyn.checkHostRegisterQuota(org, hostId, registers.length).limit\n const withinCap = CommerceModel.registersWithinCap(registers, registerCap)\n const usableRegisters = planReady ? registers.filter((r: any) => withinCap.has(r.$id)) : []\n /*\n * The stays a sale can be charged to, asked for BY STATUS (AGL-3321).\n */\n const { data: reservationDocs } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('status', '==', 'checked_in'),\n limit(100),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const openStays = reservationDocs ?? []\n\n const [lines, setLines] = useState<RegisterLine[]>([])\n const [discountPct, setDiscountPct] = useState(0)\n // The customer the lookup attached (AGL-3609); their email is the sale's.\n const [customer, setCustomer] = useState<PosSelectedCustomer | null>(null)\n const customerEmail = customer?.email ?? ''\n const [locationId, setLocationId] = useState('')\n const [registerId, setRegisterId] = useState('')\n useEffect(() => {\n if (registerId || usableRegisters.length === 0) return\n const first = usableRegisters[0]\n setRegisterId(first.$id)\n if (first.locationId) setLocationId(first.locationId)\n }, [usableRegisters, registerId])\n const registerName = String(\n usableRegisters.find((register: any) => register.$id === registerId)?.name ?? '',\n )\n // Who is ringing (AGL-3609): a PIN-switched cashier, and the idle lock.\n const opsSettings = usePosOpsSettings(hostId)\n const cashier = usePosCashier({\n hostId,\n registerId,\n autoLockMinutes: opsSettings.autoLockMinutes,\n })\n // The last completed sale, whose receipt can still be printed (AGL-3609).\n const [lastReceipt, setLastReceipt] = useState<{ orderId: string } | null>(null)\n\n const [context, setContext] = useState<PosRegisterContext | null>(null)\n // Keyed on the uid, not the user object: a session refresh hands back a\n // new object for the same person, and re-reading the context on every one\n // would re-render the register in a loop.\n const userRef = useRef(user)\n userRef.current = user\n const uid = user?.uid ?? ''\n useEffect(() => {\n const signedIn = userRef.current\n if (!signedIn) return\n let active = true\n posRegisterContext(signedIn, hostId)\n .then((answer) => {\n // Only a whole answer: a register that half-knows its tenders would\n // offer one the server then refuses.\n if (active && answer?.settings && answer?.terminal) setContext(answer)\n })\n .catch(() => undefined)\n return () => {\n active = false\n }\n }, [uid, hostId])\n\n /** The open sale, once the basket has been priced and payment started. */\n const [sale, setSale] = useState<PosSaleSummary | null>(null)\n const [saleLines, setSaleLines] = useState<RegisterLine[]>([])\n const [opening, setOpening] = useState(false)\n const [sheetOpen, setSheetOpen] = useState(false)\n const [pairing, setPairing] = useState<{\n code: string\n expiresAtMs: number\n /** A customer display, or a self-service kiosk (AGL-3623). */\n mode: CommerceModel.PosDeviceMode\n } | null>(null)\n const display = usePosDisplay(user, hostId, registerId)\n\n /**\n * One key per basket (AGL-1691): minted on the first Charge and retired\n * whenever the basket changes, so a retried Charge finds the same sale and\n * ringing the same coffee twice is two sales.\n */\n const attemptKey = useRef('')\n const fill = useViewportFill({ min: 480 })\n useEffect(() => {\n attemptKey.current = ''\n }, [lines, discountPct])\n\n const products = useMemo(\n () =>\n [...(productDocs ?? [])].map((product: any) => ({\n ...CommerceModel.liftLegacyProduct(product),\n $id: product.$id,\n })),\n [productDocs],\n )\n /*\n * THE OFFLINE REGISTER (AGL-3625): the catalog and the site's offline rules\n * kept on this device, the queue of cash sales rung without a connection,\n * and the sync that records them once it returns.\n */\n const loadCatalog = useCallback(\n async () =>\n (\n await getDocs(\n query(\n collection(firestore, 'hosts', hostId, 'products'),\n ...listQueryConstraints(posProductPlan({})),\n limit(POS_GRID_CEILING),\n ),\n )\n ).docs.map((snapshot) => ({ ...(snapshot.data() as Record<string, unknown>), $id: snapshot.id })),\n [firestore, hostId],\n )\n const liveRegister = usableRegisters.find((register: any) => register.$id === registerId)\n const offline = usePosOffline({\n hostId,\n user,\n registerId,\n openShiftId: liveRegister ? (liveRegister.openShiftId ?? null) : undefined,\n locationId,\n ...(cashier.assertion ? { cashierAssertion: cashier.assertion } : {}),\n liveProducts: products,\n loadCatalog,\n })\n const [offlineCheckout, setOfflineCheckout] = useState(false)\n /** Open sales left unpaid when the connection dropped, voided once it returns. */\n const strandedSales = useRef<string[]>([])\n useEffect(() => {\n if (offline.offline || !user || !strandedSales.current.length) return\n const orderIds = strandedSales.current.splice(0)\n for (const orderId of orderIds) {\n void posTender(user, hostId, orderId, 'void').catch(() => undefined)\n }\n }, [offline.offline, user, hostId])\n const sellProducts = useMemo(\n () => (offline.offline && offline.ready ? offline.gridProducts(search, categoryId, POS_QUICK_KEYS) : products),\n [offline, search, categoryId, products],\n )\n const productsById = useMemo(\n () => new Map<string, any>(sellProducts.map((product: any) => [product.$id, product] as const)),\n [sellProducts],\n )\n /** AGL-2357: warns, never blocks. */\n const shortfalls = useMemo(\n () =>\n lines.map((line) => {\n const product: any = productsById.get(line.productId)\n if (!product) return null\n return CommerceModel.stockShortfall(\n product,\n line.variantId ?? product.variants?.[0]?.id,\n line.quantity,\n )\n }),\n [lines, productsById],\n )\n\n const itemsCents = lines.reduce((sum, line) => sum + line.unitAmountCents * line.quantity, 0)\n const discountCents = Math.round((itemsCents * discountPct) / 100)\n const estimateCents = itemsCents - discountCents\n const units = lines.reduce((sum, line) => sum + line.quantity, 0)\n\n const notify = useCallback(\n (message: string, variant: 'success' | 'error' | 'warning' | 'info') => {\n enqueueSnackbar(message, { variant, persist: false, allowDuplicate: true })\n },\n [enqueueSnackbar],\n )\n\n /** A pairing code for a customer display or a self-service kiosk (AGL-3623). */\n const showPairingCode = useCallback(\n async (mode: CommerceModel.PosDeviceMode) => {\n try {\n setPairing({ ...(await display.pairingCode(mode)), mode })\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not make a code', 'error')\n }\n },\n [display, notify],\n )\n\n /**\n * Adds a line, or more of an identical one: the same product, variant and\n * modifiers merge, so two oat lattes are one line of two and an oat latte\n * beside a whole-milk one stays two lines.\n */\n const addProduct = useCallback(\n (product: any, variant?: any, modifiers: CommerceModel.ModifierSelection[] = [], quantity = 1) => {\n const next = registerLineFor(product, {\n variant: variant ?? product.variants[0],\n modifiers,\n quantity,\n })\n setLines((prev) => {\n const existing = prev.find((line) => lineKey(line) === lineKey(next))\n if (existing) {\n return prev.map((line) =>\n line === existing\n ? { ...line, quantity: Math.min(99, line.quantity + next.quantity) }\n : line,\n )\n }\n return [...prev, next]\n })\n },\n [],\n )\n\n /** The item sheet: a product to add, or a basket line to change. */\n const [itemSheet, setItemSheet] = useState<{\n product: any\n editIndex?: number\n initial?: { variantId?: string; modifiers?: CommerceModel.ModifierSelection[]; quantity: number }\n } | null>(null)\n // Every product rung up this sale, so a line can be reopened after the\n // grid has moved on to another category or search.\n const productCache = useRef(new Map<string, any>())\n const tapProduct = useCallback(\n (product: any, variant?: any) => {\n productCache.current.set(product.$id, product)\n if (posItemNeedsChoice(product) && !(variant && CommerceModel.productModifierGroups(product).length === 0)) {\n setItemSheet({\n product,\n ...(variant ? { initial: { variantId: variant.id, quantity: 1 } } : {}),\n })\n return\n }\n addProduct(product, variant)\n },\n [addProduct],\n )\n const basketCounts = useMemo(() => {\n const counts = new Map<string, number>()\n for (const line of lines) counts.set(line.productId, (counts.get(line.productId) ?? 0) + line.quantity)\n return counts\n }, [lines])\n\n /**\n * The barcode wedge: a LOOKUP against the whole catalog (AGL-2501),\n * barcode first, and a miss says so.\n */\n const lookupCode = useCallback(async (scanned: string) => {\n const needle = scanned.trim().toLowerCase()\n if (!needle || sale) return\n if (offline.offline) {\n const found = offline.findByCode(needle)\n if (!found) return void notify(`No product matches “${scanned.trim()}”`, 'warning')\n tapProduct(found.product, found.variant)\n setSearch('')\n return\n }\n const lookup = async (field: 'barcodes' | 'skus') => {\n const found = await getDocs(\n query(\n collection(firestore, 'hosts', hostId, 'products'),\n ...listQueryConstraints(posProductPlan({ code: { field, value: needle } })),\n limit(1),\n ),\n )\n return found.docs[0]\n }\n let hit: Awaited<ReturnType<typeof lookup>>\n try {\n hit = (await lookup('barcodes')) ?? (await lookup('skus'))\n } catch (error) {\n console.error(error)\n offline.reportNetworkFailure()\n return void notify('Could not reach the catalog — try again', 'warning')\n }\n if (!hit) return void notify(`No product matches “${scanned.trim()}”`, 'warning')\n const product = { ...CommerceModel.liftLegacyProduct(hit.data() as any), $id: hit.id }\n const variant =\n product.variants.find(\n (item: any) =>\n item.barcode?.trim().toLowerCase() === needle || item.sku?.trim().toLowerCase() === needle,\n ) ?? product.variants[0]\n // A scanned variant is the variant; a product with modifiers still asks\n // for them, with that variant already picked.\n tapProduct(product, variant)\n setSearch('')\n }, [sale, firestore, hostId, tapProduct, notify, offline])\n const handleSearchEnter = useCallback(() => lookupCode(search), [lookupCode, search])\n // A scanner fired while focus is on a product or a button (AGL-3619), and\n // the camera; neither while a sale is taking payment or an item is open.\n useScannerWedge((code) => void lookupCode(code), !sale && !itemSheet)\n const scanAdornment = useMemo(\n () => <ScanAdornment label=\"Scan a barcode with the camera\" onScan={(code) => void lookupCode(code)} />,\n [lookupCode],\n )\n\n /** Prices the basket on the server and opens the sale for payment. */\n // A ref, not `opening`: two taps inside one React batch both read the\n // pre-click state, and only a ref is written before the second reads it\n // (the AGL-1682 lesson).\n const chargeInFlight = useRef(false)\n const charge = useCallback(async () => {\n if (chargeInFlight.current || lines.length === 0 || !user) return\n if (!registerId) return void notify('Select a register before taking payment', 'warning')\n // Offline, the basket rings as a cash sale kept on this register (AGL-3625).\n if (offline.offline) {\n if (!offline.ready) return void notify(offline.unavailableReason ?? 'Offline selling is unavailable', 'warning')\n setOfflineCheckout(true)\n return\n }\n if (!attemptKey.current) attemptKey.current = newAttemptKey()\n chargeInFlight.current = true\n setOpening(true)\n try {\n const opened = await openPosSale(user, attemptKey.current, {\n hostId,\n registerId,\n lines,\n discountPct,\n ...(customerEmail ? { customerEmail } : {}),\n ...(customer ? { customer } : {}),\n ...(cashier.assertion ? { cashierAssertion: cashier.assertion } : {}),\n ...(locationId ? { locationId } : {}),\n })\n setSaleLines(lines)\n setSale({\n orderId: opened.orderId,\n status: 'pending',\n totalCents: opened.totals.totalCents,\n paidCents: 0,\n dueCents: opened.totals.totalCents,\n tenderableCents: opened.totals.totalCents,\n tipCents: 0,\n payments: [],\n })\n setSheetOpen(true)\n } catch (error) {\n if (error instanceof PosRequestError) {\n notify(error.message, 'error')\n } else {\n // The request never reached the server: the register is offline.\n offline.reportNetworkFailure()\n notify('The register lost its connection. Charge again to take cash offline.', 'warning')\n }\n } finally {\n chargeInFlight.current = false\n setOpening(false)\n }\n }, [lines, user, registerId, hostId, discountPct, customerEmail, customer, cashier.assertion, locationId, notify, offline])\n\n const resetSale = useCallback(() => {\n if (sale?.status === 'paid') setLastReceipt({ orderId: sale.orderId })\n setSale(null)\n setSaleLines([])\n setLines([])\n setDiscountPct(0)\n setCustomer(null)\n setSheetOpen(false)\n }, [sale])\n\n // The customer display mirrors the basket while nothing else is on it.\n const mirrored = sale ? saleLines : lines\n // Whether the display was last left showing a basket. A paid sale leaves it\n // on the thank-you the server wrote, which an empty new basket must not\n // cut short with the idle screen; the next item added takes it over.\n // True at first, so a register that opens empty clears whatever a previous\n // session left on the screen.\n const displayShowsBasket = useRef(true)\n // The tip picked for the payment about to be taken; the ledger has it only\n // once that payment is recorded. Gone with the sale.\n const [pendingTipCents, setPendingTipCents] = useState(0)\n useEffect(() => {\n if (!sale || sale.status === 'paid') setPendingTipCents(0)\n }, [sale])\n useEffect(() => {\n if (sale?.status === 'paid') displayShowsBasket.current = false\n }, [sale?.status])\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (sale?.payments.some((payment) => payment.status === 'pending' && payment.method === 'card_present')) {\n return\n }\n if (sale?.status === 'paid') return\n if (!mirrored.length && !displayShowsBasket.current) return\n const timer = setTimeout(() => {\n displayShowsBasket.current = mirrored.length > 0\n void display.show(\n mirrored.length\n ? {\n mode: 'cart',\n cart: {\n lines: mirrored.map((line) => ({\n name: line.name,\n ...(line.variantLabel ? { variantLabel: line.variantLabel } : {}),\n quantity: line.quantity,\n amountCents: line.unitAmountCents * line.quantity,\n })),\n itemsCents,\n discountCents,\n taxCents: sale ? Math.max(0, sale.totalCents - estimateCents) : 0,\n totalCents: sale ? sale.totalCents : estimateCents,\n ...(sale\n ? {\n paidCents: sale.paidCents,\n dueCents: sale.dueCents,\n tipCents: posDisplayTipCents(sale, pendingTipCents),\n }\n : {}),\n },\n }\n : { mode: 'idle' },\n )\n }, 400)\n return () => clearTimeout(timer)\n }, [display, mirrored, sale, itemsCents, discountCents, estimateCents, pendingTipCents])\n\n const registerPicker = !planReady ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Checking your plan…'}\n </Typography>\n ) : usableRegisters.length === 0 ? (\n <Typography variant=\"body2\" color=\"warning.main\">\n {registers.length > 0\n ? 'Your registers exceed your plan — remove extras or upgrade in Billing to take payments.'\n : 'No POS register yet. Add one under Commerce → Settings → POS registers before taking payments.'}\n </Typography>\n ) : usableRegisters.length > 1 ? (\n <TextField\n label=\"Register\"\n value={registerId}\n onChange={(event) => setRegisterId(event.target.value)}\n size=\"small\"\n select\n disabled={Boolean(sale)}\n >\n {usableRegisters.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {usableRegisters[0]?.name}\n </Typography>\n )\n\n /**\n * On a narrow screen the register's bar owns the bottom edge, so it moves\n * the console's floating launchers clear of itself through the shell's\n * `--aglyn-dock-inset-bottom` seam; a launcher left in the corner sat on\n * top of Charge.\n */\n const bottomBarRef = useRef<HTMLDivElement | null>(null)\n useEffect(() => {\n const node = bottomBarRef.current\n if (wide || !node) return undefined\n const root = document.documentElement\n const property = '--aglyn-dock-inset-bottom'\n const publish = () => {\n root.style.setProperty(property, `${Math.round(node.getBoundingClientRect().height) + 20}px`)\n }\n publish()\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(publish)\n observer?.observe(node)\n return () => {\n observer?.disconnect()\n root.style.removeProperty(property)\n }\n }, [wide])\n\n const registerPanel = (\n <Stack spacing={1.5} sx={{ minHeight: 0, flex: 1 }}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"h6\" sx={{ flex: 1 }}>\n {'Register'}\n </Typography>\n {registerId ? (\n <Button\n size=\"small\"\n onClick={() => void showPairingCode('display')}\n >\n {display.connected ? 'Display connected' : 'Pair display'}\n </Button>\n ) : null}\n </Stack>\n {registerPicker}\n {(locationDocs?.length ?? 0) > 1 ? (\n <TextField\n label=\"Location\"\n value={locationId}\n onChange={(event) => setLocationId(event.target.value)}\n size=\"small\"\n select\n disabled={Boolean(sale)}\n >\n {(locationDocs ?? []).map((location: any) => (\n <MenuItem key={location.$id} value={location.$id}>\n {location.name}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {registerId ? (\n <PosOperationsBar\n hostId={hostId}\n registerId={registerId}\n {...(registerName ? { registerName } : {})}\n cashier={cashier}\n onExchange={(returned) =>\n setCustomer(\n returned.email || returned.name\n ? { kind: 'none', id: '', name: returned.name ?? '', email: returned.email, phone: null }\n : null,\n )\n }\n />\n ) : null}\n <PosCartPanel\n lines={sale ? saleLines : lines}\n shortfalls={sale ? [] : shortfalls}\n onQuantity={(index, quantity) =>\n setLines((prev) =>\n quantity <= 0\n ? prev.filter((_line, at) => at !== index)\n : prev.map((line, at) => (at === index ? { ...line, quantity: Math.min(99, quantity) } : line)),\n )\n }\n onRemove={(index) => setLines((prev) => prev.filter((_line, at) => at !== index))}\n onEdit={(index) => {\n const line = lines[index]\n const product = line\n ? (productCache.current.get(line.productId) ?? productsById.get(line.productId))\n : undefined\n if (!line || !product) return\n setItemSheet({\n product,\n editIndex: index,\n initial: {\n ...(line.variantId ? { variantId: line.variantId } : {}),\n ...(line.modifiers ? { modifiers: line.modifiers } : {}),\n quantity: line.quantity,\n },\n })\n }}\n discountPct={discountPct}\n onDiscountPct={setDiscountPct}\n customer={\n sale ? null : <PosCustomerLookup hostId={hostId} value={customer} onChange={setCustomer} />\n }\n locked={Boolean(sale)}\n />\n {sale && user ? (\n sale.status === 'paid' ? (\n <PosReceiptPanel\n user={user}\n hostId={hostId}\n sale={sale}\n context={context}\n display={display}\n onNewSale={resetSale}\n registerId={registerId}\n {...(registerName ? { registerName } : {})}\n {...(cashier.cashier ? { cashierName: cashier.cashier.name } : {})}\n notify={notify}\n />\n ) : (\n <PosTenderPanel\n user={user}\n hostId={hostId}\n registerId={registerId}\n sale={sale}\n context={context}\n stays={openStays}\n display={display}\n onSale={setSale}\n onVoided={() => {\n setSale(null)\n setSaleLines([])\n }}\n onTipChange={setPendingTipCents}\n {...(cashier.assertion ? { cashierAssertion: cashier.assertion } : {})}\n notify={notify}\n offline={offline.offline}\n {...(offline.ready\n ? {\n onSellOffline: () => {\n // The server's open sale took no payment; it is voided once\n // the connection returns, and the basket rings offline.\n strandedSales.current.push(sale.orderId)\n setSale(null)\n setSaleLines([])\n setOfflineCheckout(true)\n },\n }\n : {})}\n />\n )\n ) : (\n <>\n <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>\n <Typography variant=\"h6\">{'Due'}</Typography>\n <Typography variant=\"h6\">{usd(estimateCents)}</Typography>\n </Box>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Tax is added when you charge.'}\n </Typography>\n <Button\n variant=\"contained\"\n size=\"large\"\n disabled={opening || lines.length === 0 || !registerId}\n onClick={() => void charge()}\n sx={{ minHeight: 56 }}\n >\n {opening\n ? 'Pricing…'\n : offline.offline\n ? `Cash ${usd(offline.totalsFor(lines, discountPct)?.totalCents ?? estimateCents)} (offline)`\n : `Charge ${usd(estimateCents)}`}\n </Button>\n {lastReceipt ? (\n <PosLastReceipt\n hostId={hostId}\n orderId={lastReceipt.orderId}\n {...(registerName ? { registerName } : {})}\n {...(cashier.cashier ? { cashierName: cashier.cashier.name } : {})}\n />\n ) : null}\n </>\n )}\n </Stack>\n )\n\n return (\n <>\n <NextPageTitle screen={'POS'} />\n <Box\n ref={fill.ref}\n sx={{\n display: 'flex',\n // From under the console's header, nav and page title to the\n // bottom of the window, not a whole window tall below them.\n height: fill.height,\n overflow: 'hidden',\n }}\n >\n <Box sx={{ flex: 1, p: 2, overflowY: 'auto', pb: wide ? 2 : 12 }}>\n <Box sx={{ mb: 2, '&:empty': { display: 'none' } }}>\n <PosOfflineBanner offline={offline} />\n </Box>\n {/* \"Pay at counter\" orders from this register's kiosks (AGL-3623). */}\n {registerId ? (\n <PosKioskQueue\n user={user}\n hostId={hostId}\n registerId={registerId}\n disabled={Boolean(sale)}\n onTake={(next, nextLines) => {\n setSaleLines(nextLines)\n setSale(next)\n setSheetOpen(true)\n }}\n notify={notify}\n />\n ) : null}\n {/* Orders other channels send to the counter (AGL-3644). */}\n {WidgetSlot ? <PosOrdersZone renderer={WidgetSlot} hostId={hostId} registerId={registerId || null} /> : null}\n <PosProductGrid\n search={search}\n onSearch={setSearch}\n onSearchEnter={() => void handleSearchEnter()}\n scanAdornment={scanAdornment}\n categories={(categoryDocs ?? []).map((category: any) => ({\n $id: category.$id,\n name: String(category.name ?? 'Category'),\n }))}\n categoryId={categoryId}\n onCategory={setCategoryId}\n notices={gridPlan.notices}\n hostId={hostId}\n products={sellProducts}\n basketCounts={basketCounts}\n onTap={(product) => {\n if (sale) return void notify('Finish or void the open sale first', 'info')\n tapProduct(product)\n }}\n />\n </Box>\n {wide ? (\n <Box\n sx={{\n width: { md: 400, lg: 440 },\n borderLeft: 1,\n borderColor: 'divider',\n display: 'flex',\n flexDirection: 'column',\n p: 2,\n overflowY: 'auto',\n }}\n >\n {registerPanel}\n </Box>\n ) : null}\n </Box>\n {!wide ? (\n <>\n <Box\n ref={bottomBarRef}\n sx={{\n position: 'fixed',\n left: 0,\n right: 0,\n bottom: 0,\n p: 1.5,\n bgcolor: 'background.paper',\n borderTop: 1,\n borderColor: 'divider',\n display: 'flex',\n gap: 1,\n alignItems: 'center',\n zIndex: theme.zIndex.appBar,\n }}\n >\n <Badge badgeContent={units} color=\"primary\">\n <Button\n variant=\"outlined\"\n onClick={() => setSheetOpen(true)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {sale ? 'Payment' : 'Cart'}\n </Button>\n </Badge>\n <Typography variant=\"h6\" sx={{ flex: 1, textAlign: 'right' }}>\n {usd(sale ? sale.dueCents : estimateCents)}\n </Typography>\n {!sale ? (\n <Button\n variant=\"contained\"\n disabled={opening || lines.length === 0 || !registerId}\n onClick={() => void charge()}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {'Charge'}\n </Button>\n ) : null}\n </Box>\n <Drawer\n anchor=\"bottom\"\n open={sheetOpen}\n onClose={() => setSheetOpen(false)}\n slotProps={{ paper: { sx: { maxHeight: '90dvh', p: 2, borderTopLeftRadius: 16, borderTopRightRadius: 16 } } }}\n >\n {registerPanel}\n </Drawer>\n </>\n ) : null}\n <PosItemDialog\n product={itemSheet?.product ?? null}\n initial={itemSheet?.initial}\n onClose={() => setItemSheet(null)}\n onConfirm={(choice) => {\n const sheet = itemSheet\n setItemSheet(null)\n if (!sheet) return\n if (sheet.editIndex === undefined) {\n addProduct(sheet.product, choice.variant, choice.modifiers, choice.quantity)\n return\n }\n const at = sheet.editIndex\n setLines((prev) =>\n prev.map((line, index) => (index === at ? registerLineFor(sheet.product, choice) : line)),\n )\n }}\n {...(itemSheet?.editIndex !== undefined\n ? {\n onRemove: () => {\n const at = itemSheet.editIndex\n setItemSheet(null)\n setLines((prev) => prev.filter((_line, index) => index !== at))\n },\n }\n : {})}\n />\n <PosOfflineCheckout\n open={offlineCheckout}\n offline={offline}\n hostId={hostId}\n lines={lines}\n discountPct={discountPct}\n customer={customer}\n {...(registerName ? { registerName } : {})}\n {...(cashier.cashier ? { cashierName: cashier.cashier.name } : {})}\n onClose={() => setOfflineCheckout(false)}\n onRung={() => undefined}\n onDone={() => {\n setOfflineCheckout(false)\n setLines([])\n setDiscountPct(0)\n setCustomer(null)\n setSheetOpen(false)\n }}\n />\n <Dialog open={Boolean(pairing)} onClose={() => setPairing(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{pairing?.mode === 'kiosk' ? 'Pair a self-service kiosk' : 'Pair a customer display'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <ToggleButtonGroup\n exclusive\n fullWidth\n size=\"small\"\n value={pairing?.mode ?? 'display'}\n onChange={(_event, mode: CommerceModel.PosDeviceMode | null) => {\n if (mode && mode !== pairing?.mode) void showPairingCode(mode)\n }}\n sx={{ mt: 1 }}\n >\n <ToggleButton value=\"display\">{'Customer display'}</ToggleButton>\n <ToggleButton value=\"kiosk\">{'Self-service kiosk'}</ToggleButton>\n </ToggleButtonGroup>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {(pairing?.mode === 'kiosk'\n ? 'On the tablet customers order from, open this address and enter the code. '\n : 'On the tablet facing your customer, open this address and enter the code. ') +\n 'The code works once and expires in 10 minutes.'}\n </Typography>\n <Typography variant=\"body1\" sx={{ wordBreak: 'break-all' }}>\n {`${typeof window === 'undefined' ? '' : window.location.origin}/kiosk/commerce/${\n pairing?.mode === 'kiosk' ? 'pos-kiosk' : 'pos-display'\n }`}\n </Typography>\n <Typography variant=\"h3\" component=\"p\" sx={{ textAlign: 'center', letterSpacing: 8 }}>\n {pairing?.code}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setPairing(null)}>{'Done'}</Button>\n </DialogActions>\n </Dialog>\n </>\n )\n}\nPosConsolePage.displayName = 'PosConsolePage'\n\nexport default PosConsolePage\n"],"names":["Aglyn","CommerceModel","PRODUCT_LIST_BASE","PRODUCT_LIST_QUERY","NextPageTitle","useSnackbar","planListQuery","useViewportFill","nameSearchNormalizers","Badge","Box","Button","Dialog","DialogActions","DialogContent","DialogTitle","Drawer","MenuItem","Stack","TextField","ToggleButton","ToggleButtonGroup","Typography","useMediaQuery","useTheme","collection","getDocs","limit","query","where","memo","useCallback","useEffect","useMemo","useRef","useState","useFirestore","useUser","useFirestoreCollection","listQueryConstraints","useOrgPlan","newAttemptKey","openPosSale","posRegisterContext","posTender","PosRequestError","usd","PosCartPanel","ScanAdornment","useScannerWedge","PosCustomerLookup","PosLastReceipt","PosOperationsBar","usePosCashier","usePosOpsSettings","POS_QUICK_KEYS","POS_TOUCH_PX","PosProductGrid","PosItemDialog","posItemNeedsChoice","PosReceiptPanel","PosTenderPanel","PosKioskQueue","posDisplayTipCents","usePosDisplay","useConsoleWidgetSlot","POS_ORDERS_ZONE","PosOfflineBanner","PosOfflineCheckout","usePosOffline","SELLABLE","field","op","value","POS_GRID_CEILING","posProductPlan","options","typed","search","trim","plan","POS_GRID_QUERY","base","clauses","code","categoryId","quickKeys","filters","path","fields","column","kind","tokensPath","operators","POS_CATEGORY_KEY","registerLineFor","product","choice","variant","modifiers","quantity","resolved","resolveLineModifiers","picked","ok","label","lineLabelWithModifiers","Object","keys","length","values","join","undefined","productId","$id","id","variantId","name","variantLabel","unitAmountCents","Math","round","Number","priceUsd","extraCents","lineKey","line","modifierSelectionKey","PosOrdersZone","props","renderer","Renderer","hostId","registerId","slot","orgId","PosConsolePage","liveRegister","usableRegisters","offline","WidgetSlot","firestore","data","user","enqueueSnackbar","theme","wide","breakpoints","up","setSearch","setCategoryIdState","window","localStorage","getItem","setCategoryId","setItem","gridPlan","productDocs","idField","categoryDocs","locationDocs","registerDocs","org","ready","planReady","registers","sort","a","b","String","localeCompare","registerCap","checkHostRegisterQuota","withinCap","registersWithinCap","filter","r","has","reservationDocs","openStays","lines","setLines","discountPct","setDiscountPct","customer","setCustomer","customerEmail","email","locationId","setLocationId","setRegisterId","first","registerName","find","register","opsSettings","cashier","autoLockMinutes","lastReceipt","setLastReceipt","context","setContext","userRef","current","uid","signedIn","active","then","answer","settings","terminal","catch","sale","setSale","saleLines","setSaleLines","opening","setOpening","sheetOpen","setSheetOpen","pairing","setPairing","display","attemptKey","fill","min","products","map","liftLegacyProduct","loadCatalog","docs","snapshot","openShiftId","assertion","cashierAssertion","liveProducts","offlineCheckout","setOfflineCheckout","strandedSales","orderIds","splice","orderId","sellProducts","gridProducts","productsById","Map","shortfalls","get","stockShortfall","variants","itemsCents","reduce","sum","discountCents","estimateCents","units","notify","message","persist","allowDuplicate","showPairingCode","mode","pairingCode","error","addProduct","next","prev","existing","itemSheet","setItemSheet","productCache","tapProduct","set","productModifierGroups","initial","basketCounts","counts","lookupCode","scanned","needle","toLowerCase","found","findByCode","lookup","hit","console","reportNetworkFailure","item","barcode","sku","handleSearchEnter","scanAdornment","onScan","chargeInFlight","charge","unavailableReason","opened","status","totalCents","totals","paidCents","dueCents","tenderableCents","tipCents","payments","resetSale","mirrored","displayShowsBasket","pendingTipCents","setPendingTipCents","connected","asking","some","payment","method","timer","setTimeout","show","cart","amountCents","taxCents","max","clearTimeout","registerPicker","color","onChange","event","target","size","select","disabled","Boolean","bottomBarRef","node","root","document","documentElement","property","publish","style","setProperty","getBoundingClientRect","height","observer","ResizeObserver","observe","disconnect","removeProperty","registerPanel","spacing","sx","minHeight","flex","direction","alignItems","onClick","location","onExchange","returned","phone","onQuantity","index","_line","at","onRemove","onEdit","editIndex","onDiscountPct","locked","onNewSale","cashierName","stays","onSale","onVoided","onTipChange","onSellOffline","push","justifyContent","totalsFor","screen","ref","overflow","p","overflowY","pb","mb","onTake","nextLines","onSearch","onSearchEnter","categories","category","onCategory","notices","onTap","width","md","lg","borderLeft","borderColor","flexDirection","position","left","right","bottom","bgcolor","borderTop","gap","zIndex","appBar","badgeContent","textAlign","anchor","open","onClose","slotProps","paper","maxHeight","borderTopLeftRadius","borderTopRightRadius","onConfirm","sheet","onRung","onDone","maxWidth","fullWidth","exclusive","_event","mt","wordBreak","origin","component","letterSpacing","displayName"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The register's zone (AGL-3644): `posOrders`, above the till's product grid,
3
+ * where orders another channel sends to the counter — a delivery app's, say
4
+ * — wait to be accepted, made and handed over.
5
+ *
6
+ * Declared here because zones are declared by the plugin that hosts them. A
7
+ * widget from another plugin restates these props rather than importing
8
+ * this package, and it writes no order of this plugin's itself: what it
9
+ * records goes through core's channel-orders seam, under this plugin's rules.
10
+ * The register's own gate — `managePos` and the `pos` entitlement — stands
11
+ * in front of the page, and a widget's routes ask it again.
12
+ */
13
+ /** What `posOrders` hands a widget. */
14
+ export interface ConsolePosOrdersZoneProps {
15
+ hostId: string;
16
+ /** The org the page names; `undefined` where the host does not know it. */
17
+ orgId: string | undefined;
18
+ /** The register the till is open on, or `null` before one is chosen. */
19
+ registerId: string | null;
20
+ }
21
+ export declare const POS_ORDERS_ZONE: import("@aglyn/aglyn/plugin-manager/plugin-zones").PluginZone<ConsolePosOrdersZoneProps>;
22
+ /** Declares it, from the console registrar. */
23
+ export declare function registerCommercePosZones(): void;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { definePluginZone, registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
17
+ import { BUNDLE_ID } from "../../constants/bundle-common.js";
18
+ export const POS_ORDERS_ZONE = definePluginZone('posOrders');
19
+ /** Declares it, from the console registrar. */ export function registerCommercePosZones() {
20
+ registerPluginZone({
21
+ zone: POS_ORDERS_ZONE,
22
+ label: 'Register orders',
23
+ surface: 'console',
24
+ layout: 'bare',
25
+ description: 'Above the POS register’s product grid. A widget here shows orders another channel sends to the counter, for staff to accept, make and hand over; it records them through its own routes and core’s channel-orders seam, never by writing an order.'
26
+ }, {
27
+ pluginId: BUNDLE_ID
28
+ });
29
+ }
30
+
31
+ //# sourceMappingURL=pos-zones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-zones.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n definePluginZone,\n registerPluginZone,\n} from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport { BUNDLE_ID } from '../../constants/bundle-common'\n\n/**\n * The register's zone (AGL-3644): `posOrders`, above the till's product grid,\n * where orders another channel sends to the counter — a delivery app's, say\n * — wait to be accepted, made and handed over.\n *\n * Declared here because zones are declared by the plugin that hosts them. A\n * widget from another plugin restates these props rather than importing\n * this package, and it writes no order of this plugin's itself: what it\n * records goes through core's channel-orders seam, under this plugin's rules.\n * The register's own gate — `managePos` and the `pos` entitlement — stands\n * in front of the page, and a widget's routes ask it again.\n */\n\n/** What `posOrders` hands a widget. */\nexport interface ConsolePosOrdersZoneProps {\n hostId: string\n /** The org the page names; `undefined` where the host does not know it. */\n orgId: string | undefined\n /** The register the till is open on, or `null` before one is chosen. */\n registerId: string | null\n}\n\nexport const POS_ORDERS_ZONE = definePluginZone<ConsolePosOrdersZoneProps>('posOrders')\n\n/** Declares it, from the console registrar. */\nexport function registerCommercePosZones(): void {\n registerPluginZone(\n {\n zone: POS_ORDERS_ZONE,\n label: 'Register orders',\n surface: 'console',\n layout: 'bare',\n description:\n 'Above the POS register’s product grid. A widget here shows orders another channel sends to the counter, for staff to accept, make and hand over; it records them through its own routes and core’s channel-orders seam, never by writing an order.',\n },\n { pluginId: BUNDLE_ID },\n )\n}\n"],"names":["definePluginZone","registerPluginZone","BUNDLE_ID","POS_ORDERS_ZONE","registerCommercePosZones","zone","label","surface","layout","description","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,SACEA,gBAAgB,EAChBC,kBAAkB,QACb,2CAA0C;AACjD,SAASC,SAAS,QAAQ,mCAA+B;AAwBzD,OAAO,MAAMC,kBAAkBH,iBAA4C,aAAY;AAEvF,6CAA6C,GAC7C,OAAO,SAASI;IACdH,mBACE;QACEI,MAAMF;QACNG,OAAO;QACPC,SAAS;QACTC,QAAQ;QACRC,aACE;IACJ,GACA;QAAEC,UAAUR;IAAU;AAE1B"}
@@ -1427,52 +1427,14 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1427
1427
  update
1428
1428
  ]);
1429
1429
  const handleSave = useCallback(async ()=>{
1430
- var _ref, _ref1, _ref2;
1431
- var _current_mediaUrls;
1432
1430
  if (!current.name.trim() || error) return;
1433
- const primaryVariant = current.variants[0];
1434
- // JSON-safe base (no Firestore Timestamp — it won't survive the API
1435
- // hop); millis fields are what the checkout + Product block read.
1436
- /**
1437
- * `$id` is dropped, not carried (AGL-1374).
1438
- *
1439
- * `current` is `draft ?? liftLegacyProduct(product)`, and the hub stamps
1440
- * `$id` onto every row it lists (`{...liftLegacyProduct(p), $id: p.$id}`)
1441
- * — a SYNTHETIC key `idField: '$id'` puts on the in-memory object, which
1442
- * nothing persists. Spreading `current` carried it into the payload, and
1443
- * this write is `merge: false`, so it was stored as a real field on every
1444
- * product save. Nothing reads it; it is the listener's bookkeeping
1445
- * leaking into storage, and once there no reader can tell it from a field
1446
- * the editor meant to write. Excluding it also CLEANS the key off any
1447
- * product a previous save corrupted, because a replacing write stores
1448
- * exactly the payload.
1449
- *
1450
- * `product.$id` is still the doc path below — reading the synthetic key
1451
- * is what it is for. Writing it is the bug.
1452
- */ const seeded = current;
1453
1431
  /*
1454
- * The seed's `skus` / `barcodes` are dropped too (AGL-3321):
1455
- * `productSearchFields` below OMITS each when no variant has one, so a
1456
- * seeded copy would survive a save that removed the last SKU, and the
1457
- * product would go on answering a SKU filter for a code it no longer has.
1458
- */ const { $id: _syntheticId, skus: _seededSkus, barcodes: _seededBarcodes } = seeded, currentFields = _object_without_properties_loose(seeded, [
1459
- "$id",
1460
- "skus",
1461
- "barcodes"
1462
- ]);
1463
- const base = _extends({}, currentFields, CommerceModel.productSearchFields({
1464
- name: current.name.trim().slice(0, 120),
1465
- variants: current.variants
1466
- }), {
1467
- slug: current.slug || CommerceModel.commerceSlug(current.name),
1468
- priceUsd: (_ref = primaryVariant == null ? void 0 : primaryVariant.priceUsd) != null ? _ref : 0
1469
- }, CommerceModel.productStockFields({
1470
- variants: current.variants,
1471
- oversellPolicy: current.oversellPolicy
1472
- }), {
1473
- imageUrl: (_ref1 = (_ref2 = (_current_mediaUrls = current.mediaUrls) == null ? void 0 : _current_mediaUrls[0]) != null ? _ref2 : current.imageUrl) != null ? _ref1 : null,
1474
- updatedAtMs: Date.now()
1475
- });
1432
+ * The fields the save writes — `$id` and the seed's `skus`/`barcodes`
1433
+ * dropped, the name with its search keys, slug, price, stock fields,
1434
+ * image — are `productSaveFields`, the same code the native apps' save
1435
+ * route runs (AGL-3652). JSON-safe: no Firestore Timestamp, which would
1436
+ * not survive the API hop; millis fields are what checkout reads.
1437
+ */ const base = CommerceModel.productSaveFields(current, Date.now());
1476
1438
  try {
1477
1439
  /**
1478
1440
  * Refuse an EDIT whose seed the server never confirmed (AGL-1358).
@@ -1499,13 +1461,7 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1499
1461
  }, async ()=>{
1500
1462
  // The smart collections this product's rules answer, from the
1501
1463
  // host's rules as they stand now (AGL-3321).
1502
- const membership = await productCollectionFields(firestore, hostId, {
1503
- name: base.name,
1504
- type: current.type,
1505
- tags: current.tags,
1506
- categoryIds: current.categoryIds,
1507
- variants: current.variants
1508
- });
1464
+ const membership = await productCollectionFields(firestore, hostId, CommerceModel.productMembershipInput(base, current));
1509
1465
  if (product) {
1510
1466
  /**
1511
1467
  * RESERVATIONS ARE NOT THE EDITOR'S TO WRITE (AGL-2356).
@@ -1526,9 +1482,6 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1526
1482
  * REST of this payload can be; it cannot help here, because a hold
1527
1483
  * legitimately appears seconds after a perfectly fresh seed.
1528
1484
  */ const productRef = doc(firestore, 'hosts', hostId, 'products', product.$id);
1529
- const { stockHolds: _seededHolds } = base, withoutHolds = _object_without_properties_loose(base, [
1530
- "stockHolds"
1531
- ]);
1532
1485
  const liveHolds = await getDoc(productRef).then((snapshot)=>snapshot.get('stockHolds')).catch(()=>undefined);
1533
1486
  // Edit stays client-direct (no quota consumed); full replace.
1534
1487
  // The product page renders it with no publish step, so the save
@@ -1537,14 +1490,7 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1537
1490
  firestore,
1538
1491
  user,
1539
1492
  hostId,
1540
- write: (batch)=>batch.set(productRef, _extends({}, withoutHolds, membership, liveHolds ? {
1541
- stockHolds: liveHolds
1542
- } : {}, {
1543
- // The editor edits a LIVE product, and the products table
1544
- // lists only `deletedAt == null` (AGL-3321): a replace
1545
- // whose seed lacked the field would take the product off
1546
- // the list.
1547
- deletedAt: null,
1493
+ write: (batch)=>batch.set(productRef, _extends({}, CommerceModel.productEditWrite(base, liveHolds), membership, {
1548
1494
  updatedAt: Timestamp.now()
1549
1495
  }), {
1550
1496
  merge: false
@@ -1576,9 +1522,9 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1576
1522
  persist: false
1577
1523
  });
1578
1524
  } catch (saveError) {
1579
- var _ref3;
1525
+ var _ref;
1580
1526
  console.error(saveError);
1581
- enqueueSnackbar((_ref3 = saveError == null ? void 0 : saveError.message) != null ? _ref3 : 'An error has occurred', {
1527
+ enqueueSnackbar((_ref = saveError == null ? void 0 : saveError.message) != null ? _ref : 'An error has occurred', {
1582
1528
  variant: 'error',
1583
1529
  allowDuplicate: true
1584
1530
  });