@aglyn/plugins-commerce 1.0.0-beta.278 → 1.0.0-beta.283

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 (212) hide show
  1. package/package.json +17 -14
  2. package/src/lib/components/commerce-console-page.js +33 -1
  3. package/src/lib/components/commerce-console-page.js.map +1 -1
  4. package/src/lib/components/console/payments-settings-card.component.js +1 -1
  5. package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
  6. package/src/lib/components/console/pos/pos-hardware-api.d.ts +122 -0
  7. package/src/lib/components/console/pos/pos-hardware-api.js +90 -0
  8. package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -0
  9. package/src/lib/components/console/pos/pos-reader-splash-api.d.ts +58 -0
  10. package/src/lib/components/console/pos/pos-reader-splash-api.js +101 -0
  11. package/src/lib/components/console/pos/pos-reader-splash-api.js.map +1 -0
  12. package/src/lib/components/console/pos-devices-card.component.js +5 -0
  13. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  14. package/src/lib/components/console/pos-hardware-card.component.d.ts +26 -0
  15. package/src/lib/components/console/pos-hardware-card.component.js +456 -0
  16. package/src/lib/components/console/pos-hardware-card.component.js.map +1 -0
  17. package/src/lib/components/console/pos-hardware-orders-staff-page.component.d.ts +14 -0
  18. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +519 -0
  19. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -0
  20. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.d.ts +27 -0
  21. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +444 -0
  22. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -0
  23. package/src/lib/components/console/pos-ops/pos-check-in-zone.component.d.ts +9 -0
  24. package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js +37 -0
  25. package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js.map +1 -0
  26. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +24 -0
  27. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +346 -0
  28. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -0
  29. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +5 -1
  30. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +83 -4
  31. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -1
  32. package/src/lib/components/console/pos-ops/pos-day-totals-card.component.d.ts +35 -0
  33. package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js +546 -0
  34. package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js.map +1 -0
  35. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +2 -1
  36. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +20 -1
  37. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
  38. package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +1 -1
  39. package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -1
  40. package/src/lib/components/console/pos-page.component.js +6 -3
  41. package/src/lib/components/console/pos-page.component.js.map +1 -1
  42. package/src/lib/components/console/pos-reader-splash-setting.component.d.ts +22 -0
  43. package/src/lib/components/console/pos-reader-splash-setting.component.js +275 -0
  44. package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -0
  45. package/src/lib/components/console/pos-reader-splash-staff-page.component.d.ts +14 -0
  46. package/src/lib/components/console/pos-reader-splash-staff-page.component.js +301 -0
  47. package/src/lib/components/console/pos-reader-splash-staff-page.component.js.map +1 -0
  48. package/src/lib/components/console/pos-zones.d.ts +37 -3
  49. package/src/lib/components/console/pos-zones.js +11 -1
  50. package/src/lib/components/console/pos-zones.js.map +1 -1
  51. package/src/lib/components/console/product-check-in-fields.component.d.ts +20 -0
  52. package/src/lib/components/console/product-check-in-fields.component.js +172 -0
  53. package/src/lib/components/console/product-check-in-fields.component.js.map +1 -0
  54. package/src/lib/components/console/product-editor-dialog.component.js +48 -9
  55. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  56. package/src/lib/components/console/product-register-fields.component.d.ts +12 -0
  57. package/src/lib/components/console/product-register-fields.component.js +39 -1
  58. package/src/lib/components/console/product-register-fields.component.js.map +1 -1
  59. package/src/lib/components/console/products-hub-card.component.js +21 -6
  60. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  61. package/src/lib/components/console/reservations-card.component.js +239 -70
  62. package/src/lib/components/console/reservations-card.component.js.map +1 -1
  63. package/src/lib/components/reservation-widget.js +16 -0
  64. package/src/lib/components/reservation-widget.js.map +1 -1
  65. package/src/lib/constants/operator-alerts.d.ts +6 -0
  66. package/src/lib/constants/operator-alerts.js +20 -1
  67. package/src/lib/constants/operator-alerts.js.map +1 -1
  68. package/src/lib/declarations.console-server.js +7 -0
  69. package/src/lib/declarations.console-server.js.map +1 -1
  70. package/src/lib/declarations.d.ts +26 -0
  71. package/src/lib/declarations.js +34 -0
  72. package/src/lib/declarations.js.map +1 -0
  73. package/src/lib/model/commerce-check-in-product.d.ts +37 -0
  74. package/src/lib/model/commerce-check-in-product.js +49 -0
  75. package/src/lib/model/commerce-check-in-product.js.map +1 -0
  76. package/src/lib/model/commerce-check-in.d.ts +187 -0
  77. package/src/lib/model/commerce-check-in.js +468 -0
  78. package/src/lib/model/commerce-check-in.js.map +1 -0
  79. package/src/lib/model/commerce-pos-day-report.d.ts +209 -0
  80. package/src/lib/model/commerce-pos-day-report.js +572 -0
  81. package/src/lib/model/commerce-pos-day-report.js.map +1 -0
  82. package/src/lib/model/commerce-pos-offline.d.ts +65 -3
  83. package/src/lib/model/commerce-pos-offline.js +104 -7
  84. package/src/lib/model/commerce-pos-offline.js.map +1 -1
  85. package/src/lib/model/commerce-pos-ops.d.ts +3 -0
  86. package/src/lib/model/commerce-pos-ops.js +1 -0
  87. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  88. package/src/lib/model/commerce-pos.d.ts +43 -3
  89. package/src/lib/model/commerce-pos.js +73 -5
  90. package/src/lib/model/commerce-pos.js.map +1 -1
  91. package/src/lib/model/commerce-reservations.d.ts +73 -7
  92. package/src/lib/model/commerce-reservations.js +90 -10
  93. package/src/lib/model/commerce-reservations.js.map +1 -1
  94. package/src/lib/model/commerce.d.ts +40 -0
  95. package/src/lib/model/commerce.js +22 -4
  96. package/src/lib/model/commerce.js.map +1 -1
  97. package/src/lib/model/index.d.ts +1 -0
  98. package/src/lib/model/index.js +1 -0
  99. package/src/lib/model/index.js.map +1 -1
  100. package/src/lib/model/plugin-permissions.d.ts +1 -1
  101. package/src/lib/model/plugin-permissions.js +2 -1
  102. package/src/lib/model/plugin-permissions.js.map +1 -1
  103. package/src/lib/model/pos-hardware.d.ts +288 -0
  104. package/src/lib/model/pos-hardware.js +499 -0
  105. package/src/lib/model/pos-hardware.js.map +1 -0
  106. package/src/lib/model/pos-offline-card-limits.d.ts +20 -0
  107. package/src/lib/model/pos-offline-card-limits.js +28 -0
  108. package/src/lib/model/pos-offline-card-limits.js.map +1 -0
  109. package/src/lib/model/pos-reader-splash.d.ts +114 -0
  110. package/src/lib/model/pos-reader-splash.js +141 -0
  111. package/src/lib/model/pos-reader-splash.js.map +1 -0
  112. package/src/lib/model/product-write.d.ts +6 -0
  113. package/src/lib/plugin-config.d.ts +10 -0
  114. package/src/lib/plugin-config.js +40 -0
  115. package/src/lib/plugin-config.js.map +1 -1
  116. package/src/lib/plugin.js +28 -0
  117. package/src/lib/plugin.js.map +1 -1
  118. package/src/lib/server/cart-checkout.js +3 -1
  119. package/src/lib/server/cart-checkout.js.map +1 -1
  120. package/src/lib/server/cart.js +12 -1
  121. package/src/lib/server/cart.js.map +1 -1
  122. package/src/lib/server/catalog.js +49 -12
  123. package/src/lib/server/catalog.js.map +1 -1
  124. package/src/lib/server/checkout-extras.js +1 -1
  125. package/src/lib/server/checkout-extras.js.map +1 -1
  126. package/src/lib/server/checkout.js +7 -0
  127. package/src/lib/server/checkout.js.map +1 -1
  128. package/src/lib/server/person-eraser.d.ts +8 -1
  129. package/src/lib/server/person-eraser.js +23 -1
  130. package/src/lib/server/person-eraser.js.map +1 -1
  131. package/src/lib/server/pos-check-in.d.ts +49 -0
  132. package/src/lib/server/pos-check-in.js +652 -0
  133. package/src/lib/server/pos-check-in.js.map +1 -0
  134. package/src/lib/server/pos-day-report.d.ts +46 -0
  135. package/src/lib/server/pos-day-report.js +299 -0
  136. package/src/lib/server/pos-day-report.js.map +1 -0
  137. package/src/lib/server/pos-hardware-admin.d.ts +50 -0
  138. package/src/lib/server/pos-hardware-admin.js +366 -0
  139. package/src/lib/server/pos-hardware-admin.js.map +1 -0
  140. package/src/lib/server/pos-hardware-notify.d.ts +27 -0
  141. package/src/lib/server/pos-hardware-notify.js +142 -0
  142. package/src/lib/server/pos-hardware-notify.js.map +1 -0
  143. package/src/lib/server/pos-hardware-user-eraser.d.ts +26 -0
  144. package/src/lib/server/pos-hardware-user-eraser.js +67 -0
  145. package/src/lib/server/pos-hardware-user-eraser.js.map +1 -0
  146. package/src/lib/server/pos-hardware-webhook.d.ts +31 -0
  147. package/src/lib/server/pos-hardware-webhook.js +176 -0
  148. package/src/lib/server/pos-hardware-webhook.js.map +1 -0
  149. package/src/lib/server/pos-hardware.d.ts +58 -0
  150. package/src/lib/server/pos-hardware.js +234 -0
  151. package/src/lib/server/pos-hardware.js.map +1 -0
  152. package/src/lib/server/pos-offline-card-reconcile.d.ts +38 -0
  153. package/src/lib/server/pos-offline-card-reconcile.js +58 -0
  154. package/src/lib/server/pos-offline-card-reconcile.js.map +1 -0
  155. package/src/lib/server/pos-offline-sync.d.ts +32 -0
  156. package/src/lib/server/pos-offline-sync.js +191 -15
  157. package/src/lib/server/pos-offline-sync.js.map +1 -1
  158. package/src/lib/server/pos-ops-routes.d.ts +4 -2
  159. package/src/lib/server/pos-ops-routes.js +14 -2
  160. package/src/lib/server/pos-ops-routes.js.map +1 -1
  161. package/src/lib/server/pos-order.js +39 -51
  162. package/src/lib/server/pos-order.js.map +1 -1
  163. package/src/lib/server/pos-payment.js +8 -4
  164. package/src/lib/server/pos-payment.js.map +1 -1
  165. package/src/lib/server/pos-reader-splash-admin.d.ts +36 -0
  166. package/src/lib/server/pos-reader-splash-admin.js +295 -0
  167. package/src/lib/server/pos-reader-splash-admin.js.map +1 -0
  168. package/src/lib/server/pos-reader-splash-render.d.ts +40 -0
  169. package/src/lib/server/pos-reader-splash-render.js +138 -0
  170. package/src/lib/server/pos-reader-splash-render.js.map +1 -0
  171. package/src/lib/server/pos-reader-splash-server.d.ts +32 -0
  172. package/src/lib/server/pos-reader-splash-server.js +32 -0
  173. package/src/lib/server/pos-reader-splash-server.js.map +1 -0
  174. package/src/lib/server/pos-reader-splash.d.ts +105 -0
  175. package/src/lib/server/pos-reader-splash.js +548 -0
  176. package/src/lib/server/pos-reader-splash.js.map +1 -0
  177. package/src/lib/server/pos-sale.d.ts +2 -1
  178. package/src/lib/server/pos-sale.js +3 -1
  179. package/src/lib/server/pos-sale.js.map +1 -1
  180. package/src/lib/server/pos-terminal.d.ts +67 -4
  181. package/src/lib/server/pos-terminal.js +239 -32
  182. package/src/lib/server/pos-terminal.js.map +1 -1
  183. package/src/lib/server/process-restock.js +4 -0
  184. package/src/lib/server/process-restock.js.map +1 -1
  185. package/src/lib/server/product-card.js +2 -2
  186. package/src/lib/server/product-card.js.map +1 -1
  187. package/src/lib/server/product-catalog.d.ts +2 -0
  188. package/src/lib/server/product-catalog.js +11 -4
  189. package/src/lib/server/product-catalog.js.map +1 -1
  190. package/src/lib/server/product.js +3 -1
  191. package/src/lib/server/product.js.map +1 -1
  192. package/src/lib/server/related.js +8 -1
  193. package/src/lib/server/related.js.map +1 -1
  194. package/src/lib/server/reservation-availability-query.d.ts +35 -0
  195. package/src/lib/server/reservation-availability-query.js +34 -0
  196. package/src/lib/server/reservation-availability-query.js.map +1 -0
  197. package/src/lib/server/reservation-availability.d.ts +21 -0
  198. package/src/lib/server/reservation-availability.js +64 -10
  199. package/src/lib/server/reservation-availability.js.map +1 -1
  200. package/src/lib/server/reservation-walk-in.d.ts +28 -0
  201. package/src/lib/server/reservation-walk-in.js +166 -0
  202. package/src/lib/server/reservation-walk-in.js.map +1 -0
  203. package/src/lib/server/reserve.js +13 -10
  204. package/src/lib/server/reserve.js.map +1 -1
  205. package/src/lib/server/reviews.js +3 -1
  206. package/src/lib/server/reviews.js.map +1 -1
  207. package/src/lib/server/site-page-resolver.js +5 -2
  208. package/src/lib/server/site-page-resolver.js.map +1 -1
  209. package/src/lib/server.js +26 -0
  210. package/src/lib/server.js.map +1 -1
  211. package/src/lib/testing/fake-firestore.js +72 -0
  212. package/src/lib/testing/fake-firestore.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-reader-splash-staff-page.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { ConsoleStaffPageProps } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { resolveStaffRoleGate } from '@aglyn/aglyn/app-utils/staff-role-gate'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { BlockedControl } from '@aglyn/shared-ui-jsx/components/blocked-control.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { Alert, Box, Button, Stack, Typography } from '@mui/material'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { POS_READER_SPLASH_MAX_BYTES, type PosReaderSplashFamilyId } from '../../model/pos-reader-splash'\nimport {\n PosReaderSplashRequestError,\n staffApplyReaderSplash,\n staffReaderSplash,\n staffReaderSplashPreview,\n staffRemoveReaderSplash,\n staffUploadReaderSplash,\n type StaffReaderSplash,\n type StaffReaderSplashFamily,\n} from './pos/pos-reader-splash-api'\n\nconst WRITE_ROLES = ['super'] as const\n\n/** A file as base64, without the `data:` prefix. */\nfunction readBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(String(reader.result ?? '').replace(/^data:[^,]*,/, ''))\n reader.onerror = () => reject(reader.error)\n reader.readAsDataURL(file)\n })\n}\n\n/**\n * Staff → Reader start-up screen (AGL-4048): the platform's default screen\n * for Stripe smart readers, shown by every store that has not picked its own\n * logo or image. White-label workspaces never show it. The artwork is made\n * separately and uploaded here, one image per screen size, each checked\n * against Stripe's rules before it is kept. A change is put on every store's\n * readers straight away; readers pick it up within about ten minutes.\n */\nexport function PosReaderSplashStaffPage(props: ConsoleStaffPageProps) {\n const { staffRole = null } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const [state, setState] = useState<StaffReaderSplash | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [previews, setPreviews] = useState<Partial<Record<PosReaderSplashFamilyId, string>>>({})\n const inputs = useRef<Partial<Record<PosReaderSplashFamilyId, HTMLInputElement | null>>>({})\n const gate = resolveStaffRoleGate(staffRole, WRITE_ROLES)\n const uid = user?.uid ?? ''\n\n const warn = useCallback(\n (caught: unknown, fallback: string) =>\n enqueueSnackbar(caught instanceof PosReaderSplashRequestError ? caught.message : fallback, {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const load = useCallback(async () => {\n if (!user) return\n setError(null)\n try {\n setState(await staffReaderSplash(user))\n } catch (caught) {\n setError(caught instanceof PosReaderSplashRequestError ? caught.message : 'The start-up screen could not be read')\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid])\n\n useEffect(() => {\n void load()\n }, [load])\n\n // Each family's image, fetched with the staff session (the route is not public).\n const shas = state?.families.map((family) => family.image?.sha256 ?? '').join(',') ?? ''\n useEffect(() => {\n if (!user || !state) return\n let active = true\n const made: string[] = []\n void Promise.all(\n state.families.map(async (family) => {\n const url = family.image ? await staffReaderSplashPreview(user, family.id).catch(() => null) : null\n if (url) made.push(url)\n return [family.id, url ?? undefined] as const\n }),\n ).then((entries) => {\n if (active) setPreviews(Object.fromEntries(entries))\n })\n return () => {\n active = false\n made.forEach((url) => URL.revokeObjectURL(url))\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, shas])\n\n const applyEverywhere = async () => {\n if (!user) return\n try {\n const counts = await staffApplyReaderSplash(user)\n enqueueSnackbar(\n `Updated ${counts.applied} ${counts.applied === 1 ? 'store' : 'stores'}` +\n (counts.failed ? `; ${counts.failed} could not be updated` : '') +\n (counts.more ? '. Press Update stores again for the rest.' : '.'),\n { variant: counts.failed ? 'warning' : 'success', persist: false },\n )\n } catch (caught) {\n warn(caught, 'Stores could not be updated')\n }\n }\n\n const change = async (run: () => Promise<StaffReaderSplash>, fallback: string) => {\n setBusy(true)\n try {\n setState(await run())\n await applyEverywhere()\n } catch (caught) {\n warn(caught, fallback)\n } finally {\n setBusy(false)\n }\n }\n\n const upload = async (family: StaffReaderSplashFamily, file: File | undefined) => {\n if (!user || !file) return\n if (file.size >= POS_READER_SPLASH_MAX_BYTES) {\n enqueueSnackbar('Use an image under 2 MB.', { variant: 'warning', persist: false })\n return\n }\n const data = await readBase64(file)\n await change(() => staffUploadReaderSplash(user, family.id, data), 'The image could not be uploaded')\n }\n\n const remove = async (family: StaffReaderSplashFamily) => {\n if (!user) return\n const confirmed = await confirm({\n title: `Remove the ${family.label} screen?`,\n description:\n family.id === 'portrait-large'\n ? 'Without it there is no default: stores that use it go back to the reader’s standard screen.'\n : 'This screen is then drawn from the S700 and S710 image.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (confirmed) await change(() => staffRemoveReaderSplash(user, family.id), 'The image could not be removed')\n }\n\n const writeReason = gate.reason ?? (busy ? 'Saving…' : undefined)\n\n return (\n <CardDisplay\n header={'Reader start-up screen'}\n help={pluginDocsHelp('posHardware', { anchor: '#reader-start-up-screen' })}\n HeaderProps={{\n action: (\n <BlockedControl blocked={Boolean(writeReason) || !state?.ready} reason={writeReason ?? 'Upload the S700 and S710 screen first.'}>\n <Button size=\"small\" onClick={() => void applyEverywhere()}>\n {'Update stores'}\n </Button>\n </BlockedControl>\n ),\n }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'The default screen Stripe smart readers show while they wait for a payment, on every store that has not ' +\n 'chosen its own logo or image. White-label workspaces never show it. Readers pick up a change within about ' +\n 'ten minutes.'}\n </Typography>\n <Alert severity=\"info\">\n {'Each image must be a PNG or JPEG under 2 MB, at exactly the reader’s screen size. The WisePOS E screen is ' +\n 'drawn from the S700 and S710 image when none is uploaded.'}\n </Alert>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {(state?.families ?? []).map((family) => (\n <Stack key={family.id} direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ alignItems: { sm: 'center' } }}>\n <Box\n sx={(theme) => ({\n width: theme.spacing(12),\n aspectRatio: '9 / 16',\n borderRadius: 1,\n border: 1,\n borderColor: 'divider',\n bgcolor: 'action.hover',\n overflow: 'hidden',\n flexShrink: 0,\n })}\n >\n {previews[family.id] ? (\n <Box\n component=\"img\"\n src={previews[family.id]}\n alt={`${family.label} start-up screen`}\n sx={{ width: 1, height: 1, objectFit: 'cover', display: 'block' }}\n />\n ) : null}\n </Box>\n <Stack spacing={0.5} sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"subtitle2\">{family.label}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${family.width} × ${family.height} pixels. ` +\n (family.image\n ? `Uploaded ${new Date(family.image.uploadedAtMs).toLocaleString()}.`\n : family.id === 'portrait-large'\n ? 'Not uploaded: stores show the reader’s standard screen.'\n : 'Not uploaded: drawn from the S700 and S710 image.')}\n </Typography>\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <input\n ref={(element) => {\n inputs.current[family.id] = element\n }}\n type=\"file\"\n accept=\"image/png,image/jpeg\"\n hidden\n aria-label={`Upload the ${family.label} screen`}\n onChange={(event) => {\n const file = event.target.files?.[0]\n event.target.value = ''\n void upload(family, file)\n }}\n />\n <BlockedControl blocked={Boolean(writeReason)} reason={writeReason ?? ''}>\n <Button size=\"small\" onClick={() => inputs.current[family.id]?.click()}>\n {family.image ? 'Replace' : 'Upload'}\n </Button>\n </BlockedControl>\n {family.image ? (\n <BlockedControl blocked={Boolean(writeReason)} reason={writeReason ?? ''}>\n <Button size=\"small\" color=\"error\" onClick={() => void remove(family)}>\n {'Remove'}\n </Button>\n </BlockedControl>\n ) : null}\n </Stack>\n </Stack>\n ))}\n </Stack>\n </CardDisplay>\n )\n}\nPosReaderSplashStaffPage.displayName = 'PosReaderSplashStaffPage'\n\nexport default PosReaderSplashStaffPage\n"],"names":["pluginDocsHelp","resolveStaffRoleGate","CardDisplay","useConfirmationContext","BlockedControl","useSnackbar","useUser","Alert","Box","Button","Stack","Typography","useCallback","useEffect","useRef","useState","POS_READER_SPLASH_MAX_BYTES","PosReaderSplashRequestError","staffApplyReaderSplash","staffReaderSplash","staffReaderSplashPreview","staffRemoveReaderSplash","staffUploadReaderSplash","WRITE_ROLES","readBase64","file","Promise","resolve","reject","reader","FileReader","onload","String","result","replace","onerror","error","readAsDataURL","PosReaderSplashStaffPage","props","gate","staffRole","data","user","enqueueSnackbar","confirm","state","setState","setError","busy","setBusy","previews","setPreviews","inputs","uid","warn","caught","fallback","message","variant","persist","load","shas","families","map","family","image","sha256","join","active","made","all","url","id","catch","push","undefined","then","entries","Object","fromEntries","forEach","URL","revokeObjectURL","applyEverywhere","counts","applied","failed","more","change","run","upload","size","remove","confirmed","title","label","description","confirmationText","confirmationButtonProps","color","writeReason","reason","header","help","anchor","HeaderProps","action","blocked","Boolean","ready","onClick","contentGutterX","contentGutterY","spacing","severity","direction","xs","sm","sx","alignItems","theme","width","aspectRatio","borderRadius","border","borderColor","bgcolor","overflow","flexShrink","component","src","alt","height","objectFit","display","flex","minWidth","Date","uploadedAtMs","toLocaleString","input","ref","element","current","type","accept","hidden","aria-label","onChange","event","target","files","value","click","displayName"],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  /**
2
- * The register's zone (AGL-3644): `posOrders`, above the till's product grid,
2
+ * The register's zones. `posOrders` (AGL-3644), above the till's product grid,
3
3
  * where orders another channel sends to the counter — a delivery app's, say
4
- * — wait to be accepted, made and handed over.
4
+ * — wait to be accepted, made and handed over. `posCheckIn` (AGL-4043), on
5
+ * the register's check-in, where another plugin shows what a customer at the
6
+ * window needs for the day.
5
7
  *
6
8
  * Declared here because zones are declared by the plugin that hosts them. A
7
9
  * widget from another plugin restates these props rather than importing
@@ -19,5 +21,37 @@ export interface ConsolePosOrdersZoneProps {
19
21
  registerId: string | null;
20
22
  }
21
23
  export declare const POS_ORDERS_ZONE: import("@aglyn/aglyn/plugin-manager/plugin-zones").PluginZone<ConsolePosOrdersZoneProps>;
22
- /** Declares it, from the console registrar. */
24
+ /**
25
+ * Where the register's check-in zone is drawn (AGL-4043): a customer row in
26
+ * the check-in search, the customer the check-in screen has open, or the
27
+ * customer attached to a sale on the register.
28
+ */
29
+ export type PosCheckInZonePlacement = 'check-in-row' | 'check-in-customer' | 'register-customer';
30
+ /**
31
+ * What `posCheckIn` hands a widget (AGL-4043): one customer at the window on
32
+ * one day, and nothing about why anybody is checking them. A widget reads
33
+ * its own records for the customer (by contact id, else by email) and shows
34
+ * what it knows — a status, a button that starts its own flow.
35
+ */
36
+ export interface ConsolePosCheckInZoneProps {
37
+ hostId: string;
38
+ /** The org the page names; `undefined` where the host does not know it. */
39
+ orgId: string | undefined;
40
+ /** The customer's contact in the workspace's people records, or `null` when none is known. */
41
+ contactId: string | null;
42
+ /** The customer's email address, lower case, or `null` when none is known. */
43
+ email: string | null;
44
+ /** The day being checked in, `YYYY-MM-DD` in the site's time zone. */
45
+ dayKey: string;
46
+ /** The customer's name as the order or the stay gave it, or `null`. */
47
+ name: string | null;
48
+ /**
49
+ * How many check-ins the customer has due on `dayKey` (each person a pass
50
+ * or a stay covers), or `null` where the host does not know.
51
+ */
52
+ unitsDue: number | null;
53
+ placement: PosCheckInZonePlacement;
54
+ }
55
+ export declare const POS_CHECK_IN_ZONE: import("@aglyn/aglyn/plugin-manager/plugin-zones").PluginZone<ConsolePosCheckInZoneProps>;
56
+ /** Declares them, from the console registrar. */
23
57
  export declare function registerCommercePosZones(): void;
@@ -16,7 +16,8 @@
16
16
  */ import { definePluginZone, registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
17
17
  import { BUNDLE_ID } from "../../constants/bundle-common.js";
18
18
  export const POS_ORDERS_ZONE = definePluginZone('posOrders');
19
- /** Declares it, from the console registrar. */ export function registerCommercePosZones() {
19
+ export const POS_CHECK_IN_ZONE = definePluginZone('posCheckIn');
20
+ /** Declares them, from the console registrar. */ export function registerCommercePosZones() {
20
21
  registerPluginZone({
21
22
  zone: POS_ORDERS_ZONE,
22
23
  label: 'Register orders',
@@ -26,6 +27,15 @@ export const POS_ORDERS_ZONE = definePluginZone('posOrders');
26
27
  }, {
27
28
  pluginId: BUNDLE_ID
28
29
  });
30
+ registerPluginZone({
31
+ zone: POS_CHECK_IN_ZONE,
32
+ label: 'Register check-in',
33
+ surface: 'console',
34
+ layout: 'bare',
35
+ description: 'On each customer row of the register’s check-in, on the customer the check-in screen has open, and on the customer attached to a sale. A widget here shows a status the customer needs for the day from its own records, and may offer a button that starts its own flow; it never checks anybody in and writes no check-in.'
36
+ }, {
37
+ pluginId: BUNDLE_ID
38
+ });
29
39
  }
30
40
 
31
41
  //# sourceMappingURL=pos-zones.js.map
@@ -1 +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"}
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 zones. `posOrders` (AGL-3644), 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. `posCheckIn` (AGL-4043), on\n * the register's check-in, where another plugin shows what a customer at the\n * window needs for the day.\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/**\n * Where the register's check-in zone is drawn (AGL-4043): a customer row in\n * the check-in search, the customer the check-in screen has open, or the\n * customer attached to a sale on the register.\n */\nexport type PosCheckInZonePlacement = 'check-in-row' | 'check-in-customer' | 'register-customer'\n\n/**\n * What `posCheckIn` hands a widget (AGL-4043): one customer at the window on\n * one day, and nothing about why anybody is checking them. A widget reads\n * its own records for the customer (by contact id, else by email) and shows\n * what it knows — a status, a button that starts its own flow.\n */\nexport interface ConsolePosCheckInZoneProps {\n hostId: string\n /** The org the page names; `undefined` where the host does not know it. */\n orgId: string | undefined\n /** The customer's contact in the workspace's people records, or `null` when none is known. */\n contactId: string | null\n /** The customer's email address, lower case, or `null` when none is known. */\n email: string | null\n /** The day being checked in, `YYYY-MM-DD` in the site's time zone. */\n dayKey: string\n /** The customer's name as the order or the stay gave it, or `null`. */\n name: string | null\n /**\n * How many check-ins the customer has due on `dayKey` (each person a pass\n * or a stay covers), or `null` where the host does not know.\n */\n unitsDue: number | null\n placement: PosCheckInZonePlacement\n}\n\nexport const POS_CHECK_IN_ZONE = definePluginZone<ConsolePosCheckInZoneProps>('posCheckIn')\n\n/** Declares them, 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 registerPluginZone(\n {\n zone: POS_CHECK_IN_ZONE,\n label: 'Register check-in',\n surface: 'console',\n layout: 'bare',\n description:\n 'On each customer row of the register’s check-in, on the customer the check-in screen has open, and on the customer attached to a sale. A widget here shows a status the customer needs for the day from its own records, and may offer a button that starts its own flow; it never checks anybody in and writes no check-in.',\n },\n { pluginId: BUNDLE_ID },\n )\n}\n"],"names":["definePluginZone","registerPluginZone","BUNDLE_ID","POS_ORDERS_ZONE","POS_CHECK_IN_ZONE","registerCommercePosZones","zone","label","surface","layout","description","pluginId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,SACEA,gBAAgB,EAChBC,kBAAkB,QACb,2CAA0C;AACjD,SAASC,SAAS,QAAQ,mCAA+B;AA0BzD,OAAO,MAAMC,kBAAkBH,iBAA4C,aAAY;AAmCvF,OAAO,MAAMI,oBAAoBJ,iBAA6C,cAAa;AAE3F,+CAA+C,GAC/C,OAAO,SAASK;IACdJ,mBACE;QACEK,MAAMH;QACNI,OAAO;QACPC,SAAS;QACTC,QAAQ;QACRC,aACE;IACJ,GACA;QAAEC,UAAUT;IAAU;IAExBD,mBACE;QACEK,MAAMF;QACNG,OAAO;QACPC,SAAS;QACTC,QAAQ;QACRC,aACE;IACJ,GACA;QAAEC,UAAUT;IAAU;AAE1B"}
@@ -0,0 +1,20 @@
1
+ import * as CommerceModel from '../../model';
2
+ type Patch = Partial<CommerceModel.HostProduct>;
3
+ /** What the section reads of a variant: never its price or SKU, so typing those does not redraw it. */
4
+ export type CheckInVariant = Pick<CommerceModel.ProductVariant, 'id' | 'options' | 'checkIn'>;
5
+ export interface ProductCheckInFieldsProps {
6
+ checkIn: CommerceModel.ProductCheckIn | undefined;
7
+ variants: readonly CheckInVariant[];
8
+ update: (patch: Patch | ((at: CommerceModel.HostProduct) => Patch)) => void;
9
+ }
10
+ /**
11
+ * Check-in at the window (AGL-4043): whether each item sold of this product
12
+ * is somebody to check in on the day it was bought — a day pass, a camping
13
+ * spot, parking — and how many people one item admits. A product with
14
+ * options can turn it on or off per variant ("Spectator" needs no
15
+ * wristband) and give a variant its own number of people.
16
+ *
17
+ * Memoized on its own props like every section of this editor (AGL-3423).
18
+ */
19
+ export declare const ProductCheckInFields: import("react").MemoExoticComponent<(props: ProductCheckInFieldsProps) => import("react").JSX.Element>;
20
+ export {};
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
19
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
20
+ import { FormControlLabel, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
21
+ import { memo } from "react";
22
+ import * as CommerceModel from "../../model/index.js";
23
+ /** A whole number of people from 1 to the ceiling, from what was typed; blank is 1. */ function headcountFrom(value) {
24
+ const count = Math.round(Number(value));
25
+ return Number.isFinite(count) && count >= 1 ? Math.min(count, CommerceModel.CHECK_IN_MAX_HEADCOUNT) : 1;
26
+ }
27
+ function variantLabel(variant) {
28
+ var _variant_options;
29
+ const values = Object.values((_variant_options = variant.options) != null ? _variant_options : {});
30
+ return values.length ? values.join(' / ') : 'Default';
31
+ }
32
+ /**
33
+ * Check-in at the window (AGL-4043): whether each item sold of this product
34
+ * is somebody to check in on the day it was bought — a day pass, a camping
35
+ * spot, parking — and how many people one item admits. A product with
36
+ * options can turn it on or off per variant ("Spectator" needs no
37
+ * wristband) and give a variant its own number of people.
38
+ *
39
+ * Memoized on its own props like every section of this editor (AGL-3423).
40
+ */ export const ProductCheckInFields = /*#__PURE__*/ memo(function ProductCheckInFields(props) {
41
+ var _ref;
42
+ const { checkIn, variants, update } = props;
43
+ const enabled = (checkIn == null ? void 0 : checkIn.enabled) === true;
44
+ const headcount = (_ref = checkIn == null ? void 0 : checkIn.headcount) != null ? _ref : 1;
45
+ const setProduct = (next)=>update({
46
+ checkIn: next
47
+ });
48
+ // Written against the draft as it stands, so a price typed meanwhile is kept.
49
+ const setVariant = (id, next)=>update((at)=>({
50
+ variants: at.variants.map((variant)=>{
51
+ if (variant.id !== id) return variant;
52
+ const { checkIn: _previous } = variant, rest = _object_without_properties_loose(variant, [
53
+ "checkIn"
54
+ ]);
55
+ return next ? _extends({}, rest, {
56
+ checkIn: next
57
+ }) : rest;
58
+ })
59
+ }));
60
+ return /*#__PURE__*/ _jsxs(Stack, {
61
+ spacing: 1.5,
62
+ children: [
63
+ /*#__PURE__*/ _jsx(Typography, {
64
+ variant: "subtitle1",
65
+ component: "h3",
66
+ children: 'Check-in'
67
+ }),
68
+ /*#__PURE__*/ _jsx(FormControlLabel, {
69
+ control: /*#__PURE__*/ _jsx(Switch, {
70
+ checked: enabled,
71
+ onChange: (event)=>setProduct(event.target.checked ? {
72
+ enabled: true,
73
+ headcount
74
+ } : {
75
+ enabled: false
76
+ })
77
+ }),
78
+ label: "Needs check-in"
79
+ }),
80
+ /*#__PURE__*/ _jsx(Typography, {
81
+ variant: "body2",
82
+ color: "text.secondary",
83
+ children: 'Each one sold, online or at the register, is somebody to check in at the window on the day it was bought, ' + 'with an optional wristband number or color.'
84
+ }),
85
+ enabled ? /*#__PURE__*/ _jsx(TextField, {
86
+ label: "People per item",
87
+ size: "small",
88
+ value: headcount,
89
+ onChange: (event)=>setProduct({
90
+ enabled: true,
91
+ headcount: headcountFrom(event.target.value)
92
+ }),
93
+ helperText: headcount > 1 ? `Buying 3 makes ${3 * headcount} check-ins` : 'Buying 3 makes 3 check-ins',
94
+ slotProps: {
95
+ htmlInput: {
96
+ inputMode: 'numeric'
97
+ }
98
+ },
99
+ sx: {
100
+ maxWidth: (theme)=>theme.spacing(28)
101
+ }
102
+ }) : null,
103
+ variants.length > 1 ? variants.map((variant)=>{
104
+ var _ref;
105
+ const own = CommerceModel.normalizeProductCheckIn(variant.checkIn);
106
+ const choice = own ? own.enabled ? 'on' : 'off' : 'product';
107
+ return /*#__PURE__*/ _jsxs(Stack, {
108
+ direction: {
109
+ xs: 'column',
110
+ sm: 'row'
111
+ },
112
+ spacing: 1,
113
+ children: [
114
+ /*#__PURE__*/ _jsxs(TextField, {
115
+ select: true,
116
+ size: "small",
117
+ label: variantLabel(variant),
118
+ value: choice,
119
+ onChange: (event)=>{
120
+ var _ref;
121
+ const picked = event.target.value;
122
+ setVariant(variant.id, picked === 'product' ? undefined : picked === 'on' ? {
123
+ enabled: true,
124
+ headcount: (_ref = own == null ? void 0 : own.headcount) != null ? _ref : headcount
125
+ } : {
126
+ enabled: false
127
+ });
128
+ },
129
+ sx: {
130
+ flex: 1
131
+ },
132
+ children: [
133
+ /*#__PURE__*/ _jsx(MenuItem, {
134
+ value: "product",
135
+ children: enabled ? 'Same as the product (needs check-in)' : 'Same as the product (no check-in)'
136
+ }),
137
+ /*#__PURE__*/ _jsx(MenuItem, {
138
+ value: "on",
139
+ children: 'Needs check-in'
140
+ }),
141
+ /*#__PURE__*/ _jsx(MenuItem, {
142
+ value: "off",
143
+ children: 'No check-in'
144
+ })
145
+ ]
146
+ }),
147
+ choice === 'on' ? /*#__PURE__*/ _jsx(TextField, {
148
+ label: "People per item",
149
+ size: "small",
150
+ value: (_ref = own == null ? void 0 : own.headcount) != null ? _ref : 1,
151
+ onChange: (event)=>setVariant(variant.id, {
152
+ enabled: true,
153
+ headcount: headcountFrom(event.target.value)
154
+ }),
155
+ slotProps: {
156
+ htmlInput: {
157
+ inputMode: 'numeric'
158
+ }
159
+ },
160
+ sx: {
161
+ flex: 1
162
+ }
163
+ }) : null
164
+ ]
165
+ }, variant.id);
166
+ }) : null
167
+ ]
168
+ });
169
+ });
170
+ ProductCheckInFields.displayName = 'ProductCheckInFields';
171
+
172
+ //# sourceMappingURL=product-check-in-fields.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/product-check-in-fields.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 { FormControlLabel, MenuItem, Stack, Switch, TextField, Typography } from '@mui/material'\nimport { memo } from 'react'\nimport * as CommerceModel from '../../model'\n\ntype Patch = Partial<CommerceModel.HostProduct>\n\n/** What the section reads of a variant: never its price or SKU, so typing those does not redraw it. */\nexport type CheckInVariant = Pick<CommerceModel.ProductVariant, 'id' | 'options' | 'checkIn'>\n\nexport interface ProductCheckInFieldsProps {\n checkIn: CommerceModel.ProductCheckIn | undefined\n variants: readonly CheckInVariant[]\n update: (patch: Patch | ((at: CommerceModel.HostProduct) => Patch)) => void\n}\n\ntype VariantChoice = 'product' | 'on' | 'off'\n\n/** A whole number of people from 1 to the ceiling, from what was typed; blank is 1. */\nfunction headcountFrom(value: string): number {\n const count = Math.round(Number(value))\n return Number.isFinite(count) && count >= 1 ? Math.min(count, CommerceModel.CHECK_IN_MAX_HEADCOUNT) : 1\n}\n\nfunction variantLabel(variant: CheckInVariant): string {\n const values = Object.values(variant.options ?? {})\n return values.length ? values.join(' / ') : 'Default'\n}\n\n/**\n * Check-in at the window (AGL-4043): whether each item sold of this product\n * is somebody to check in on the day it was bought — a day pass, a camping\n * spot, parking — and how many people one item admits. A product with\n * options can turn it on or off per variant (\"Spectator\" needs no\n * wristband) and give a variant its own number of people.\n *\n * Memoized on its own props like every section of this editor (AGL-3423).\n */\nexport const ProductCheckInFields = memo(function ProductCheckInFields(props: ProductCheckInFieldsProps) {\n const { checkIn, variants, update } = props\n const enabled = checkIn?.enabled === true\n const headcount = checkIn?.headcount ?? 1\n\n const setProduct = (next: CommerceModel.ProductCheckIn) => update({ checkIn: next })\n // Written against the draft as it stands, so a price typed meanwhile is kept.\n const setVariant = (id: string, next: CommerceModel.ProductCheckIn | undefined) =>\n update((at) => ({\n variants: at.variants.map((variant) => {\n if (variant.id !== id) return variant\n const { checkIn: _previous, ...rest } = variant\n return next ? { ...rest, checkIn: next } : rest\n }),\n }))\n\n return (\n <Stack spacing={1.5}>\n <Typography variant=\"subtitle1\" component=\"h3\">\n {'Check-in'}\n </Typography>\n <FormControlLabel\n control={\n <Switch\n checked={enabled}\n onChange={(event) =>\n setProduct(event.target.checked ? { enabled: true, headcount } : { enabled: false })\n }\n />\n }\n label=\"Needs check-in\"\n />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Each one sold, online or at the register, is somebody to check in at the window on the day it was bought, ' +\n 'with an optional wristband number or color.'}\n </Typography>\n {enabled ? (\n <TextField\n label=\"People per item\"\n size=\"small\"\n value={headcount}\n onChange={(event) => setProduct({ enabled: true, headcount: headcountFrom(event.target.value) })}\n helperText={headcount > 1 ? `Buying 3 makes ${3 * headcount} check-ins` : 'Buying 3 makes 3 check-ins'}\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n sx={{ maxWidth: (theme) => theme.spacing(28) }}\n />\n ) : null}\n {variants.length > 1\n ? variants.map((variant) => {\n const own = CommerceModel.normalizeProductCheckIn(variant.checkIn)\n const choice: VariantChoice = own ? (own.enabled ? 'on' : 'off') : 'product'\n return (\n <Stack key={variant.id} direction={{ xs: 'column', sm: 'row' }} spacing={1}>\n <TextField\n select\n size=\"small\"\n label={variantLabel(variant)}\n value={choice}\n onChange={(event) => {\n const picked = event.target.value as VariantChoice\n setVariant(\n variant.id,\n picked === 'product'\n ? undefined\n : picked === 'on'\n ? { enabled: true, headcount: own?.headcount ?? headcount }\n : { enabled: false },\n )\n }}\n sx={{ flex: 1 }}\n >\n <MenuItem value=\"product\">{enabled ? 'Same as the product (needs check-in)' : 'Same as the product (no check-in)'}</MenuItem>\n <MenuItem value=\"on\">{'Needs check-in'}</MenuItem>\n <MenuItem value=\"off\">{'No check-in'}</MenuItem>\n </TextField>\n {choice === 'on' ? (\n <TextField\n label=\"People per item\"\n size=\"small\"\n value={own?.headcount ?? 1}\n onChange={(event) =>\n setVariant(variant.id, { enabled: true, headcount: headcountFrom(event.target.value) })\n }\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n sx={{ flex: 1 }}\n />\n ) : null}\n </Stack>\n )\n })\n : null}\n </Stack>\n )\n})\n\nProductCheckInFields.displayName = 'ProductCheckInFields'\n"],"names":["FormControlLabel","MenuItem","Stack","Switch","TextField","Typography","memo","CommerceModel","headcountFrom","value","count","Math","round","Number","isFinite","min","CHECK_IN_MAX_HEADCOUNT","variantLabel","variant","values","Object","options","length","join","ProductCheckInFields","props","checkIn","variants","update","enabled","headcount","setProduct","next","setVariant","id","at","map","_previous","rest","spacing","component","control","checked","onChange","event","target","label","color","size","helperText","slotProps","htmlInput","inputMode","sx","maxWidth","theme","own","normalizeProductCheckIn","choice","direction","xs","sm","select","picked","undefined","flex","displayName"],"mappings":"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"}
@@ -35,7 +35,8 @@ import { useContentStable } from "@aglyn/shared-ui-jsx/hooks/use-content-stable"
35
35
  import { EntitlementUpsell, useCommerceEntitlement } from "./entitlement-gate.component.js";
36
36
  import { PRODUCT_EDITOR_ZONE } from "./product-zones.js";
37
37
  import { MembersVideosField, PaidDownloadAddButton, PaidMediaProtection } from "./paid-media.js";
38
- import { ProductRegisterFields } from "./product-register-fields.component.js";
38
+ import { ProductCheckInFields } from "./product-check-in-fields.component.js";
39
+ import { ProductRegisterFields, ProductSellOnlineField } from "./product-register-fields.component.js";
39
40
  /**
40
41
  * What each picker in this dialog will offer.
41
42
  *
@@ -1192,6 +1193,26 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1192
1193
  const update = useCallback((patch)=>replaceDraft((at)=>_extends({}, at, typeof patch === 'function' ? patch(at) : patch)), [
1193
1194
  replaceDraft
1194
1195
  ]);
1196
+ // The check-in section's view of the variants (AGL-4043): ids, options and
1197
+ // their check-in setting only, so a keystroke in a price or a SKU leaves it
1198
+ // alone (AGL-3423).
1199
+ const checkInVariantsKey = JSON.stringify(current.variants.map((variant)=>{
1200
+ var _variant_options, _variant_checkIn;
1201
+ return [
1202
+ variant.id,
1203
+ (_variant_options = variant.options) != null ? _variant_options : null,
1204
+ (_variant_checkIn = variant.checkIn) != null ? _variant_checkIn : null
1205
+ ];
1206
+ }));
1207
+ const checkInVariants = useMemo(()=>current.variants.map(({ id, options, checkIn })=>({
1208
+ id,
1209
+ options,
1210
+ checkIn
1211
+ })), // Keyed on what it reads, not on the array the last keystroke replaced.
1212
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1213
+ [
1214
+ checkInVariantsKey
1215
+ ]);
1195
1216
  const setTags = useCallback((tags)=>update({
1196
1217
  tags: tags.map((tag)=>String(tag).trim()).filter(Boolean)
1197
1218
  }), [
@@ -1682,14 +1703,32 @@ const MemoPaidDownloadAddButton = /*#__PURE__*/ memo(PaidDownloadAddButton);
1682
1703
  update: update,
1683
1704
  replaceDraft: replaceDraft
1684
1705
  }),
1685
- pos.ready && pos.entitled ? /*#__PURE__*/ _jsx(ProductRegisterFields, {
1686
- posQuickKey: Boolean(current.posQuickKey),
1687
- modifierGroups: (_current_modifierGroups = current.modifierGroups) != null ? _current_modifierGroups : NO_MODIFIER_GROUPS,
1688
- update: update
1689
- }) : pos.ready ? /*#__PURE__*/ _jsx(EntitlementUpsell, {
1690
- planLabel: pos.planLabel,
1691
- upgradeHref: pos.upgradeHref,
1692
- children: 'Register quick keys and modifier groups (sizes, add-ons) come with the point of sale.'
1706
+ pos.ready && pos.entitled ? /*#__PURE__*/ _jsxs(_Fragment, {
1707
+ children: [
1708
+ /*#__PURE__*/ _jsx(ProductRegisterFields, {
1709
+ posQuickKey: Boolean(current.posQuickKey),
1710
+ sellOnline: CommerceModel.productSellsOnline(current),
1711
+ modifierGroups: (_current_modifierGroups = current.modifierGroups) != null ? _current_modifierGroups : NO_MODIFIER_GROUPS,
1712
+ update: update
1713
+ }),
1714
+ /*#__PURE__*/ _jsx(ProductCheckInFields, {
1715
+ checkIn: current.checkIn,
1716
+ variants: checkInVariants,
1717
+ update: update
1718
+ })
1719
+ ]
1720
+ }) : pos.ready ? /*#__PURE__*/ _jsxs(_Fragment, {
1721
+ children: [
1722
+ /*#__PURE__*/ _jsx(EntitlementUpsell, {
1723
+ planLabel: pos.planLabel,
1724
+ upgradeHref: pos.upgradeHref,
1725
+ children: 'Register quick keys, modifier groups (sizes, add-ons), check-in at the window and selling a product in person only come with the point of sale.'
1726
+ }),
1727
+ !CommerceModel.productSellsOnline(current) ? /*#__PURE__*/ _jsx(ProductSellOnlineField, {
1728
+ sellOnline: false,
1729
+ update: update
1730
+ }) : null
1731
+ ]
1693
1732
  }) : null,
1694
1733
  current.type === 'digital' ? /*#__PURE__*/ _jsx(ProductDigitalFields, {
1695
1734
  hostId: hostId,