@aglyn/plugins-commerce 1.0.0-beta.232 → 1.0.0-beta.234
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -13
- package/src/lib/components/cart-extras.d.ts +6 -0
- package/src/lib/components/cart-extras.js +4 -1
- package/src/lib/components/cart-extras.js.map +1 -1
- package/src/lib/components/cart-fulfillment.d.ts +117 -0
- package/src/lib/components/cart-fulfillment.js +367 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -0
- package/src/lib/components/cart.js +52 -10
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +42 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +38 -10
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.js +177 -3
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +10 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
- package/src/lib/components/console/order-offline-notice.component.js +53 -0
- package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +24 -1
- package/src/lib/components/console/pos/pos-api.js +13 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
- package/src/lib/components/console/pos/use-pos-display.js +3 -2
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-devices-card.component.js +2 -2
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
- package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
- package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
- package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
- package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
- package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +174 -27
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +35 -10
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/stock-movements-card.component.js +48 -16
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +8 -1
- package/src/lib/components/console/store-zones.js +11 -1
- package/src/lib/components/console/store-zones.js.map +1 -1
- package/src/lib/components/order-status.js +66 -0
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +42 -15
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
- package/src/lib/constants/local-fulfillment-list-query.js +84 -0
- package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
- package/src/lib/constants/orders-list-query.d.ts +7 -2
- package/src/lib/constants/orders-list-query.js +89 -8
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
- package/src/lib/constants/pos-shift-list-query.js +115 -0
- package/src/lib/constants/pos-shift-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +6 -1
- package/src/lib/constants/product-list-query.js +77 -8
- package/src/lib/constants/product-list-query.js.map +1 -1
- package/src/lib/constants/stock-movement-query.d.ts +3 -2
- package/src/lib/constants/stock-movement-query.js +52 -8
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +5 -3
- package/src/lib/model/buyer-notifications.js +25 -4
- package/src/lib/model/buyer-notifications.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +59 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
- package/src/lib/model/commerce-pos-kiosk.js +147 -0
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +234 -0
- package/src/lib/model/commerce-pos-offline.js +301 -0
- package/src/lib/model/commerce-pos-offline.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +16 -6
- package/src/lib/model/commerce-pos-ops.js +12 -4
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +13 -1
- package/src/lib/model/commerce-pos.js +5 -4
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-stock-holds.d.ts +24 -3
- package/src/lib/model/commerce-stock-holds.js +26 -8
- package/src/lib/model/commerce-stock-holds.js.map +1 -1
- package/src/lib/model/commerce.d.ts +3 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +4 -0
- package/src/lib/model/index.js +4 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
- package/src/lib/model/local-fulfillment-settings.js +361 -0
- package/src/lib/model/local-fulfillment-settings.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +10 -1
- package/src/lib/model/order-list-fields.js +1 -0
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +131 -0
- package/src/lib/model/order-local-fulfillment.js +125 -0
- package/src/lib/model/order-local-fulfillment.js.map +1 -0
- package/src/lib/model/order-shipping-export.js +4 -0
- package/src/lib/model/order-shipping-export.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +20 -1
- package/src/lib/model/order-status-view.js +60 -6
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/plugin-config.js +6 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +8 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-kiosk-config.d.ts +26 -0
- package/src/lib/pos-kiosk-config.js +59 -0
- package/src/lib/pos-kiosk-config.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +8 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +19 -0
- package/src/lib/server/api-v1/order-view.js +35 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/billing-webhook.js +238 -87
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +173 -13
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout-extras.js +18 -4
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +71 -14
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.d.ts +86 -0
- package/src/lib/server/local-fulfillment-status.js +379 -0
- package/src/lib/server/local-fulfillment-status.js.map +1 -0
- package/src/lib/server/local-fulfillment.d.ts +190 -0
- package/src/lib/server/local-fulfillment.js +580 -0
- package/src/lib/server/local-fulfillment.js.map +1 -0
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/order-notifications.js +61 -0
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +27 -1
- package/src/lib/server/pos-display.js +50 -9
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
- package/src/lib/server/pos-kiosk-principal.js +42 -0
- package/src/lib/server/pos-kiosk-principal.js.map +1 -0
- package/src/lib/server/pos-kiosk.d.ts +54 -0
- package/src/lib/server/pos-kiosk.js +972 -0
- package/src/lib/server/pos-kiosk.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +85 -0
- package/src/lib/server/pos-offline-sync.js +765 -0
- package/src/lib/server/pos-offline-sync.js.map +1 -0
- package/src/lib/server/pos-order.js +22 -4
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +6 -0
- package/src/lib/server/pos-payment.js +225 -6
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-print.js +5 -0
- package/src/lib/server/pos-print.js.map +1 -1
- package/src/lib/server/pos-return.js +27 -0
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.d.ts +6 -0
- package/src/lib/server/pos-sale.js +2 -0
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +8 -1
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/refund.js +3 -0
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/stock-hold.d.ts +9 -1
- package/src/lib/server/stock-hold.js +15 -7
- package/src/lib/server/stock-hold.js.map +1 -1
- package/src/lib/server.js +16 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.js +161 -0
- package/src/lib/tenant-emails.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/pos-tender-panel.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Divider,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport * as CommerceModel from '../../../model'\nimport {\n centsFromInput,\n newAttemptKey,\n posGiftCardBalance,\n posNativeBridge,\n posTender,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n type PosTenderAction,\n type PosTenderResult,\n} from './pos-api'\nimport { POS_TOUCH_PX } from './pos-product-grid.component'\nimport {\n PosCashDialog,\n PosFolioDialog,\n PosGiftCardDialog,\n PosKeyedCardDialog,\n PosQrDialog,\n} from './pos-tender-dialogs.component'\nimport type { PosDisplayControl } from './use-pos-display'\n\ntype User = Parameters<typeof posTender>[0]\n\nconst STATUS_LABEL: Record<CommerceModel.OrderPaymentStatus, string> = {\n pending: 'Waiting',\n succeeded: 'Approved',\n failed: 'Declined',\n canceled: 'Canceled',\n reversed: 'Returned',\n}\n\nconst STATUS_COLOR: Record<\n CommerceModel.OrderPaymentStatus,\n 'default' | 'success' | 'error' | 'warning' | 'info'\n> = {\n pending: 'info',\n succeeded: 'success',\n failed: 'error',\n canceled: 'default',\n reversed: 'warning',\n}\n\nexport interface PosTenderPanelProps {\n user: User\n hostId: string\n registerId: string\n sale: PosSaleSummary\n context: PosRegisterContext | null\n stays: any[]\n display: PosDisplayControl\n onSale: (sale: PosSaleSummary) => void\n /** The sale is voided: the basket is the cashier's again. */\n onVoided: () => void\n /** The tip chosen for the next payment, before it is taken. */\n onTipChange?: (tipCents: number) => void\n /** A PIN-switched cashier (AGL-3609) takes each payment they start. */\n cashierAssertion?: string\n notify: (message: string, variant: 'success' | 'error' | 'warning' | 'info') => void\n}\n\n/**\n * Taking payment on an open sale (AGL-3607): the balance due, every payment\n * taken so far with its live status, and the tenders. A sale can take as many\n * payments as it needs; it is paid when the balance reaches zero, and only\n * then does the server take the stock and complete it.\n */\nexport function PosTenderPanel(props: PosTenderPanelProps) {\n const { user, hostId, sale, context, display, onSale, notify } = props\n const settings = context?.settings\n const [amount, setAmount] = useState('')\n const [tipCents, setTipCents] = useState(0)\n const [busy, setBusy] = useState(false)\n const [dialog, setDialog] = useState<'cash' | 'gift' | 'folio' | null>(null)\n const [qr, setQr] = useState<{ url: string; amountCents: number } | null>(null)\n const [keyed, setKeyed] = useState<{ clientSecret: string; amountCents: number; paymentId: string } | null>(\n null,\n )\n const [readerId, setReaderId] = useState('')\n const inFlight = useRef(false)\n const { confirm } = useConfirmationContext()\n const { onTipChange } = props\n useEffect(() => {\n onTipChange?.(tipCents)\n }, [onTipChange, tipCents])\n\n const readers = (context?.readers ?? []).filter(\n (reader) => !reader.registerId || reader.registerId === props.registerId,\n )\n useEffect(() => {\n if (!readerId && readers.length) {\n setReaderId(readers.find((reader) => reader.registerId === props.registerId)?.id ?? readers[0].id)\n }\n }, [readerId, readers, props.registerId])\n\n // The amount defaults to whatever is still open; a split is the cashier\n // typing less than that.\n const typedCents = centsFromInput(amount)\n const chargeCents = typedCents > 0 ? Math.min(typedCents, sale.tenderableCents) : sale.tenderableCents\n const paid = sale.status === 'paid'\n\n const run = useCallback(\n async (\n action: PosTenderAction,\n body: Record<string, unknown> = {},\n starts = false,\n ): Promise<PosTenderResult | null> => {\n if (inFlight.current) return null\n inFlight.current = true\n setBusy(true)\n try {\n const result = await posTender(\n user,\n hostId,\n sale.orderId,\n action,\n starts && props.cashierAssertion ? { ...body, cashierAssertion: props.cashierAssertion } : body,\n starts ? newAttemptKey() : undefined,\n )\n onSale(result.sale)\n if (starts) {\n setAmount('')\n setTipCents(0)\n }\n return result\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Something went wrong', 'error')\n return null\n } finally {\n inFlight.current = false\n setBusy(false)\n }\n },\n [user, hostId, sale.orderId, onSale, notify, props.cashierAssertion],\n )\n\n // Card payments still waiting are checked every two seconds: the reader,\n // the QR page and the typed card all settle on the server, and this is the\n // register's view of it (the webhook does the same thing when it lands).\n const pending = sale.payments.filter(\n (payment) => payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method),\n )\n const pendingKey = pending.map((payment) => payment.id).join(',')\n const latest = useRef({ user, onSale })\n latest.current = { user, onSale }\n useEffect(() => {\n if (!pendingKey) return undefined\n const timer = setInterval(async () => {\n for (const id of pendingKey.split(',')) {\n try {\n const result = await posTender(latest.current.user, hostId, sale.orderId, 'status', {\n paymentId: id,\n })\n latest.current.onSale(result.sale)\n } catch {\n // The next tick asks again.\n }\n }\n }, 2000)\n return () => clearInterval(timer)\n }, [pendingKey, hostId, sale.orderId])\n\n // The display shows \"tap your card\" while a reader payment waits, and the\n // running balance otherwise.\n const readerWaiting = pending.some((payment) => payment.method === 'card_present')\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (readerWaiting) {\n void display.show({ mode: 'processing', processing: { message: 'Tap, insert or swipe your card on the reader.' } })\n }\n }, [readerWaiting, display])\n\n const askTip = useCallback(async () => {\n const base = chargeCents\n if (!(base > 0) || !settings) return\n const answer = await display.ask({\n mode: 'tip',\n tip: { baseCents: base, percentages: settings.tipPercentages, allowCustom: true },\n })\n if (answer) {\n setTipCents(answer.tipCents ?? 0)\n notify(answer.tipCents ? `Tip: ${usd(answer.tipCents)}` : 'No tip', 'info')\n }\n }, [chargeCents, settings, display, notify])\n\n const startCardPresent = useCallback(async () => {\n if (!readerId) return\n await run('card-present', { amountCents: chargeCents, tipCents, readerId }, true)\n }, [run, chargeCents, tipCents, readerId])\n\n const startBridge = useCallback(async () => {\n const bridge = posNativeBridge()\n if (!bridge) return\n const amountCents = chargeCents\n const result = await run('card-present-sdk', { amountCents, tipCents }, true)\n if (!result?.paymentIntentId || !result.clientSecret || !result.paymentId) return\n try {\n const collected = await bridge.collectCardPayment({\n paymentIntentId: result.paymentIntentId,\n clientSecret: result.clientSecret,\n amountCents: amountCents + tipCents,\n })\n if (collected.status !== 'collected') {\n notify(collected.message ?? 'The card was not taken.', 'warning')\n }\n } finally {\n // Settled by the server either way: the status poll captures an\n // authorized tap and records a decline or a cancel.\n await run('status', { paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents, notify])\n\n const startKeyed = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-keyed', { amountCents, tipCents }, true)\n if (result?.clientSecret && result.paymentId) {\n setKeyed({ clientSecret: result.clientSecret, amountCents: amountCents + tipCents, paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents])\n\n const startLink = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-link', { amountCents, tipCents }, true)\n const url = result?.sale.payments.find((payment) => payment.id === result.paymentId)?.checkoutUrl\n if (url) setQr({ url, amountCents: amountCents + tipCents })\n }, [run, chargeCents, tipCents])\n\n const tipOn = Boolean(settings?.tippingEnabled) && !paid\n\n return (\n <Stack spacing={1.5} sx={{ minHeight: 0 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>\n <Typography variant=\"h6\">{paid ? 'Paid' : 'Balance due'}</Typography>\n <Typography variant=\"h4\" component=\"p\">\n {usd(paid ? sale.totalCents : sale.dueCents)}\n </Typography>\n </Box>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Total ${usd(sale.totalCents)} · paid ${usd(sale.paidCents)}` +\n (sale.tipCents ? ` · tips ${usd(sale.tipCents)}` : '')}\n </Typography>\n\n {sale.payments.length ? (\n <Stack spacing={1} aria-label=\"Payments\">\n {sale.payments.map((payment) => (\n <Box key={payment.id} sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 140 }}>\n {CommerceModel.describeOrderPayment({ ...payment, atMs: 0 })}\n {payment.changeCents ? ` · change ${usd(payment.changeCents)}` : ''}\n </Typography>\n <Chip size=\"small\" label={STATUS_LABEL[payment.status]} color={STATUS_COLOR[payment.status]} />\n {payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method) ? (\n <>\n {payment.method === 'card_link' && payment.checkoutUrl ? (\n <Button\n size=\"small\"\n onClick={() => setQr({ url: payment.checkoutUrl as string, amountCents: payment.amountCents })}\n >\n {'Show QR'}\n </Button>\n ) : null}\n {payment.method === 'card_present' && payment.livemode === false && context?.terminal?.testMode ? (\n <Button size=\"small\" onClick={() => void run('simulate', { paymentId: payment.id })}>\n {'Simulate tap'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={() => void run('cancel', { paymentId: payment.id })}>\n {'Cancel'}\n </Button>\n </>\n ) : null}\n {payment.status === 'failed' && payment.method === 'card_present' && !paid ? (\n <Button size=\"small\" onClick={() => void run('retry', { paymentId: payment.id })}>\n {'Retry'}\n </Button>\n ) : null}\n {payment.failureMessage && payment.status === 'failed' ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ width: 1 }}>\n {payment.failureMessage}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : null}\n\n {!paid ? (\n <>\n <Divider />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n label=\"Amount to charge ($)\"\n placeholder={(sale.tenderableCents / 100).toFixed(2)}\n value={amount}\n onChange={(event) => setAmount(event.target.value.replace(/[^0-9.]/g, ''))}\n sx={{ flex: 1 }}\n helperText={\n typedCents > 0 && typedCents < sale.tenderableCents\n ? `Split: ${usd(sale.tenderableCents - typedCents)} stays open`\n : ' '\n }\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n {tipOn ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"body2\" sx={{ mr: 1 }}>\n {`Tip ${usd(tipCents)}`}\n </Typography>\n {display.connected ? (\n <Button\n variant=\"outlined\"\n onClick={() => void askTip()}\n disabled={busy || Boolean(display.asking)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {display.asking === 'tip' ? 'Waiting for customer…' : 'Ask on display'}\n </Button>\n ) : null}\n {(settings?.tipPercentages ?? []).map((pct) => (\n <Button\n key={pct}\n variant={tipCents === CommerceModel.posTipFromPercent(chargeCents, pct) && tipCents > 0 ? 'contained' : 'outlined'}\n onClick={() => setTipCents(CommerceModel.posTipFromPercent(chargeCents, pct))}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {`${pct}%`}\n </Button>\n ))}\n <Button onClick={() => setTipCents(0)} sx={{ minHeight: POS_TOUCH_PX }}>\n {'No tip'}\n </Button>\n </Stack>\n ) : null}\n <Box\n sx={{\n display: 'grid',\n gap: 1,\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n }}\n >\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('cash')}\n sx={{ minHeight: 56 }}\n >\n {'Cash'}\n </Button>\n {context?.terminal?.available && readers.length ? (\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0 || !readerId}\n onClick={() => void startCardPresent()}\n sx={{ minHeight: 56 }}\n >\n {'Card reader'}\n </Button>\n ) : null}\n {posNativeBridge() ? (\n <Button\n variant=\"contained\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startBridge()}\n sx={{ minHeight: 56 }}\n >\n {'Tap to Pay / Bluetooth reader'}\n </Button>\n ) : null}\n {context?.publishableKey ? (\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startKeyed()}\n sx={{ minHeight: 56 }}\n >\n {'Type card'}\n </Button>\n ) : null}\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => void startLink()}\n sx={{ minHeight: 56 }}\n >\n {'Card (QR)'}\n </Button>\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('gift')}\n sx={{ minHeight: 56 }}\n >\n {'Gift card'}\n </Button>\n {props.stays.length ? (\n <Button\n variant=\"outlined\"\n disabled={busy || chargeCents <= 0}\n onClick={() => setDialog('folio')}\n sx={{ minHeight: 56 }}\n >\n {'Room'}\n </Button>\n ) : null}\n </Box>\n {context?.terminal?.available && readers.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Card reader\"\n value={readerId}\n onChange={(event) => setReaderId(event.target.value)}\n >\n {readers.map((reader) => (\n <MenuItem key={reader.id} value={reader.id}>\n {`${reader.label}${reader.status === 'online' ? '' : ' (offline)'}`}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {readers.some((reader) => reader.id === readerId && reader.status !== 'online') ? (\n <Alert severity=\"warning\">{'The selected card reader looks offline.'}</Alert>\n ) : null}\n <Button\n color=\"error\"\n disabled={busy}\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Void this sale?',\n description:\n 'Every payment taken on it is handed back: cards are refunded, gift ' +\n 'cards re-credited and room charges removed. Hand back any cash.',\n confirmationText: 'Void sale',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const result = await run('void')\n if (result) {\n notify('Sale voided', 'info')\n props.onVoided()\n }\n }}\n sx={{ minHeight: POS_TOUCH_PX, alignSelf: 'flex-start' }}\n >\n {'Void sale'}\n </Button>\n </>\n ) : null}\n\n <PosCashDialog\n open={dialog === 'cash'}\n dueCents={chargeCents}\n tipCents={tipCents}\n busy={busy}\n onClose={() => setDialog(null)}\n onTake={async (tenderedCents) => {\n const result = await run(\n 'cash',\n {\n tenderedCents,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n tipCents,\n },\n true,\n )\n if (result) {\n setDialog(null)\n const change = result.sale.payments.find((payment) => payment.id === result.paymentId)?.changeCents\n if (change) notify(`Change due: ${usd(change)}`, 'success')\n }\n }}\n />\n <PosGiftCardDialog\n open={dialog === 'gift'}\n busy={busy}\n onClose={() => setDialog(null)}\n onCheck={async (code) => {\n try {\n return await posGiftCardBalance(user, hostId, code)\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not read that card', 'warning')\n return null\n }\n }}\n onApply={async (code) => {\n const result = await run('gift-card', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n />\n <PosFolioDialog\n open={dialog === 'folio'}\n amountCents={chargeCents}\n stays={props.stays}\n busy={busy}\n onClose={() => setDialog(null)}\n onCharge={async (reservationId) => {\n const result = await run(\n 'folio',\n { reservationId, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosQrDialog url={qr?.url ?? ''} amountCents={qr?.amountCents ?? 0} onClose={() => setQr(null)} />\n <PosKeyedCardDialog\n clientSecret={keyed?.clientSecret ?? ''}\n publishableKey={context?.publishableKey ?? ''}\n amountCents={keyed?.amountCents ?? 0}\n onClose={async () => {\n const open = keyed\n setKeyed(null)\n // Closing without paying releases the amount for another tender.\n if (open) await run('cancel', { paymentId: open.paymentId })\n }}\n onConfirmed={async () => {\n const open = keyed\n setKeyed(null)\n if (open) await run('status', { paymentId: open.paymentId })\n }}\n />\n </Stack>\n )\n}\nPosTenderPanel.displayName = 'PosTenderPanel'\n"],"names":["Alert","Box","Button","Chip","Divider","MenuItem","Stack","TextField","Typography","useConfirmationContext","useCallback","useEffect","useRef","useState","CommerceModel","centsFromInput","newAttemptKey","posGiftCardBalance","posNativeBridge","posTender","PosRequestError","usd","POS_TOUCH_PX","PosCashDialog","PosFolioDialog","PosGiftCardDialog","PosKeyedCardDialog","PosQrDialog","STATUS_LABEL","pending","succeeded","failed","canceled","reversed","STATUS_COLOR","PosTenderPanel","props","context","user","hostId","sale","display","onSale","notify","settings","amount","setAmount","tipCents","setTipCents","busy","setBusy","dialog","setDialog","qr","setQr","keyed","setKeyed","readerId","setReaderId","inFlight","confirm","onTipChange","readers","filter","reader","registerId","length","find","id","typedCents","chargeCents","Math","min","tenderableCents","paid","status","run","action","body","starts","current","result","orderId","cashierAssertion","undefined","error","message","payments","payment","isCardPaymentMethod","method","pendingKey","map","join","latest","timer","setInterval","split","paymentId","clearInterval","readerWaiting","some","connected","asking","show","mode","processing","askTip","base","answer","ask","tip","baseCents","percentages","tipPercentages","allowCustom","startCardPresent","amountCents","startBridge","bridge","paymentIntentId","clientSecret","collected","collectCardPayment","startKeyed","startLink","url","checkoutUrl","tipOn","Boolean","tippingEnabled","spacing","sx","minHeight","justifyContent","alignItems","variant","component","totalCents","dueCents","color","paidCents","aria-label","gap","flexWrap","flex","minWidth","describeOrderPayment","atMs","changeCents","size","label","onClick","livemode","terminal","testMode","failureMessage","width","direction","placeholder","toFixed","value","onChange","event","target","replace","helperText","slotProps","htmlInput","inputMode","rowGap","mr","disabled","pct","posTipFromPercent","gridTemplateColumns","available","publishableKey","stays","select","severity","confirmed","title","description","confirmationText","confirmationButtonProps","then","catch","onVoided","alignSelf","open","onClose","onTake","tenderedCents","change","onCheck","code","onApply","onCharge","reservationId","onConfirmed","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/pos-tender-panel.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Divider,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport * as CommerceModel from '../../../model'\nimport {\n centsFromInput,\n newAttemptKey,\n posCreditLookup,\n posGiftCardBalance,\n posNativeBridge,\n posTender,\n PosRequestError,\n usd,\n type PosRegisterContext,\n type PosSaleSummary,\n type PosTenderAction,\n type PosTenderResult,\n} from './pos-api'\nimport { POS_TOUCH_PX } from './pos-product-grid.component'\nimport {\n PosCashDialog,\n PosCreditDialog,\n PosFolioDialog,\n PosGiftCardDialog,\n PosKeyedCardDialog,\n PosQrDialog,\n} from './pos-tender-dialogs.component'\nimport type { PosDisplayControl } from './use-pos-display'\n\ntype User = Parameters<typeof posTender>[0]\n\nconst STATUS_LABEL: Record<CommerceModel.OrderPaymentStatus, string> = {\n pending: 'Waiting',\n succeeded: 'Approved',\n failed: 'Declined',\n canceled: 'Canceled',\n reversed: 'Returned',\n}\n\nconst STATUS_COLOR: Record<\n CommerceModel.OrderPaymentStatus,\n 'default' | 'success' | 'error' | 'warning' | 'info'\n> = {\n pending: 'info',\n succeeded: 'success',\n failed: 'error',\n canceled: 'default',\n reversed: 'warning',\n}\n\nexport interface PosTenderPanelProps {\n user: User\n hostId: string\n registerId: string\n sale: PosSaleSummary\n context: PosRegisterContext | null\n stays: any[]\n display: PosDisplayControl\n onSale: (sale: PosSaleSummary) => void\n /** The sale is voided: the basket is the cashier's again. */\n onVoided: () => void\n /** The tip chosen for the next payment, before it is taken. */\n onTipChange?: (tipCents: number) => void\n /** A PIN-switched cashier (AGL-3609) takes each payment they start. */\n cashierAssertion?: string\n notify: (message: string, variant: 'success' | 'error' | 'warning' | 'info') => void\n /**\n * The register is offline (AGL-3625). Every tender here is the server's —\n * the card reader, the typed card, the QR link, the gift card, the room\n * charge and this sale's own cash — so each is off until it returns.\n */\n offline?: boolean\n /** Rings this basket as an offline cash sale instead; offered while nothing is paid. */\n onSellOffline?: () => void\n}\n\n/**\n * Taking payment on an open sale (AGL-3607): the balance due, every payment\n * taken so far with its live status, and the tenders. A sale can take as many\n * payments as it needs; it is paid when the balance reaches zero, and only\n * then does the server take the stock and complete it.\n */\nexport function PosTenderPanel(props: PosTenderPanelProps) {\n const { user, hostId, sale, context, display, onSale, notify } = props\n const settings = context?.settings\n const [amount, setAmount] = useState('')\n const [tipCents, setTipCents] = useState(0)\n const [busy, setBusy] = useState(false)\n const [dialog, setDialog] = useState<'cash' | 'gift' | 'folio' | 'credit' | null>(null)\n // The store-credit provider whose dialog is open (AGL-3640).\n const [creditProvider, setCreditProvider] = useState<{ providerId: string; label: string; lookup: boolean } | null>(\n null,\n )\n const [qr, setQr] = useState<{ url: string; amountCents: number } | null>(null)\n const [keyed, setKeyed] = useState<{ clientSecret: string; amountCents: number; paymentId: string } | null>(\n null,\n )\n const [readerId, setReaderId] = useState('')\n const inFlight = useRef(false)\n const { confirm } = useConfirmationContext()\n const { onTipChange } = props\n useEffect(() => {\n onTipChange?.(tipCents)\n }, [onTipChange, tipCents])\n\n const readers = (context?.readers ?? []).filter(\n (reader) => !reader.registerId || reader.registerId === props.registerId,\n )\n useEffect(() => {\n if (!readerId && readers.length) {\n setReaderId(readers.find((reader) => reader.registerId === props.registerId)?.id ?? readers[0].id)\n }\n }, [readerId, readers, props.registerId])\n\n // The amount defaults to whatever is still open; a split is the cashier\n // typing less than that.\n const typedCents = centsFromInput(amount)\n const chargeCents = typedCents > 0 ? Math.min(typedCents, sale.tenderableCents) : sale.tenderableCents\n const paid = sale.status === 'paid'\n const offline = props.offline === true\n\n const run = useCallback(\n async (\n action: PosTenderAction,\n body: Record<string, unknown> = {},\n starts = false,\n ): Promise<PosTenderResult | null> => {\n if (inFlight.current) return null\n inFlight.current = true\n setBusy(true)\n try {\n const result = await posTender(\n user,\n hostId,\n sale.orderId,\n action,\n starts && props.cashierAssertion ? { ...body, cashierAssertion: props.cashierAssertion } : body,\n starts ? newAttemptKey() : undefined,\n )\n onSale(result.sale)\n if (starts) {\n setAmount('')\n setTipCents(0)\n }\n return result\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Something went wrong', 'error')\n return null\n } finally {\n inFlight.current = false\n setBusy(false)\n }\n },\n [user, hostId, sale.orderId, onSale, notify, props.cashierAssertion],\n )\n\n // Card payments still waiting are checked every two seconds: the reader,\n // the QR page and the typed card all settle on the server, and this is the\n // register's view of it (the webhook does the same thing when it lands).\n const pending = sale.payments.filter(\n (payment) => payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method),\n )\n const pendingKey = pending.map((payment) => payment.id).join(',')\n const latest = useRef({ user, onSale })\n latest.current = { user, onSale }\n useEffect(() => {\n if (!pendingKey) return undefined\n const timer = setInterval(async () => {\n for (const id of pendingKey.split(',')) {\n try {\n const result = await posTender(latest.current.user, hostId, sale.orderId, 'status', {\n paymentId: id,\n })\n latest.current.onSale(result.sale)\n } catch {\n // The next tick asks again.\n }\n }\n }, 2000)\n return () => clearInterval(timer)\n }, [pendingKey, hostId, sale.orderId])\n\n // The display shows \"tap your card\" while a reader payment waits, and the\n // running balance otherwise.\n const readerWaiting = pending.some((payment) => payment.method === 'card_present')\n useEffect(() => {\n if (!display.connected || display.asking) return\n if (readerWaiting) {\n void display.show({ mode: 'processing', processing: { message: 'Tap, insert or swipe your card on the reader.' } })\n }\n }, [readerWaiting, display])\n\n const askTip = useCallback(async () => {\n const base = chargeCents\n if (!(base > 0) || !settings) return\n const answer = await display.ask({\n mode: 'tip',\n tip: { baseCents: base, percentages: settings.tipPercentages, allowCustom: true },\n })\n if (answer) {\n setTipCents(answer.tipCents ?? 0)\n notify(answer.tipCents ? `Tip: ${usd(answer.tipCents)}` : 'No tip', 'info')\n }\n }, [chargeCents, settings, display, notify])\n\n const startCardPresent = useCallback(async () => {\n if (!readerId) return\n await run('card-present', { amountCents: chargeCents, tipCents, readerId }, true)\n }, [run, chargeCents, tipCents, readerId])\n\n const startBridge = useCallback(async () => {\n const bridge = posNativeBridge()\n if (!bridge) return\n const amountCents = chargeCents\n const result = await run('card-present-sdk', { amountCents, tipCents }, true)\n if (!result?.paymentIntentId || !result.clientSecret || !result.paymentId) return\n try {\n const collected = await bridge.collectCardPayment({\n paymentIntentId: result.paymentIntentId,\n clientSecret: result.clientSecret,\n amountCents: amountCents + tipCents,\n })\n if (collected.status !== 'collected') {\n notify(collected.message ?? 'The card was not taken.', 'warning')\n }\n } finally {\n // Settled by the server either way: the status poll captures an\n // authorized tap and records a decline or a cancel.\n await run('status', { paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents, notify])\n\n const startKeyed = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-keyed', { amountCents, tipCents }, true)\n if (result?.clientSecret && result.paymentId) {\n setKeyed({ clientSecret: result.clientSecret, amountCents: amountCents + tipCents, paymentId: result.paymentId })\n }\n }, [run, chargeCents, tipCents])\n\n const startLink = useCallback(async () => {\n const amountCents = chargeCents\n const result = await run('card-link', { amountCents, tipCents }, true)\n const url = result?.sale.payments.find((payment) => payment.id === result.paymentId)?.checkoutUrl\n if (url) setQr({ url, amountCents: amountCents + tipCents })\n }, [run, chargeCents, tipCents])\n\n const tipOn = Boolean(settings?.tippingEnabled) && !paid\n\n return (\n <Stack spacing={1.5} sx={{ minHeight: 0 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>\n <Typography variant=\"h6\">{paid ? 'Paid' : 'Balance due'}</Typography>\n <Typography variant=\"h4\" component=\"p\">\n {usd(paid ? sale.totalCents : sale.dueCents)}\n </Typography>\n </Box>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Total ${usd(sale.totalCents)} · paid ${usd(sale.paidCents)}` +\n (sale.tipCents ? ` · tips ${usd(sale.tipCents)}` : '')}\n </Typography>\n\n {sale.payments.length ? (\n <Stack spacing={1} aria-label=\"Payments\">\n {sale.payments.map((payment) => (\n <Box key={payment.id} sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 140 }}>\n {CommerceModel.describeOrderPayment({ ...payment, atMs: 0 })}\n {payment.changeCents ? ` · change ${usd(payment.changeCents)}` : ''}\n </Typography>\n <Chip size=\"small\" label={STATUS_LABEL[payment.status]} color={STATUS_COLOR[payment.status]} />\n {payment.status === 'pending' && CommerceModel.isCardPaymentMethod(payment.method) ? (\n <>\n {payment.method === 'card_link' && payment.checkoutUrl ? (\n <Button\n size=\"small\"\n onClick={() => setQr({ url: payment.checkoutUrl as string, amountCents: payment.amountCents })}\n >\n {'Show QR'}\n </Button>\n ) : null}\n {payment.method === 'card_present' && payment.livemode === false && context?.terminal?.testMode ? (\n <Button size=\"small\" onClick={() => void run('simulate', { paymentId: payment.id })}>\n {'Simulate tap'}\n </Button>\n ) : null}\n <Button size=\"small\" color=\"error\" onClick={() => void run('cancel', { paymentId: payment.id })}>\n {'Cancel'}\n </Button>\n </>\n ) : null}\n {payment.status === 'failed' && payment.method === 'card_present' && !paid ? (\n <Button size=\"small\" onClick={() => void run('retry', { paymentId: payment.id })}>\n {'Retry'}\n </Button>\n ) : null}\n {payment.failureMessage && payment.status === 'failed' ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ width: 1 }}>\n {payment.failureMessage}\n </Typography>\n ) : null}\n </Box>\n ))}\n </Stack>\n ) : null}\n\n {offline && !paid ? (\n <Alert\n severity=\"warning\"\n action={\n props.onSellOffline && sale.payments.length === 0 ? (\n <Button color=\"inherit\" size=\"small\" onClick={props.onSellOffline}>\n {'Sell for cash offline'}\n </Button>\n ) : null\n }\n >\n {sale.payments.length === 0\n ? 'Offline: card readers, typed cards, the QR link, gift cards, store credit and room charges are off. ' +\n 'Take this basket as an offline cash sale, or wait for the connection.'\n : 'Offline: this sale has a payment on it and finishes when the connection returns. ' +\n 'Card readers, typed cards, the QR link, gift cards, store credit and room charges are off.'}\n </Alert>\n ) : null}\n {!paid ? (\n <>\n <Divider />\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n label=\"Amount to charge ($)\"\n placeholder={(sale.tenderableCents / 100).toFixed(2)}\n value={amount}\n onChange={(event) => setAmount(event.target.value.replace(/[^0-9.]/g, ''))}\n sx={{ flex: 1 }}\n helperText={\n typedCents > 0 && typedCents < sale.tenderableCents\n ? `Split: ${usd(sale.tenderableCents - typedCents)} stays open`\n : ' '\n }\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n {tipOn ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"body2\" sx={{ mr: 1 }}>\n {`Tip ${usd(tipCents)}`}\n </Typography>\n {display.connected ? (\n <Button\n variant=\"outlined\"\n onClick={() => void askTip()}\n disabled={offline || busy || Boolean(display.asking)}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {display.asking === 'tip' ? 'Waiting for customer…' : 'Ask on display'}\n </Button>\n ) : null}\n {(settings?.tipPercentages ?? []).map((pct) => (\n <Button\n key={pct}\n variant={tipCents === CommerceModel.posTipFromPercent(chargeCents, pct) && tipCents > 0 ? 'contained' : 'outlined'}\n onClick={() => setTipCents(CommerceModel.posTipFromPercent(chargeCents, pct))}\n sx={{ minHeight: POS_TOUCH_PX }}\n >\n {`${pct}%`}\n </Button>\n ))}\n <Button onClick={() => setTipCents(0)} sx={{ minHeight: POS_TOUCH_PX }}>\n {'No tip'}\n </Button>\n </Stack>\n ) : null}\n <Box\n sx={{\n display: 'grid',\n gap: 1,\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n }}\n >\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('cash')}\n sx={{ minHeight: 56 }}\n >\n {'Cash'}\n </Button>\n {context?.terminal?.available && readers.length ? (\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0 || !readerId}\n onClick={() => void startCardPresent()}\n sx={{ minHeight: 56 }}\n >\n {'Card reader'}\n </Button>\n ) : null}\n {posNativeBridge() ? (\n <Button\n variant=\"contained\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startBridge()}\n sx={{ minHeight: 56 }}\n >\n {'Tap to Pay / Bluetooth reader'}\n </Button>\n ) : null}\n {context?.publishableKey ? (\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startKeyed()}\n sx={{ minHeight: 56 }}\n >\n {'Type card'}\n </Button>\n ) : null}\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => void startLink()}\n sx={{ minHeight: 56 }}\n >\n {'Card (QR)'}\n </Button>\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('gift')}\n sx={{ minHeight: 56 }}\n >\n {'Gift card'}\n </Button>\n {(context?.credits ?? []).map((credit) => (\n <Button\n key={credit.providerId}\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => {\n setCreditProvider(credit)\n setDialog('credit')\n }}\n sx={{ minHeight: 56 }}\n >\n {credit.label}\n </Button>\n ))}\n {props.stays.length ? (\n <Button\n variant=\"outlined\"\n disabled={offline || busy || chargeCents <= 0}\n onClick={() => setDialog('folio')}\n sx={{ minHeight: 56 }}\n >\n {'Room'}\n </Button>\n ) : null}\n </Box>\n {context?.terminal?.available && readers.length > 1 ? (\n <TextField\n select\n size=\"small\"\n label=\"Card reader\"\n value={readerId}\n onChange={(event) => setReaderId(event.target.value)}\n >\n {readers.map((reader) => (\n <MenuItem key={reader.id} value={reader.id}>\n {`${reader.label}${reader.status === 'online' ? '' : ' (offline)'}`}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n {readers.some((reader) => reader.id === readerId && reader.status !== 'online') ? (\n <Alert severity=\"warning\">{'The selected card reader looks offline.'}</Alert>\n ) : null}\n <Button\n color=\"error\"\n disabled={offline || busy}\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Void this sale?',\n description:\n 'Every payment taken on it is handed back: cards are refunded, gift ' +\n 'cards and store credit re-credited and room charges removed. Hand back any cash.',\n confirmationText: 'Void sale',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const result = await run('void')\n if (result) {\n notify('Sale voided', 'info')\n props.onVoided()\n }\n }}\n sx={{ minHeight: POS_TOUCH_PX, alignSelf: 'flex-start' }}\n >\n {'Void sale'}\n </Button>\n </>\n ) : null}\n\n <PosCashDialog\n open={dialog === 'cash'}\n dueCents={chargeCents}\n tipCents={tipCents}\n busy={busy}\n onClose={() => setDialog(null)}\n onTake={async (tenderedCents) => {\n const result = await run(\n 'cash',\n {\n tenderedCents,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n tipCents,\n },\n true,\n )\n if (result) {\n setDialog(null)\n const change = result.sale.payments.find((payment) => payment.id === result.paymentId)?.changeCents\n if (change) notify(`Change due: ${usd(change)}`, 'success')\n }\n }}\n />\n <PosGiftCardDialog\n open={dialog === 'gift'}\n busy={busy}\n onClose={() => setDialog(null)}\n onCheck={async (code) => {\n try {\n return await posGiftCardBalance(user, hostId, code)\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not read that card', 'warning')\n return null\n }\n }}\n onApply={async (code) => {\n const result = await run('gift-card', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n />\n <PosCreditDialog\n open={dialog === 'credit' && Boolean(creditProvider)}\n label={creditProvider?.label ?? 'Store credit'}\n canLookup={Boolean(creditProvider?.lookup)}\n busy={busy}\n onClose={() => setDialog(null)}\n onLookup={async (query) => {\n if (!creditProvider) return null\n try {\n return (await posCreditLookup(user, hostId, creditProvider.providerId, query)).accounts\n } catch (error) {\n notify(error instanceof PosRequestError ? error.message : 'Could not look that up', 'warning')\n return null\n }\n }}\n onApplyCode={async (code) => {\n const result = await run('credit', { code, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) }, true)\n if (result) setDialog(null)\n }}\n onApplyAccount={async (account) => {\n if (!creditProvider) return\n const result = await run(\n 'credit',\n {\n providerId: creditProvider.providerId,\n reference: account.reference,\n ...(typedCents > 0 ? { amountCents: chargeCents } : {}),\n },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosFolioDialog\n open={dialog === 'folio'}\n amountCents={chargeCents}\n stays={props.stays}\n busy={busy}\n onClose={() => setDialog(null)}\n onCharge={async (reservationId) => {\n const result = await run(\n 'folio',\n { reservationId, ...(typedCents > 0 ? { amountCents: chargeCents } : {}) },\n true,\n )\n if (result) setDialog(null)\n }}\n />\n <PosQrDialog url={qr?.url ?? ''} amountCents={qr?.amountCents ?? 0} onClose={() => setQr(null)} />\n <PosKeyedCardDialog\n clientSecret={keyed?.clientSecret ?? ''}\n publishableKey={context?.publishableKey ?? ''}\n amountCents={keyed?.amountCents ?? 0}\n onClose={async () => {\n const open = keyed\n setKeyed(null)\n // Closing without paying releases the amount for another tender.\n if (open) await run('cancel', { paymentId: open.paymentId })\n }}\n onConfirmed={async () => {\n const open = keyed\n setKeyed(null)\n if (open) await run('status', { paymentId: open.paymentId })\n }}\n />\n </Stack>\n )\n}\nPosTenderPanel.displayName = 'PosTenderPanel'\n"],"names":["Alert","Box","Button","Chip","Divider","MenuItem","Stack","TextField","Typography","useConfirmationContext","useCallback","useEffect","useRef","useState","CommerceModel","centsFromInput","newAttemptKey","posCreditLookup","posGiftCardBalance","posNativeBridge","posTender","PosRequestError","usd","POS_TOUCH_PX","PosCashDialog","PosCreditDialog","PosFolioDialog","PosGiftCardDialog","PosKeyedCardDialog","PosQrDialog","STATUS_LABEL","pending","succeeded","failed","canceled","reversed","STATUS_COLOR","PosTenderPanel","props","context","user","hostId","sale","display","onSale","notify","settings","amount","setAmount","tipCents","setTipCents","busy","setBusy","dialog","setDialog","creditProvider","setCreditProvider","qr","setQr","keyed","setKeyed","readerId","setReaderId","inFlight","confirm","onTipChange","readers","filter","reader","registerId","length","find","id","typedCents","chargeCents","Math","min","tenderableCents","paid","status","offline","run","action","body","starts","current","result","orderId","cashierAssertion","undefined","error","message","payments","payment","isCardPaymentMethod","method","pendingKey","map","join","latest","timer","setInterval","split","paymentId","clearInterval","readerWaiting","some","connected","asking","show","mode","processing","askTip","base","answer","ask","tip","baseCents","percentages","tipPercentages","allowCustom","startCardPresent","amountCents","startBridge","bridge","paymentIntentId","clientSecret","collected","collectCardPayment","startKeyed","startLink","url","checkoutUrl","tipOn","Boolean","tippingEnabled","spacing","sx","minHeight","justifyContent","alignItems","variant","component","totalCents","dueCents","color","paidCents","aria-label","gap","flexWrap","flex","minWidth","describeOrderPayment","atMs","changeCents","size","label","onClick","livemode","terminal","testMode","failureMessage","width","severity","onSellOffline","direction","placeholder","toFixed","value","onChange","event","target","replace","helperText","slotProps","htmlInput","inputMode","rowGap","mr","disabled","pct","posTipFromPercent","gridTemplateColumns","available","publishableKey","credits","credit","providerId","stays","select","confirmed","title","description","confirmationText","confirmationButtonProps","then","catch","onVoided","alignSelf","open","onClose","onTake","tenderedCents","change","onCheck","code","onApply","canLookup","lookup","onLookup","query","accounts","onApplyCode","onApplyAccount","account","reference","onCharge","reservationId","onConfirmed","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;;AAEA,SACEA,KAAK,EACLC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,OAAO,EACPC,QAAQ,EACRC,KAAK,EACLC,SAAS,EACTC,UAAU,QACL,gBAAe;AACtB,SAASC,sBAAsB,QAAQ,uBAAsB;AAC7D,SAASC,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAChE,YAAYC,mBAAmB,0BAAgB;AAC/C,SACEC,cAAc,EACdC,aAAa,EACbC,eAAe,EACfC,kBAAkB,EAClBC,eAAe,EACfC,SAAS,EACTC,eAAe,EACfC,GAAG,QAKE,eAAW;AAClB,SAASC,YAAY,QAAQ,kCAA8B;AAC3D,SACEC,aAAa,EACbC,eAAe,EACfC,cAAc,EACdC,iBAAiB,EACjBC,kBAAkB,EAClBC,WAAW,QACN,oCAAgC;AAKvC,MAAMC,eAAiE;IACrEC,SAAS;IACTC,WAAW;IACXC,QAAQ;IACRC,UAAU;IACVC,UAAU;AACZ;AAEA,MAAMC,eAGF;IACFL,SAAS;IACTC,WAAW;IACXC,QAAQ;IACRC,UAAU;IACVC,UAAU;AACZ;AA4BA;;;;;CAKC,GACD,OAAO,SAASE,eAAeC,KAA0B;;QAiT5CC,mBAuEFA;IAvXT,MAAM,EAAEC,IAAI,EAAEC,MAAM,EAAEC,IAAI,EAAEH,OAAO,EAAEI,OAAO,EAAEC,MAAM,EAAEC,MAAM,EAAE,GAAGP;IACjE,MAAMQ,WAAWP,2BAAAA,QAASO,QAAQ;IAClC,MAAM,CAACC,QAAQC,UAAU,GAAGnC,SAAS;IACrC,MAAM,CAACoC,UAAUC,YAAY,GAAGrC,SAAS;IACzC,MAAM,CAACsC,MAAMC,QAAQ,GAAGvC,SAAS;IACjC,MAAM,CAACwC,QAAQC,UAAU,GAAGzC,SAAsD;IAClF,6DAA6D;IAC7D,MAAM,CAAC0C,gBAAgBC,kBAAkB,GAAG3C,SAC1C;IAEF,MAAM,CAAC4C,IAAIC,MAAM,GAAG7C,SAAsD;IAC1E,MAAM,CAAC8C,OAAOC,SAAS,GAAG/C,SACxB;IAEF,MAAM,CAACgD,UAAUC,YAAY,GAAGjD,SAAS;IACzC,MAAMkD,WAAWnD,OAAO;IACxB,MAAM,EAAEoD,OAAO,EAAE,GAAGvD;IACpB,MAAM,EAAEwD,WAAW,EAAE,GAAG3B;IACxB3B,UAAU;QACRsD,+BAAAA,YAAchB;IAChB,GAAG;QAACgB;QAAahB;KAAS;IAE1B,MAAMiB,UAAU,SAAC3B,2BAAAA,QAAS2B,OAAO,mBAAI,EAAE,EAAEC,MAAM,CAC7C,CAACC,SAAW,CAACA,OAAOC,UAAU,IAAID,OAAOC,UAAU,KAAK/B,MAAM+B,UAAU;IAE1E1D,UAAU;QACR,IAAI,CAACkD,YAAYK,QAAQI,MAAM,EAAE;;gBACnBJ;YAAZJ,qBAAYI,gBAAAA,QAAQK,IAAI,CAAC,CAACH,SAAWA,OAAOC,UAAU,KAAK/B,MAAM+B,UAAU,sBAA/DH,cAAkEM,EAAE,mBAAIN,OAAO,CAAC,EAAE,CAACM,EAAE;QACnG;IACF,GAAG;QAACX;QAAUK;QAAS5B,MAAM+B,UAAU;KAAC;IAExC,wEAAwE;IACxE,yBAAyB;IACzB,MAAMI,aAAa1D,eAAegC;IAClC,MAAM2B,cAAcD,aAAa,IAAIE,KAAKC,GAAG,CAACH,YAAY/B,KAAKmC,eAAe,IAAInC,KAAKmC,eAAe;IACtG,MAAMC,OAAOpC,KAAKqC,MAAM,KAAK;IAC7B,MAAMC,UAAU1C,MAAM0C,OAAO,KAAK;IAElC,MAAMC,MAAMvE,YACV,OACEwE,QACAC,OAAgC,CAAC,CAAC,EAClCC,SAAS,KAAK;QAEd,IAAIrB,SAASsB,OAAO,EAAE,OAAO;QAC7BtB,SAASsB,OAAO,GAAG;QACnBjC,QAAQ;QACR,IAAI;YACF,MAAMkC,SAAS,MAAMlE,UACnBoB,MACAC,QACAC,KAAK6C,OAAO,EACZL,QACAE,UAAU9C,MAAMkD,gBAAgB,GAAG,aAAKL;gBAAMK,kBAAkBlD,MAAMkD,gBAAgB;iBAAKL,MAC3FC,SAASpE,kBAAkByE;YAE7B7C,OAAO0C,OAAO5C,IAAI;YAClB,IAAI0C,QAAQ;gBACVpC,UAAU;gBACVE,YAAY;YACd;YACA,OAAOoC;QACT,EAAE,OAAOI,OAAO;YACd7C,OAAO6C,iBAAiBrE,kBAAkBqE,MAAMC,OAAO,GAAG,wBAAwB;YAClF,OAAO;QACT,SAAU;YACR5B,SAASsB,OAAO,GAAG;YACnBjC,QAAQ;QACV;IACF,GACA;QAACZ;QAAMC;QAAQC,KAAK6C,OAAO;QAAE3C;QAAQC;QAAQP,MAAMkD,gBAAgB;KAAC;IAGtE,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,MAAMzD,UAAUW,KAAKkD,QAAQ,CAACzB,MAAM,CAClC,CAAC0B,UAAYA,QAAQd,MAAM,KAAK,aAAajE,cAAcgF,mBAAmB,CAACD,QAAQE,MAAM;IAE/F,MAAMC,aAAajE,QAAQkE,GAAG,CAAC,CAACJ,UAAYA,QAAQrB,EAAE,EAAE0B,IAAI,CAAC;IAC7D,MAAMC,SAASvF,OAAO;QAAE4B;QAAMI;IAAO;IACrCuD,OAAOd,OAAO,GAAG;QAAE7C;QAAMI;IAAO;IAChCjC,UAAU;QACR,IAAI,CAACqF,YAAY,OAAOP;QACxB,MAAMW,QAAQC,YAAY;YACxB,KAAK,MAAM7B,MAAMwB,WAAWM,KAAK,CAAC,KAAM;gBACtC,IAAI;oBACF,MAAMhB,SAAS,MAAMlE,UAAU+E,OAAOd,OAAO,CAAC7C,IAAI,EAAEC,QAAQC,KAAK6C,OAAO,EAAE,UAAU;wBAClFgB,WAAW/B;oBACb;oBACA2B,OAAOd,OAAO,CAACzC,MAAM,CAAC0C,OAAO5C,IAAI;gBACnC,EAAE,eAAM;gBACN,4BAA4B;gBAC9B;YACF;QACF,GAAG;QACH,OAAO,IAAM8D,cAAcJ;IAC7B,GAAG;QAACJ;QAAYvD;QAAQC,KAAK6C,OAAO;KAAC;IAErC,0EAA0E;IAC1E,6BAA6B;IAC7B,MAAMkB,gBAAgB1E,QAAQ2E,IAAI,CAAC,CAACb,UAAYA,QAAQE,MAAM,KAAK;IACnEpF,UAAU;QACR,IAAI,CAACgC,QAAQgE,SAAS,IAAIhE,QAAQiE,MAAM,EAAE;QAC1C,IAAIH,eAAe;YACjB,KAAK9D,QAAQkE,IAAI,CAAC;gBAAEC,MAAM;gBAAcC,YAAY;oBAAEpB,SAAS;gBAAgD;YAAE;QACnH;IACF,GAAG;QAACc;QAAe9D;KAAQ;IAE3B,MAAMqE,SAAStG,YAAY;QACzB,MAAMuG,OAAOvC;QACb,IAAI,CAAEuC,CAAAA,OAAO,CAAA,KAAM,CAACnE,UAAU;QAC9B,MAAMoE,SAAS,MAAMvE,QAAQwE,GAAG,CAAC;YAC/BL,MAAM;YACNM,KAAK;gBAAEC,WAAWJ;gBAAMK,aAAaxE,SAASyE,cAAc;gBAAEC,aAAa;YAAK;QAClF;QACA,IAAIN,QAAQ;gBACEA;YAAZhE,aAAYgE,mBAAAA,OAAOjE,QAAQ,YAAfiE,mBAAmB;YAC/BrE,OAAOqE,OAAOjE,QAAQ,GAAG,CAAC,KAAK,EAAE3B,IAAI4F,OAAOjE,QAAQ,GAAG,GAAG,UAAU;QACtE;IACF,GAAG;QAACyB;QAAa5B;QAAUH;QAASE;KAAO;IAE3C,MAAM4E,mBAAmB/G,YAAY;QACnC,IAAI,CAACmD,UAAU;QACf,MAAMoB,IAAI,gBAAgB;YAAEyC,aAAahD;YAAazB;YAAUY;QAAS,GAAG;IAC9E,GAAG;QAACoB;QAAKP;QAAazB;QAAUY;KAAS;IAEzC,MAAM8D,cAAcjH,YAAY;QAC9B,MAAMkH,SAASzG;QACf,IAAI,CAACyG,QAAQ;QACb,MAAMF,cAAchD;QACpB,MAAMY,SAAS,MAAML,IAAI,oBAAoB;YAAEyC;YAAazE;QAAS,GAAG;QACxE,IAAI,EAACqC,0BAAAA,OAAQuC,eAAe,KAAI,CAACvC,OAAOwC,YAAY,IAAI,CAACxC,OAAOiB,SAAS,EAAE;QAC3E,IAAI;YACF,MAAMwB,YAAY,MAAMH,OAAOI,kBAAkB,CAAC;gBAChDH,iBAAiBvC,OAAOuC,eAAe;gBACvCC,cAAcxC,OAAOwC,YAAY;gBACjCJ,aAAaA,cAAczE;YAC7B;YACA,IAAI8E,UAAUhD,MAAM,KAAK,aAAa;oBAC7BgD;gBAAPlF,QAAOkF,qBAAAA,UAAUpC,OAAO,YAAjBoC,qBAAqB,2BAA2B;YACzD;QACF,SAAU;YACR,gEAAgE;YAChE,oDAAoD;YACpD,MAAM9C,IAAI,UAAU;gBAAEsB,WAAWjB,OAAOiB,SAAS;YAAC;QACpD;IACF,GAAG;QAACtB;QAAKP;QAAazB;QAAUJ;KAAO;IAEvC,MAAMoF,aAAavH,YAAY;QAC7B,MAAMgH,cAAchD;QACpB,MAAMY,SAAS,MAAML,IAAI,cAAc;YAAEyC;YAAazE;QAAS,GAAG;QAClE,IAAIqC,CAAAA,0BAAAA,OAAQwC,YAAY,KAAIxC,OAAOiB,SAAS,EAAE;YAC5C3C,SAAS;gBAAEkE,cAAcxC,OAAOwC,YAAY;gBAAEJ,aAAaA,cAAczE;gBAAUsD,WAAWjB,OAAOiB,SAAS;YAAC;QACjH;IACF,GAAG;QAACtB;QAAKP;QAAazB;KAAS;IAE/B,MAAMiF,YAAYxH,YAAY;YAGhB4E;QAFZ,MAAMoC,cAAchD;QACpB,MAAMY,SAAS,MAAML,IAAI,aAAa;YAAEyC;YAAazE;QAAS,GAAG;QACjE,MAAMkF,MAAM7C,2BAAAA,6BAAAA,OAAQ5C,IAAI,CAACkD,QAAQ,CAACrB,IAAI,CAAC,CAACsB,UAAYA,QAAQrB,EAAE,KAAKc,OAAOiB,SAAS,sBAAvEjB,2BAA0E8C,WAAW;QACjG,IAAID,KAAKzE,MAAM;YAAEyE;YAAKT,aAAaA,cAAczE;QAAS;IAC5D,GAAG;QAACgC;QAAKP;QAAazB;KAAS;IAE/B,MAAMoF,QAAQC,QAAQxF,4BAAAA,SAAUyF,cAAc,KAAK,CAACzD;IAEpD,qBACE,MAACxE;QAAMkI,SAAS;QAAKC,IAAI;YAAEC,WAAW;QAAE;;0BACtC,MAACzI;gBAAIwI,IAAI;oBAAE9F,SAAS;oBAAQgG,gBAAgB;oBAAiBC,YAAY;gBAAW;;kCAClF,KAACpI;wBAAWqI,SAAQ;kCAAM/D,OAAO,SAAS;;kCAC1C,KAACtE;wBAAWqI,SAAQ;wBAAKC,WAAU;kCAChCxH,IAAIwD,OAAOpC,KAAKqG,UAAU,GAAGrG,KAAKsG,QAAQ;;;;0BAG/C,KAACxI;gBAAWqI,SAAQ;gBAAQI,OAAM;0BAC/B,CAAC,MAAM,EAAE3H,IAAIoB,KAAKqG,UAAU,EAAE,QAAQ,EAAEzH,IAAIoB,KAAKwG,SAAS,GAAG,GAC3DxG,CAAAA,KAAKO,QAAQ,GAAG,CAAC,QAAQ,EAAE3B,IAAIoB,KAAKO,QAAQ,GAAG,GAAG,EAAC;;YAGvDP,KAAKkD,QAAQ,CAACtB,MAAM,iBACnB,KAAChE;gBAAMkI,SAAS;gBAAGW,cAAW;0BAC3BzG,KAAKkD,QAAQ,CAACK,GAAG,CAAC,CAACJ;wBAiBwDtD;yCAhB1E,MAACtC;wBAAqBwI,IAAI;4BAAE9F,SAAS;4BAAQiG,YAAY;4BAAUQ,KAAK;4BAAGC,UAAU;wBAAO;;0CAC1F,MAAC7I;gCAAWqI,SAAQ;gCAAQJ,IAAI;oCAAEa,MAAM;oCAAGC,UAAU;gCAAI;;oCACtDzI,cAAc0I,oBAAoB,CAAC,aAAK3D;wCAAS4D,MAAM;;oCACvD5D,QAAQ6D,WAAW,GAAG,CAAC,UAAU,EAAEpI,IAAIuE,QAAQ6D,WAAW,GAAG,GAAG;;;0CAEnE,KAACvJ;gCAAKwJ,MAAK;gCAAQC,OAAO9H,YAAY,CAAC+D,QAAQd,MAAM,CAAC;gCAAEkE,OAAO7G,YAAY,CAACyD,QAAQd,MAAM,CAAC;;4BAC1Fc,QAAQd,MAAM,KAAK,aAAajE,cAAcgF,mBAAmB,CAACD,QAAQE,MAAM,kBAC/E;;oCACGF,QAAQE,MAAM,KAAK,eAAeF,QAAQuC,WAAW,iBACpD,KAAClI;wCACCyJ,MAAK;wCACLE,SAAS,IAAMnG,MAAM;gDAAEyE,KAAKtC,QAAQuC,WAAW;gDAAYV,aAAa7B,QAAQ6B,WAAW;4CAAC;kDAE3F;yCAED;oCACH7B,QAAQE,MAAM,KAAK,kBAAkBF,QAAQiE,QAAQ,KAAK,UAASvH,4BAAAA,oBAAAA,QAASwH,QAAQ,qBAAjBxH,kBAAmByH,QAAQ,kBAC7F,KAAC9J;wCAAOyJ,MAAK;wCAAQE,SAAS,IAAM,KAAK5E,IAAI,YAAY;gDAAEsB,WAAWV,QAAQrB,EAAE;4CAAC;kDAC9E;yCAED;kDACJ,KAACtE;wCAAOyJ,MAAK;wCAAQV,OAAM;wCAAQY,SAAS,IAAM,KAAK5E,IAAI,UAAU;gDAAEsB,WAAWV,QAAQrB,EAAE;4CAAC;kDAC1F;;;iCAGH;4BACHqB,QAAQd,MAAM,KAAK,YAAYc,QAAQE,MAAM,KAAK,kBAAkB,CAACjB,qBACpE,KAAC5E;gCAAOyJ,MAAK;gCAAQE,SAAS,IAAM,KAAK5E,IAAI,SAAS;wCAAEsB,WAAWV,QAAQrB,EAAE;oCAAC;0CAC3E;iCAED;4BACHqB,QAAQoE,cAAc,IAAIpE,QAAQd,MAAM,KAAK,yBAC5C,KAACvE;gCAAWqI,SAAQ;gCAAUI,OAAM;gCAAQR,IAAI;oCAAEyB,OAAO;gCAAE;0CACxDrE,QAAQoE,cAAc;iCAEvB;;uBAnCIpE,QAAQrB,EAAE;;iBAuCtB;YAEHQ,WAAW,CAACF,qBACX,KAAC9E;gBACCmK,UAAS;gBACTjF,QACE5C,MAAM8H,aAAa,IAAI1H,KAAKkD,QAAQ,CAACtB,MAAM,KAAK,kBAC9C,KAACpE;oBAAO+I,OAAM;oBAAUU,MAAK;oBAAQE,SAASvH,MAAM8H,aAAa;8BAC9D;qBAED;0BAGL1H,KAAKkD,QAAQ,CAACtB,MAAM,KAAK,IACtB,yGACA,0EACA,sFACA;iBAEJ;YACH,CAACQ,qBACA;;kCACE,KAAC1E;kCACD,KAACE;wBAAM+J,WAAU;wBAAM7B,SAAS;wBAAGC,IAAI;4BAAEG,YAAY;wBAAS;kCAC5D,cAAA,KAACrI;4BACCqJ,OAAM;4BACNU,aAAa,AAAC5H,CAAAA,KAAKmC,eAAe,GAAG,GAAE,EAAG0F,OAAO,CAAC;4BAClDC,OAAOzH;4BACP0H,UAAU,CAACC,QAAU1H,UAAU0H,MAAMC,MAAM,CAACH,KAAK,CAACI,OAAO,CAAC,YAAY;4BACtEnC,IAAI;gCAAEa,MAAM;4BAAE;4BACduB,YACEpG,aAAa,KAAKA,aAAa/B,KAAKmC,eAAe,GAC/C,CAAC,OAAO,EAAEvD,IAAIoB,KAAKmC,eAAe,GAAGJ,YAAY,WAAW,CAAC,GAC7D;4BAENqG,WAAW;gCAAEC,WAAW;oCAAEC,WAAW;gCAAU;4BAAE;;;oBAGpD3C,sBACC,MAAC/H;wBAAM+J,WAAU;wBAAM7B,SAAS;wBAAGC,IAAI;4BAAEG,YAAY;4BAAUS,UAAU;4BAAQ4B,QAAQ;wBAAE;;0CACzF,KAACzK;gCAAWqI,SAAQ;gCAAQJ,IAAI;oCAAEyC,IAAI;gCAAE;0CACrC,CAAC,IAAI,EAAE5J,IAAI2B,WAAW;;4BAExBN,QAAQgE,SAAS,iBAChB,KAACzG;gCACC2I,SAAQ;gCACRgB,SAAS,IAAM,KAAK7C;gCACpBmE,UAAUnG,WAAW7B,QAAQmF,QAAQ3F,QAAQiE,MAAM;gCACnD6B,IAAI;oCAAEC,WAAWnH;gCAAa;0CAE7BoB,QAAQiE,MAAM,KAAK,QAAQ,0BAA0B;iCAEtD;4BACH,UAAC9D,4BAAAA,SAAUyE,cAAc,oBAAI,EAAE,EAAEtB,GAAG,CAAC,CAACmF,oBACrC,KAAClL;oCAEC2I,SAAS5F,aAAanC,cAAcuK,iBAAiB,CAAC3G,aAAa0G,QAAQnI,WAAW,IAAI,cAAc;oCACxG4G,SAAS,IAAM3G,YAAYpC,cAAcuK,iBAAiB,CAAC3G,aAAa0G;oCACxE3C,IAAI;wCAAEC,WAAWnH;oCAAa;8CAE7B,GAAG6J,IAAI,CAAC,CAAC;mCALLA;0CAQT,KAAClL;gCAAO2J,SAAS,IAAM3G,YAAY;gCAAIuF,IAAI;oCAAEC,WAAWnH;gCAAa;0CAClE;;;yBAGH;kCACJ,MAACtB;wBACCwI,IAAI;4BACF9F,SAAS;4BACTyG,KAAK;4BACLkC,qBAAqB;wBACvB;;0CAEA,KAACpL;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAMvG,UAAU;gCACzBmF,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;;4BAEFnG,CAAAA,4BAAAA,oBAAAA,QAASwH,QAAQ,qBAAjBxH,kBAAmBgJ,SAAS,KAAIrH,QAAQI,MAAM,iBAC7C,KAACpE;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe,KAAK,CAACb;gCAClDgG,SAAS,IAAM,KAAKpC;gCACpBgB,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;iCAED;4BACHvH,kCACC,KAACjB;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAM,KAAKlC;gCACpBc,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;iCAED;4BACHnG,CAAAA,2BAAAA,QAASiJ,cAAc,kBACtB,KAACtL;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAM,KAAK5B;gCACpBQ,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;iCAED;0CACJ,KAACxI;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAM,KAAK3B;gCACpBO,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;;0CAEH,KAACxI;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAMvG,UAAU;gCACzBmF,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;;4BAEF,UAACnG,2BAAAA,QAASkJ,OAAO,oBAAI,EAAE,EAAExF,GAAG,CAAC,CAACyF,uBAC7B,KAACxL;oCAEC2I,SAAQ;oCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;oCAC5CmF,SAAS;wCACPrG,kBAAkBkI;wCAClBpI,UAAU;oCACZ;oCACAmF,IAAI;wCAAEC,WAAW;oCAAG;8CAEnBgD,OAAO9B,KAAK;mCATR8B,OAAOC,UAAU;4BAYzBrJ,MAAMsJ,KAAK,CAACtH,MAAM,iBACjB,KAACpE;gCACC2I,SAAQ;gCACRsC,UAAUnG,WAAW7B,QAAQuB,eAAe;gCAC5CmF,SAAS,IAAMvG,UAAU;gCACzBmF,IAAI;oCAAEC,WAAW;gCAAG;0CAEnB;iCAED;;;oBAELnG,CAAAA,4BAAAA,qBAAAA,QAASwH,QAAQ,qBAAjBxH,mBAAmBgJ,SAAS,KAAIrH,QAAQI,MAAM,GAAG,kBAChD,KAAC/D;wBACCsL,MAAM;wBACNlC,MAAK;wBACLC,OAAM;wBACNY,OAAO3G;wBACP4G,UAAU,CAACC,QAAU5G,YAAY4G,MAAMC,MAAM,CAACH,KAAK;kCAElDtG,QAAQ+B,GAAG,CAAC,CAAC7B,uBACZ,KAAC/D;gCAAyBmK,OAAOpG,OAAOI,EAAE;0CACvC,GAAGJ,OAAOwF,KAAK,GAAGxF,OAAOW,MAAM,KAAK,WAAW,KAAK,cAAc;+BADtDX,OAAOI,EAAE;yBAK1B;oBACHN,QAAQwC,IAAI,CAAC,CAACtC,SAAWA,OAAOI,EAAE,KAAKX,YAAYO,OAAOW,MAAM,KAAK,0BACpE,KAAC/E;wBAAMmK,UAAS;kCAAW;yBACzB;kCACJ,KAACjK;wBACC+I,OAAM;wBACNkC,UAAUnG,WAAW7B;wBACrB0G,SAAS;4BACP,MAAMiC,YAAY,MAAM9H,QAAQ;gCAC9B+H,OAAO;gCACPC,aACE,wEACA;gCACFC,kBAAkB;gCAClBC,yBAAyB;oCAAEjD,OAAO;gCAAQ;4BAC5C,GACGkD,IAAI,CAAC,IAAM,MACXC,KAAK,CAAC,IAAM;4BACf,IAAI,CAACN,WAAW;4BAChB,MAAMxG,SAAS,MAAML,IAAI;4BACzB,IAAIK,QAAQ;gCACVzC,OAAO,eAAe;gCACtBP,MAAM+J,QAAQ;4BAChB;wBACF;wBACA5D,IAAI;4BAAEC,WAAWnH;4BAAc+K,WAAW;wBAAa;kCAEtD;;;iBAGH;0BAEJ,KAAC9K;gBACC+K,MAAMlJ,WAAW;gBACjB2F,UAAUtE;gBACVzB,UAAUA;gBACVE,MAAMA;gBACNqJ,SAAS,IAAMlJ,UAAU;gBACzBmJ,QAAQ,OAAOC;oBACb,MAAMpH,SAAS,MAAML,IACnB,QACA;wBACEyH;uBACIjI,aAAa,IAAI;wBAAEiD,aAAahD;oBAAY,IAAI,CAAC;wBACrDzB;wBAEF;oBAEF,IAAIqC,QAAQ;4BAEKA;wBADfhC,UAAU;wBACV,MAAMqJ,UAASrH,6BAAAA,OAAO5C,IAAI,CAACkD,QAAQ,CAACrB,IAAI,CAAC,CAACsB,UAAYA,QAAQrB,EAAE,KAAKc,OAAOiB,SAAS,sBAAtEjB,2BAAyEoE,WAAW;wBACnG,IAAIiD,QAAQ9J,OAAO,CAAC,YAAY,EAAEvB,IAAIqL,SAAS,EAAE;oBACnD;gBACF;;0BAEF,KAAChL;gBACC4K,MAAMlJ,WAAW;gBACjBF,MAAMA;gBACNqJ,SAAS,IAAMlJ,UAAU;gBACzBsJ,SAAS,OAAOC;oBACd,IAAI;wBACF,OAAO,MAAM3L,mBAAmBsB,MAAMC,QAAQoK;oBAChD,EAAE,OAAOnH,OAAO;wBACd7C,OAAO6C,iBAAiBrE,kBAAkBqE,MAAMC,OAAO,GAAG,4BAA4B;wBACtF,OAAO;oBACT;gBACF;gBACAmH,SAAS,OAAOD;oBACd,MAAMvH,SAAS,MAAML,IAAI,aAAa;wBAAE4H;uBAAUpI,aAAa,IAAI;wBAAEiD,aAAahD;oBAAY,IAAI,CAAC,IAAM;oBACzG,IAAIY,QAAQhC,UAAU;gBACxB;;0BAEF,KAAC7B;gBACC8K,MAAMlJ,WAAW,YAAYiF,QAAQ/E;gBACrCqG,KAAK,WAAErG,kCAAAA,eAAgBqG,KAAK,oBAAI;gBAChCmD,WAAWzE,QAAQ/E,kCAAAA,eAAgByJ,MAAM;gBACzC7J,MAAMA;gBACNqJ,SAAS,IAAMlJ,UAAU;gBACzB2J,UAAU,OAAOC;oBACf,IAAI,CAAC3J,gBAAgB,OAAO;oBAC5B,IAAI;wBACF,OAAO,AAAC,CAAA,MAAMtC,gBAAgBuB,MAAMC,QAAQc,eAAeoI,UAAU,EAAEuB,MAAK,EAAGC,QAAQ;oBACzF,EAAE,OAAOzH,OAAO;wBACd7C,OAAO6C,iBAAiBrE,kBAAkBqE,MAAMC,OAAO,GAAG,0BAA0B;wBACpF,OAAO;oBACT;gBACF;gBACAyH,aAAa,OAAOP;oBAClB,MAAMvH,SAAS,MAAML,IAAI,UAAU;wBAAE4H;uBAAUpI,aAAa,IAAI;wBAAEiD,aAAahD;oBAAY,IAAI,CAAC,IAAM;oBACtG,IAAIY,QAAQhC,UAAU;gBACxB;gBACA+J,gBAAgB,OAAOC;oBACrB,IAAI,CAAC/J,gBAAgB;oBACrB,MAAM+B,SAAS,MAAML,IACnB,UACA;wBACE0G,YAAYpI,eAAeoI,UAAU;wBACrC4B,WAAWD,QAAQC,SAAS;uBACxB9I,aAAa,IAAI;wBAAEiD,aAAahD;oBAAY,IAAI,CAAC,IAEvD;oBAEF,IAAIY,QAAQhC,UAAU;gBACxB;;0BAEF,KAAC5B;gBACC6K,MAAMlJ,WAAW;gBACjBqE,aAAahD;gBACbkH,OAAOtJ,MAAMsJ,KAAK;gBAClBzI,MAAMA;gBACNqJ,SAAS,IAAMlJ,UAAU;gBACzBkK,UAAU,OAAOC;oBACf,MAAMnI,SAAS,MAAML,IACnB,SACA;wBAAEwI;uBAAmBhJ,aAAa,IAAI;wBAAEiD,aAAahD;oBAAY,IAAI,CAAC,IACtE;oBAEF,IAAIY,QAAQhC,UAAU;gBACxB;;0BAEF,KAACzB;gBAAYsG,GAAG,WAAE1E,sBAAAA,GAAI0E,GAAG,oBAAI;gBAAIT,WAAW,WAAEjE,sBAAAA,GAAIiE,WAAW,oBAAI;gBAAG8E,SAAS,IAAM9I,MAAM;;0BACzF,KAAC9B;gBACCkG,YAAY,WAAEnE,yBAAAA,MAAOmE,YAAY,oBAAI;gBACrC0D,cAAc,WAAEjJ,2BAAAA,QAASiJ,cAAc,oBAAI;gBAC3C9D,WAAW,WAAE/D,yBAAAA,MAAO+D,WAAW,oBAAI;gBACnC8E,SAAS;oBACP,MAAMD,OAAO5I;oBACbC,SAAS;oBACT,iEAAiE;oBACjE,IAAI2I,MAAM,MAAMtH,IAAI,UAAU;wBAAEsB,WAAWgG,KAAKhG,SAAS;oBAAC;gBAC5D;gBACAmH,aAAa;oBACX,MAAMnB,OAAO5I;oBACbC,SAAS;oBACT,IAAI2I,MAAM,MAAMtH,IAAI,UAAU;wBAAEsB,WAAWgG,KAAKhG,SAAS;oBAAC;gBAC5D;;;;AAIR;AACAlE,eAAesL,WAAW,GAAG"}
|
|
@@ -27,8 +27,11 @@ export interface PosDisplayControl {
|
|
|
27
27
|
*/
|
|
28
28
|
ask: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<CommerceModel.PosDisplayResponse | null>;
|
|
29
29
|
cancelAsk: () => void;
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A fresh six-digit pairing code for a new customer display, or for a
|
|
32
|
+
* self-service kiosk (AGL-3623).
|
|
33
|
+
*/
|
|
34
|
+
pairingCode: (mode?: CommerceModel.PosDeviceMode) => Promise<{
|
|
32
35
|
code: string;
|
|
33
36
|
expiresAtMs: number;
|
|
34
37
|
}>;
|
|
@@ -135,12 +135,13 @@ import { newAttemptKey, posDisplayCall } from "./pos-api.js";
|
|
|
135
135
|
hostId,
|
|
136
136
|
registerId
|
|
137
137
|
]);
|
|
138
|
-
const pairingCode = useCallback(async ()=>{
|
|
138
|
+
const pairingCode = useCallback(async (mode = 'display')=>{
|
|
139
139
|
if (!user) throw new Error('Not signed in');
|
|
140
140
|
const result = await posDisplayCall(user, {
|
|
141
141
|
action: 'pairing-code',
|
|
142
142
|
hostId,
|
|
143
|
-
registerId
|
|
143
|
+
registerId,
|
|
144
|
+
mode
|
|
144
145
|
});
|
|
145
146
|
return result;
|
|
146
147
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/use-pos-display.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { newAttemptKey, posDisplayCall } from './pos-api'\n\ntype User = Parameters<typeof posDisplayCall>[0]\n\n/**\n * The tip the customer screen shows beside the sale (AGL-3608): the tips\n * already on its payments, plus one chosen for the payment about to be taken\n * (on the display or by the cashier), which the ledger does not hold until\n * that payment is recorded. Without the second part the screen read the\n * sale's total right after the customer added a tip, short by that tip.\n */\nexport function posDisplayTipCents(\n sale: { status: string; tipCents: number } | null | undefined,\n pendingTipCents: number,\n): number {\n if (!sale) return 0\n const pending = sale.status === 'paid' ? 0 : Math.max(0, Math.round(pendingTipCents) || 0)\n return Math.max(0, sale.tipCents) + pending\n}\n\n/** How long the register waits for the customer to answer a prompt. */\nexport const POS_DISPLAY_ANSWER_TIMEOUT_MS = 3 * 60 * 1000\n\nexport interface PosDisplayControl {\n /** A display for this register polled within the last two minutes. */\n connected: boolean\n /** The prompt the register is waiting on, if any. */\n asking: CommerceModel.PosDisplayMode | null\n /** Shows something on the display with no answer expected. */\n show: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<void>\n /**\n * Asks the customer (a tip or a receipt) and resolves with their answer,\n * or null when the cashier cancels or the customer does not answer.\n */\n ask: (\n state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>,\n ) => Promise<CommerceModel.PosDisplayResponse | null>\n cancelAsk: () => void\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos/use-pos-display.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { newAttemptKey, posDisplayCall } from './pos-api'\n\ntype User = Parameters<typeof posDisplayCall>[0]\n\n/**\n * The tip the customer screen shows beside the sale (AGL-3608): the tips\n * already on its payments, plus one chosen for the payment about to be taken\n * (on the display or by the cashier), which the ledger does not hold until\n * that payment is recorded. Without the second part the screen read the\n * sale's total right after the customer added a tip, short by that tip.\n */\nexport function posDisplayTipCents(\n sale: { status: string; tipCents: number } | null | undefined,\n pendingTipCents: number,\n): number {\n if (!sale) return 0\n const pending = sale.status === 'paid' ? 0 : Math.max(0, Math.round(pendingTipCents) || 0)\n return Math.max(0, sale.tipCents) + pending\n}\n\n/** How long the register waits for the customer to answer a prompt. */\nexport const POS_DISPLAY_ANSWER_TIMEOUT_MS = 3 * 60 * 1000\n\nexport interface PosDisplayControl {\n /** A display for this register polled within the last two minutes. */\n connected: boolean\n /** The prompt the register is waiting on, if any. */\n asking: CommerceModel.PosDisplayMode | null\n /** Shows something on the display with no answer expected. */\n show: (state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>) => Promise<void>\n /**\n * Asks the customer (a tip or a receipt) and resolves with their answer,\n * or null when the cashier cancels or the customer does not answer.\n */\n ask: (\n state: Omit<CommerceModel.PosDisplayState, 'updatedAtMs' | 'promptId'>,\n ) => Promise<CommerceModel.PosDisplayResponse | null>\n cancelAsk: () => void\n /**\n * A fresh six-digit pairing code for a new customer display, or for a\n * self-service kiosk (AGL-3623).\n */\n pairingCode: (mode?: CommerceModel.PosDeviceMode) => Promise<{ code: string; expiresAtMs: number }>\n}\n\n/**\n * The register's half of the customer display (AGL-3608). It writes the\n * display's state through `commerce/pos-display` and reads answers back the\n * same way; nothing here talks to Firestore, because the display state is\n * server-only (it can hold a customer's typed email address).\n */\nexport function usePosDisplay(\n user: User | null | undefined,\n hostId: string,\n registerId: string,\n): PosDisplayControl {\n const [connected, setConnected] = useState(false)\n const [asking, setAsking] = useState<CommerceModel.PosDisplayMode | null>(null)\n const cancelRef = useRef<(() => void) | null>(null)\n // The poll reads the latest session through a ref and is keyed on the uid,\n // so a refreshed user object does not restart it.\n const userRef = useRef(user)\n userRef.current = user\n const uid = (user as { uid?: string } | null | undefined)?.uid ?? ''\n\n useEffect(() => {\n if (!uid || !registerId) return undefined\n let active = true\n const check = async () => {\n const signedIn = userRef.current\n if (!signedIn) return\n try {\n const result = await posDisplayCall<{ connected: boolean }>(\n signedIn,\n { action: 'state', hostId, registerId },\n 'GET',\n )\n if (active) setConnected(Boolean(result.connected))\n } catch {\n if (active) setConnected(false)\n }\n }\n void check()\n const timer = setInterval(check, 15_000)\n return () => {\n active = false\n clearInterval(timer)\n }\n }, [uid, hostId, registerId])\n\n const show = useCallback<PosDisplayControl['show']>(\n async (state) => {\n if (!user || !registerId || !connected) return\n await posDisplayCall(user, { action: 'push', hostId, registerId, state }).catch(() => undefined)\n },\n [user, hostId, registerId, connected],\n )\n\n const cancelAsk = useCallback(() => {\n cancelRef.current?.()\n }, [])\n\n const ask = useCallback<PosDisplayControl['ask']>(\n async (state) => {\n if (!user || !registerId) return null\n cancelRef.current?.()\n const promptId = newAttemptKey().slice(0, 32)\n await posDisplayCall(user, {\n action: 'push',\n hostId,\n registerId,\n state: { ...state, promptId },\n })\n setAsking(state.mode)\n return await new Promise<CommerceModel.PosDisplayResponse | null>((resolve) => {\n let done = false\n const finish = (answer: CommerceModel.PosDisplayResponse | null) => {\n if (done) return\n done = true\n clearInterval(timer)\n clearTimeout(timeout)\n cancelRef.current = null\n setAsking(null)\n resolve(answer)\n }\n const timer = setInterval(async () => {\n try {\n const result = await posDisplayCall<{\n state: CommerceModel.PosDisplayState | null\n }>(user, { action: 'state', hostId, registerId }, 'GET')\n const response = result.state?.response\n if (response && response.promptId === promptId) finish(response)\n } catch {\n // A missed poll is retried on the next tick.\n }\n }, 1000)\n const timeout = setTimeout(() => finish(null), POS_DISPLAY_ANSWER_TIMEOUT_MS)\n cancelRef.current = () => finish(null)\n })\n },\n [user, hostId, registerId],\n )\n\n const pairingCode = useCallback(async (mode: CommerceModel.PosDeviceMode = 'display') => {\n if (!user) throw new Error('Not signed in')\n const result = await posDisplayCall<{ code: string; expiresAtMs: number }>(user, {\n action: 'pairing-code',\n hostId,\n registerId,\n mode,\n })\n return result\n }, [user, hostId, registerId])\n\n return { connected, asking, show, ask, cancelAsk, pairingCode }\n}\n"],"names":["useCallback","useEffect","useRef","useState","newAttemptKey","posDisplayCall","posDisplayTipCents","sale","pendingTipCents","pending","status","Math","max","round","tipCents","POS_DISPLAY_ANSWER_TIMEOUT_MS","usePosDisplay","user","hostId","registerId","connected","setConnected","asking","setAsking","cancelRef","userRef","current","uid","undefined","active","check","signedIn","result","action","Boolean","timer","setInterval","clearInterval","show","state","catch","cancelAsk","ask","promptId","slice","mode","Promise","resolve","done","finish","answer","clearTimeout","timeout","response","setTimeout","pairingCode","Error"],"mappings":"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"}
|
|
@@ -292,12 +292,12 @@ const EMPTY_ADDRESS = {
|
|
|
292
292
|
children: [
|
|
293
293
|
/*#__PURE__*/ _jsx(Typography, {
|
|
294
294
|
variant: "subtitle2",
|
|
295
|
-
children: 'Customer displays'
|
|
295
|
+
children: 'Customer displays and kiosks'
|
|
296
296
|
}),
|
|
297
297
|
/*#__PURE__*/ _jsx(Typography, {
|
|
298
298
|
variant: "body2",
|
|
299
299
|
color: "text.secondary",
|
|
300
|
-
children: 'Pair a tablet
|
|
300
|
+
children: 'Pair a tablet from the register: tap Pair display, choose Customer display or Self-service kiosk, and enter the code on the tablet.'
|
|
301
301
|
}),
|
|
302
302
|
registers.flatMap((register)=>{
|
|
303
303
|
var _displays_register_$id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-devices-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useFirestoreCollection, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { posDisplayCall, posReadersCall, PosRequestError } from './pos/pos-api'\n\ninterface ReaderRow {\n id: string\n label: string\n registerId: string | null\n deviceType: string | null\n serialNumber: string | null\n status: string\n livemode: boolean\n}\n\ninterface ReadersAnswer {\n available: boolean\n testMode: boolean\n locationReady: boolean\n readers: ReaderRow[]\n}\n\ninterface DisplayRow {\n id: string\n label: string\n createdAtMs: number\n lastSeenAtMs: number\n}\n\nexport interface PosDevicesCardProps {\n hostId: string\n}\n\nconst EMPTY_ADDRESS = { line1: '', line2: '', city: '', state: '', postalCode: '', country: 'US' }\n\n/**\n * The register's hardware (AGL-3607, AGL-3608): Stripe Terminal card readers\n * — registered with the code a reader shows, bound to a register, renamed,\n * removed — and the customer displays paired to each register, which can be\n * signed out. Readers appear only where card readers are offered at all.\n */\nexport function PosDevicesCard({ hostId }: PosDevicesCardProps) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n const [answer, setAnswer] = useState<ReadersAnswer | null>(null)\n const [displays, setDisplays] = useState<Record<string, DisplayRow[]>>({})\n const [adding, setAdding] = useState(false)\n const [code, setCode] = useState('')\n const [label, setLabel] = useState('')\n const [registerId, setRegisterId] = useState('')\n const [address, setAddress] = useState(EMPTY_ADDRESS)\n const [busy, setBusy] = useState(false)\n const [renaming, setRenaming] = useState<{ id: string; label: string } | null>(null)\n\n const notify = useCallback(\n (error: unknown, fallback: string) =>\n enqueueSnackbar(error instanceof PosRequestError ? error.message : fallback, {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const load = useCallback(\n async (refresh = false) => {\n if (!user) return\n try {\n setAnswer(await posReadersCall<ReadersAnswer>(user, { action: 'list', hostId, refresh }))\n } catch {\n setAnswer(null)\n }\n },\n [user, hostId],\n )\n const uid = user?.uid ?? ''\n useEffect(() => {\n void load(true)\n // Keyed on the person, not the session object (see the register page).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId])\n\n const registerIds = registers.map((register: any) => register.$id).join(',')\n useEffect(() => {\n if (!user || !registerIds) return\n let active = true\n void Promise.all(\n registerIds.split(',').map(async (id) => {\n const result = await posDisplayCall<{ displays: DisplayRow[] }>(user, {\n action: 'displays',\n hostId,\n registerId: id,\n }).catch(() => ({ displays: [] as DisplayRow[] }))\n return [id, result.displays] as const\n }),\n ).then((entries) => {\n if (active) setDisplays(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId, registerIds])\n\n const registerName = (id: string | null) =>\n registers.find((register: any) => register.$id === id)?.name ?? null\n\n const addReader = async () => {\n if (!user) return\n setBusy(true)\n try {\n await posReadersCall(user, {\n action: 'register',\n hostId,\n registrationCode: code.trim(),\n label: label.trim(),\n ...(registerId ? { registerId } : {}),\n ...(answer?.locationReady ? {} : { address }),\n })\n setAdding(false)\n setCode('')\n setLabel('')\n setRegisterId('')\n await load()\n } catch (error) {\n notify(error, 'The reader could not be added')\n } finally {\n setBusy(false)\n }\n }\n\n const readers = answer?.readers ?? []\n const showReaders = Boolean(answer?.available)\n\n return (\n <CardDisplay\n header={'POS devices'}\n help={pluginDocsHelp('pos', { anchor: '#card-readers' })}\n HeaderProps={\n showReaders\n ? {\n action: (\n <Button size=\"small\" onClick={() => setAdding(true)}>\n {'Add card reader'}\n </Button>\n ),\n }\n : undefined\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {showReaders ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Card readers'}</Typography>\n {readers.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {answer?.testMode\n ? 'No card readers yet. In test mode, add one with the code \"simulated-wpe\" to try a simulated reader.'\n : 'No card readers yet. Add a Stripe Reader S700 or BBPOS WisePOS E with the code it shows on screen.'}\n </Typography>\n ) : (\n readers.map((reader) => (\n <Stack\n key={reader.id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 160 }}>\n {reader.label}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {` · ${registerName(reader.registerId) ?? 'Any register'}` +\n (reader.livemode ? '' : ' · test')}\n </Typography>\n </Typography>\n <Chip\n size=\"small\"\n label={reader.status === 'online' ? 'Online' : 'Offline'}\n color={reader.status === 'online' ? 'success' : 'default'}\n />\n <TextField\n select\n size=\"small\"\n label=\"Register\"\n value={reader.registerId ?? ''}\n onChange={async (event) => {\n if (!user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: reader.id,\n registerId: event.target.value,\n })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be updated')\n }\n }}\n sx={{ minWidth: 140 }}\n >\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n onClick={() => setRenaming({ id: reader.id, label: reader.label })}\n >\n {'Rename'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this card reader?',\n description:\n `\"${reader.label}\" is removed from your account and stops taking payments. ` +\n 'To use it again, register it with a new code.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !user) return\n try {\n await posReadersCall(user, { action: 'remove', hostId, readerId: reader.id })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be removed')\n }\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n ))\n )}\n </Stack>\n ) : null}\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Customer displays'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pair a tablet facing your customer from the register: tap Pair display and enter the code on the tablet.'}\n </Typography>\n {registers.flatMap((register: any) =>\n (displays[register.$id] ?? []).map((display) => (\n <Stack key={`${register.$id}:${display.id}`} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${display.label} · ${register.name}`}\n </Typography>\n <Chip\n size=\"small\"\n label={Date.now() - display.lastSeenAtMs < 120_000 ? 'Connected' : 'Not connected'}\n color={Date.now() - display.lastSeenAtMs < 120_000 ? 'success' : 'default'}\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n if (!user) return\n try {\n await posDisplayCall(user, {\n action: 'revoke',\n hostId,\n registerId: register.$id,\n displayId: display.id,\n })\n setDisplays((prev) => ({\n ...prev,\n [register.$id]: (prev[register.$id] ?? []).filter((entry) => entry.id !== display.id),\n }))\n } catch (error) {\n notify(error, 'The display could not be signed out')\n }\n }}\n >\n {'Sign out'}\n </Button>\n </Stack>\n )),\n )}\n </Stack>\n </Stack>\n\n <Dialog open={Boolean(renaming)} onClose={() => setRenaming(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Rename card reader'}</DialogTitle>\n <DialogContent>\n <TextField\n label=\"Name\"\n value={renaming?.label ?? ''}\n onChange={(event) => setRenaming((prev) => (prev ? { ...prev, label: event.target.value } : prev))}\n fullWidth\n autoFocus\n sx={{ mt: 1 }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setRenaming(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!renaming?.label.trim()}\n onClick={async () => {\n if (!renaming || !user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: renaming.id,\n label: renaming.label.trim(),\n })\n setRenaming(null)\n await load()\n } catch (error) {\n notify(error, 'The reader could not be renamed')\n }\n }}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={adding} onClose={() => setAdding(false)} maxWidth=\"sm\" fullWidth>\n <DialogTitle>{'Add a card reader'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'On the reader, open Settings and choose Generate pairing code, then enter the code it shows.'}\n </Typography>\n <TextField\n label=\"Registration code\"\n value={code}\n onChange={(event) => setCode(event.target.value)}\n autoFocus\n slotProps={{ htmlInput: { autoComplete: 'off' } }}\n />\n <TextField label=\"Name\" placeholder=\"Front counter reader\" value={label} onChange={(event) => setLabel(event.target.value)} />\n <TextField select label=\"Register\" value={registerId} onChange={(event) => setRegisterId(event.target.value)}>\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n {answer && !answer.locationReady ? (\n <Box sx={{ display: 'grid', gap: 1.5, gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' } }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ gridColumn: '1 / -1' }}>\n {'Where the reader is used. Stripe sets the reader up for this country.'}\n </Typography>\n <TextField label=\"Street\" value={address.line1} onChange={(event) => setAddress({ ...address, line1: event.target.value })} sx={{ gridColumn: '1 / -1' }} />\n <TextField label=\"City\" value={address.city} onChange={(event) => setAddress({ ...address, city: event.target.value })} />\n <TextField label=\"State\" value={address.state} onChange={(event) => setAddress({ ...address, state: event.target.value })} />\n <TextField label=\"Postal code\" value={address.postalCode} onChange={(event) => setAddress({ ...address, postalCode: event.target.value })} />\n <TextField\n label=\"Country\"\n value={address.country}\n onChange={(event) => setAddress({ ...address, country: event.target.value.toUpperCase().slice(0, 2) })}\n />\n </Box>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setAdding(false)}>{'Cancel'}</Button>\n <Button variant=\"contained\" disabled={busy || !code.trim()} onClick={() => void addReader()}>\n {'Add reader'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nPosDevicesCard.displayName = 'PosDevicesCard'\n\nexport default PosDevicesCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","useFirestore","useFirestoreCollection","useUser","Box","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","limit","query","useCallback","useEffect","useState","posDisplayCall","posReadersCall","PosRequestError","EMPTY_ADDRESS","line1","line2","city","state","postalCode","country","PosDevicesCard","hostId","firestore","data","user","enqueueSnackbar","confirm","registerDocs","idField","registers","sort","a","b","String","name","localeCompare","answer","setAnswer","displays","setDisplays","adding","setAdding","code","setCode","label","setLabel","registerId","setRegisterId","address","setAddress","busy","setBusy","renaming","setRenaming","notify","error","fallback","message","variant","persist","load","refresh","action","uid","registerIds","map","register","$id","join","active","Promise","all","split","id","result","catch","then","entries","Object","fromEntries","registerName","find","addReader","registrationCode","trim","locationReady","readers","showReaders","Boolean","available","header","help","anchor","HeaderProps","size","onClick","undefined","contentGutterX","contentGutterY","spacing","length","color","testMode","reader","direction","sx","alignItems","flexWrap","rowGap","flex","minWidth","component","livemode","status","select","value","onChange","event","readerId","target","confirmed","title","description","confirmationText","confirmationButtonProps","flatMap","display","Date","now","lastSeenAtMs","displayId","prev","filter","entry","open","onClose","maxWidth","fullWidth","autoFocus","mt","disabled","flexDirection","gap","slotProps","htmlInput","autoComplete","placeholder","gridTemplateColumns","xs","sm","gridColumn","toUpperCase","slice","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-devices-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useFirestoreCollection, useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport { posDisplayCall, posReadersCall, PosRequestError } from './pos/pos-api'\n\ninterface ReaderRow {\n id: string\n label: string\n registerId: string | null\n deviceType: string | null\n serialNumber: string | null\n status: string\n livemode: boolean\n}\n\ninterface ReadersAnswer {\n available: boolean\n testMode: boolean\n locationReady: boolean\n readers: ReaderRow[]\n}\n\ninterface DisplayRow {\n id: string\n label: string\n createdAtMs: number\n lastSeenAtMs: number\n}\n\nexport interface PosDevicesCardProps {\n hostId: string\n}\n\nconst EMPTY_ADDRESS = { line1: '', line2: '', city: '', state: '', postalCode: '', country: 'US' }\n\n/**\n * The register's hardware (AGL-3607, AGL-3608): Stripe Terminal card readers\n * — registered with the code a reader shows, bound to a register, renamed,\n * removed — and the customer displays paired to each register, which can be\n * signed out. Readers appear only where card readers are offered at all.\n */\nexport function PosDevicesCard({ hostId }: PosDevicesCardProps) {\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { data: registerDocs } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'registers'), limit(25)),\n [firestore, hostId],\n { idField: '$id' },\n )\n const registers = [...(registerDocs ?? [])].sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n const [answer, setAnswer] = useState<ReadersAnswer | null>(null)\n const [displays, setDisplays] = useState<Record<string, DisplayRow[]>>({})\n const [adding, setAdding] = useState(false)\n const [code, setCode] = useState('')\n const [label, setLabel] = useState('')\n const [registerId, setRegisterId] = useState('')\n const [address, setAddress] = useState(EMPTY_ADDRESS)\n const [busy, setBusy] = useState(false)\n const [renaming, setRenaming] = useState<{ id: string; label: string } | null>(null)\n\n const notify = useCallback(\n (error: unknown, fallback: string) =>\n enqueueSnackbar(error instanceof PosRequestError ? error.message : fallback, {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const load = useCallback(\n async (refresh = false) => {\n if (!user) return\n try {\n setAnswer(await posReadersCall<ReadersAnswer>(user, { action: 'list', hostId, refresh }))\n } catch {\n setAnswer(null)\n }\n },\n [user, hostId],\n )\n const uid = user?.uid ?? ''\n useEffect(() => {\n void load(true)\n // Keyed on the person, not the session object (see the register page).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId])\n\n const registerIds = registers.map((register: any) => register.$id).join(',')\n useEffect(() => {\n if (!user || !registerIds) return\n let active = true\n void Promise.all(\n registerIds.split(',').map(async (id) => {\n const result = await posDisplayCall<{ displays: DisplayRow[] }>(user, {\n action: 'displays',\n hostId,\n registerId: id,\n }).catch(() => ({ displays: [] as DisplayRow[] }))\n return [id, result.displays] as const\n }),\n ).then((entries) => {\n if (active) setDisplays(Object.fromEntries(entries))\n })\n return () => {\n active = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uid, hostId, registerIds])\n\n const registerName = (id: string | null) =>\n registers.find((register: any) => register.$id === id)?.name ?? null\n\n const addReader = async () => {\n if (!user) return\n setBusy(true)\n try {\n await posReadersCall(user, {\n action: 'register',\n hostId,\n registrationCode: code.trim(),\n label: label.trim(),\n ...(registerId ? { registerId } : {}),\n ...(answer?.locationReady ? {} : { address }),\n })\n setAdding(false)\n setCode('')\n setLabel('')\n setRegisterId('')\n await load()\n } catch (error) {\n notify(error, 'The reader could not be added')\n } finally {\n setBusy(false)\n }\n }\n\n const readers = answer?.readers ?? []\n const showReaders = Boolean(answer?.available)\n\n return (\n <CardDisplay\n header={'POS devices'}\n help={pluginDocsHelp('pos', { anchor: '#card-readers' })}\n HeaderProps={\n showReaders\n ? {\n action: (\n <Button size=\"small\" onClick={() => setAdding(true)}>\n {'Add card reader'}\n </Button>\n ),\n }\n : undefined\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {showReaders ? (\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Card readers'}</Typography>\n {readers.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {answer?.testMode\n ? 'No card readers yet. In test mode, add one with the code \"simulated-wpe\" to try a simulated reader.'\n : 'No card readers yet. Add a Stripe Reader S700 or BBPOS WisePOS E with the code it shows on screen.'}\n </Typography>\n ) : (\n readers.map((reader) => (\n <Stack\n key={reader.id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}\n >\n <Typography variant=\"body2\" sx={{ flex: 1, minWidth: 160 }}>\n {reader.label}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {` · ${registerName(reader.registerId) ?? 'Any register'}` +\n (reader.livemode ? '' : ' · test')}\n </Typography>\n </Typography>\n <Chip\n size=\"small\"\n label={reader.status === 'online' ? 'Online' : 'Offline'}\n color={reader.status === 'online' ? 'success' : 'default'}\n />\n <TextField\n select\n size=\"small\"\n label=\"Register\"\n value={reader.registerId ?? ''}\n onChange={async (event) => {\n if (!user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: reader.id,\n registerId: event.target.value,\n })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be updated')\n }\n }}\n sx={{ minWidth: 140 }}\n >\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n <Button\n size=\"small\"\n onClick={() => setRenaming({ id: reader.id, label: reader.label })}\n >\n {'Rename'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this card reader?',\n description:\n `\"${reader.label}\" is removed from your account and stops taking payments. ` +\n 'To use it again, register it with a new code.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed || !user) return\n try {\n await posReadersCall(user, { action: 'remove', hostId, readerId: reader.id })\n await load()\n } catch (error) {\n notify(error, 'The reader could not be removed')\n }\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n ))\n )}\n </Stack>\n ) : null}\n <Stack spacing={1}>\n <Typography variant=\"subtitle2\">{'Customer displays and kiosks'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pair a tablet from the register: tap Pair display, choose Customer display or Self-service kiosk, and enter the code on the tablet.'}\n </Typography>\n {registers.flatMap((register: any) =>\n (displays[register.$id] ?? []).map((display) => (\n <Stack key={`${register.$id}:${display.id}`} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${display.label} · ${register.name}`}\n </Typography>\n <Chip\n size=\"small\"\n label={Date.now() - display.lastSeenAtMs < 120_000 ? 'Connected' : 'Not connected'}\n color={Date.now() - display.lastSeenAtMs < 120_000 ? 'success' : 'default'}\n />\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n if (!user) return\n try {\n await posDisplayCall(user, {\n action: 'revoke',\n hostId,\n registerId: register.$id,\n displayId: display.id,\n })\n setDisplays((prev) => ({\n ...prev,\n [register.$id]: (prev[register.$id] ?? []).filter((entry) => entry.id !== display.id),\n }))\n } catch (error) {\n notify(error, 'The display could not be signed out')\n }\n }}\n >\n {'Sign out'}\n </Button>\n </Stack>\n )),\n )}\n </Stack>\n </Stack>\n\n <Dialog open={Boolean(renaming)} onClose={() => setRenaming(null)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Rename card reader'}</DialogTitle>\n <DialogContent>\n <TextField\n label=\"Name\"\n value={renaming?.label ?? ''}\n onChange={(event) => setRenaming((prev) => (prev ? { ...prev, label: event.target.value } : prev))}\n fullWidth\n autoFocus\n sx={{ mt: 1 }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setRenaming(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!renaming?.label.trim()}\n onClick={async () => {\n if (!renaming || !user) return\n try {\n await posReadersCall(user, {\n action: 'update',\n hostId,\n readerId: renaming.id,\n label: renaming.label.trim(),\n })\n setRenaming(null)\n await load()\n } catch (error) {\n notify(error, 'The reader could not be renamed')\n }\n }}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={adding} onClose={() => setAdding(false)} maxWidth=\"sm\" fullWidth>\n <DialogTitle>{'Add a card reader'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {'On the reader, open Settings and choose Generate pairing code, then enter the code it shows.'}\n </Typography>\n <TextField\n label=\"Registration code\"\n value={code}\n onChange={(event) => setCode(event.target.value)}\n autoFocus\n slotProps={{ htmlInput: { autoComplete: 'off' } }}\n />\n <TextField label=\"Name\" placeholder=\"Front counter reader\" value={label} onChange={(event) => setLabel(event.target.value)} />\n <TextField select label=\"Register\" value={registerId} onChange={(event) => setRegisterId(event.target.value)}>\n <MenuItem value=\"\">{'Any register'}</MenuItem>\n {registers.map((register: any) => (\n <MenuItem key={register.$id} value={register.$id}>\n {register.name}\n </MenuItem>\n ))}\n </TextField>\n {answer && !answer.locationReady ? (\n <Box sx={{ display: 'grid', gap: 1.5, gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' } }}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ gridColumn: '1 / -1' }}>\n {'Where the reader is used. Stripe sets the reader up for this country.'}\n </Typography>\n <TextField label=\"Street\" value={address.line1} onChange={(event) => setAddress({ ...address, line1: event.target.value })} sx={{ gridColumn: '1 / -1' }} />\n <TextField label=\"City\" value={address.city} onChange={(event) => setAddress({ ...address, city: event.target.value })} />\n <TextField label=\"State\" value={address.state} onChange={(event) => setAddress({ ...address, state: event.target.value })} />\n <TextField label=\"Postal code\" value={address.postalCode} onChange={(event) => setAddress({ ...address, postalCode: event.target.value })} />\n <TextField\n label=\"Country\"\n value={address.country}\n onChange={(event) => setAddress({ ...address, country: event.target.value.toUpperCase().slice(0, 2) })}\n />\n </Box>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setAdding(false)}>{'Cancel'}</Button>\n <Button variant=\"contained\" disabled={busy || !code.trim()} onClick={() => void addReader()}>\n {'Add reader'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nPosDevicesCard.displayName = 'PosDevicesCard'\n\nexport default PosDevicesCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","useSnackbar","useFirestore","useFirestoreCollection","useUser","Box","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","limit","query","useCallback","useEffect","useState","posDisplayCall","posReadersCall","PosRequestError","EMPTY_ADDRESS","line1","line2","city","state","postalCode","country","PosDevicesCard","hostId","firestore","data","user","enqueueSnackbar","confirm","registerDocs","idField","registers","sort","a","b","String","name","localeCompare","answer","setAnswer","displays","setDisplays","adding","setAdding","code","setCode","label","setLabel","registerId","setRegisterId","address","setAddress","busy","setBusy","renaming","setRenaming","notify","error","fallback","message","variant","persist","load","refresh","action","uid","registerIds","map","register","$id","join","active","Promise","all","split","id","result","catch","then","entries","Object","fromEntries","registerName","find","addReader","registrationCode","trim","locationReady","readers","showReaders","Boolean","available","header","help","anchor","HeaderProps","size","onClick","undefined","contentGutterX","contentGutterY","spacing","length","color","testMode","reader","direction","sx","alignItems","flexWrap","rowGap","flex","minWidth","component","livemode","status","select","value","onChange","event","readerId","target","confirmed","title","description","confirmationText","confirmationButtonProps","flatMap","display","Date","now","lastSeenAtMs","displayId","prev","filter","entry","open","onClose","maxWidth","fullWidth","autoFocus","mt","disabled","flexDirection","gap","slotProps","htmlInput","autoComplete","placeholder","gridTemplateColumns","xs","sm","gridColumn","toUpperCase","slice","displayName"],"mappings":"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"}
|
|
@@ -14,11 +14,14 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
+
import type * as CommerceModel from '../../../model';
|
|
17
18
|
import { type PosDisplayBranding } from './pos-display-api';
|
|
18
19
|
/**
|
|
19
20
|
* The unpaired display (AGL-3608): six digits from the register's Customer
|
|
20
|
-
* display menu, exchanged once for this device's token.
|
|
21
|
+
* display menu, exchanged once for this device's token. A self-service kiosk
|
|
22
|
+
* (AGL-3623) pairs through the same screen with `mode="kiosk"`.
|
|
21
23
|
*/
|
|
22
|
-
export declare function PosDisplayPairingScreen({ onPaired, }: {
|
|
24
|
+
export declare function PosDisplayPairingScreen({ onPaired, mode, }: {
|
|
23
25
|
onPaired: (token: string, branding: PosDisplayBranding) => void;
|
|
26
|
+
mode?: CommerceModel.PosDeviceMode;
|
|
24
27
|
}): import("react").JSX.Element;
|
|
@@ -24,8 +24,10 @@ import { useState } from "react";
|
|
|
24
24
|
import { pairDisplay } from "./pos-display-api.js";
|
|
25
25
|
/**
|
|
26
26
|
* The unpaired display (AGL-3608): six digits from the register's Customer
|
|
27
|
-
* display menu, exchanged once for this device's token.
|
|
28
|
-
|
|
27
|
+
* display menu, exchanged once for this device's token. A self-service kiosk
|
|
28
|
+
* (AGL-3623) pairs through the same screen with `mode="kiosk"`.
|
|
29
|
+
*/ export function PosDisplayPairingScreen({ onPaired, mode = 'display' }) {
|
|
30
|
+
const noun = mode === 'kiosk' ? 'kiosk' : 'display';
|
|
29
31
|
const [code, setCode] = useState('');
|
|
30
32
|
const [busy, setBusy] = useState(false);
|
|
31
33
|
const [error, setError] = useState(null);
|
|
@@ -37,7 +39,7 @@ import { pairDisplay } from "./pos-display-api.js";
|
|
|
37
39
|
if (!ready || busy) return;
|
|
38
40
|
setBusy(true);
|
|
39
41
|
setError(null);
|
|
40
|
-
const result = await pairDisplay(code);
|
|
42
|
+
const result = await pairDisplay(code, mode);
|
|
41
43
|
setBusy(false);
|
|
42
44
|
const token = result.ok ? (_result_value = result.value) == null ? void 0 : _result_value.token : undefined;
|
|
43
45
|
setCode('');
|
|
@@ -65,7 +67,7 @@ import { pairDisplay } from "./pos-display-api.js";
|
|
|
65
67
|
sx: {
|
|
66
68
|
textAlign: 'center'
|
|
67
69
|
},
|
|
68
|
-
children:
|
|
70
|
+
children: `Pair this ${noun}`
|
|
69
71
|
}),
|
|
70
72
|
/*#__PURE__*/ _jsx(Typography, {
|
|
71
73
|
variant: "h6",
|
|
@@ -118,7 +120,7 @@ import { pairDisplay } from "./pos-display-api.js";
|
|
|
118
120
|
maxWidth: theme.spacing(48),
|
|
119
121
|
minHeight: theme.spacing(8)
|
|
120
122
|
}, theme.typography.h6),
|
|
121
|
-
children: busy ? 'Pairing…' :
|
|
123
|
+
children: busy ? 'Pairing…' : `Pair ${noun}`
|
|
122
124
|
})
|
|
123
125
|
]
|
|
124
126
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-display/pairing-screen.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { type FormEvent, useState } from 'react'\nimport { pairDisplay, type PosDisplayBranding } from './pos-display-api'\n\n/**\n * The unpaired display (AGL-3608): six digits from the register's Customer\n * display menu, exchanged once for this device's token
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../libs/plugins/commerce/src/lib/components/console/pos-display/pairing-screen.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { type FormEvent, useState } from 'react'\nimport type * as CommerceModel from '../../../model'\nimport { pairDisplay, type PosDisplayBranding } from './pos-display-api'\n\n/**\n * The unpaired display (AGL-3608): six digits from the register's Customer\n * display menu, exchanged once for this device's token. A self-service kiosk\n * (AGL-3623) pairs through the same screen with `mode=\"kiosk\"`.\n */\nexport function PosDisplayPairingScreen({\n onPaired,\n mode = 'display',\n}: {\n onPaired: (token: string, branding: PosDisplayBranding) => void\n mode?: CommerceModel.PosDeviceMode\n}) {\n const noun = mode === 'kiosk' ? 'kiosk' : 'display'\n const [code, setCode] = useState('')\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const ready = code.length === 6\n\n const submit = async (event: FormEvent) => {\n event.preventDefault()\n if (!ready || busy) return\n setBusy(true)\n setError(null)\n const result = await pairDisplay(code, mode)\n setBusy(false)\n const token = result.ok ? result.value?.token : undefined\n setCode('')\n if (token) {\n onPaired(token, result.value?.branding)\n return\n }\n setError(result.error ?? 'That code is not valid. Show a new code on the register.')\n }\n\n return (\n <Stack\n component=\"form\"\n onSubmit={submit}\n spacing={4}\n sx={{ minHeight: '100dvh', alignItems: 'center', justifyContent: 'center', px: 2 }}\n >\n <Typography variant=\"h3\" component=\"h1\" sx={{ textAlign: 'center' }}>\n {`Pair this ${noun}`}\n </Typography>\n <Typography variant=\"h6\" color=\"text.secondary\" sx={{ textAlign: 'center' }}>\n Enter the code shown on the register\n </Typography>\n <TextField\n value={code}\n onChange={(event) => setCode(event.target.value.replace(/\\D/g, '').slice(0, 6))}\n autoFocus\n autoComplete=\"one-time-code\"\n placeholder=\"000000\"\n slotProps={{\n htmlInput: {\n inputMode: 'numeric',\n pattern: '[0-9]*',\n maxLength: 6,\n 'aria-label': 'Pairing code',\n style: { textAlign: 'center' },\n },\n }}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n '& input': { ...theme.typography.h3, letterSpacing: theme.spacing(1) },\n })}\n />\n {error ? (\n <Alert severity=\"error\" sx={{ width: '100%', maxWidth: (theme) => theme.spacing(48) }}>\n {error}\n </Alert>\n ) : null}\n <Button\n type=\"submit\"\n variant=\"contained\"\n size=\"large\"\n disabled={!ready || busy}\n sx={(theme) => ({\n width: '100%',\n maxWidth: theme.spacing(48),\n minHeight: theme.spacing(8),\n ...theme.typography.h6,\n })}\n >\n {busy ? 'Pairing…' : `Pair ${noun}`}\n </Button>\n </Stack>\n )\n}\n"],"names":["Alert","Button","Stack","TextField","Typography","useState","pairDisplay","PosDisplayPairingScreen","onPaired","mode","noun","code","setCode","busy","setBusy","error","setError","ready","length","submit","event","result","preventDefault","token","ok","value","undefined","branding","component","onSubmit","spacing","sx","minHeight","alignItems","justifyContent","px","variant","textAlign","color","onChange","target","replace","slice","autoFocus","autoComplete","placeholder","slotProps","htmlInput","inputMode","pattern","maxLength","style","theme","width","maxWidth","typography","h3","letterSpacing","severity","type","size","disabled","h6"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,OAAOA,WAAW,sBAAqB;AACvC,OAAOC,YAAY,uBAAsB;AACzC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,eAAe,0BAAyB;AAC/C,OAAOC,gBAAgB,2BAA0B;AACjD,SAAyBC,QAAQ,QAAQ,QAAO;AAEhD,SAASC,WAAW,QAAiC,uBAAmB;AAExE;;;;CAIC,GACD,OAAO,SAASC,wBAAwB,EACtCC,QAAQ,EACRC,OAAO,SAAS,EAIjB;IACC,MAAMC,OAAOD,SAAS,UAAU,UAAU;IAC1C,MAAM,CAACE,MAAMC,QAAQ,GAAGP,SAAS;IACjC,MAAM,CAACQ,MAAMC,QAAQ,GAAGT,SAAS;IACjC,MAAM,CAACU,OAAOC,SAAS,GAAGX,SAAwB;IAClD,MAAMY,QAAQN,KAAKO,MAAM,KAAK;IAE9B,MAAMC,SAAS,OAAOC;YAaXC;YANiBA;QAN1BD,MAAME,cAAc;QACpB,IAAI,CAACL,SAASJ,MAAM;QACpBC,QAAQ;QACRE,SAAS;QACT,MAAMK,SAAS,MAAMf,YAAYK,MAAMF;QACvCK,QAAQ;QACR,MAAMS,QAAQF,OAAOG,EAAE,IAAGH,gBAAAA,OAAOI,KAAK,qBAAZJ,cAAcE,KAAK,GAAGG;QAChDd,QAAQ;QACR,IAAIW,OAAO;gBACOF;YAAhBb,SAASe,QAAOF,iBAAAA,OAAOI,KAAK,qBAAZJ,eAAcM,QAAQ;YACtC;QACF;QACAX,UAASK,gBAAAA,OAAON,KAAK,YAAZM,gBAAgB;IAC3B;IAEA,qBACE,MAACnB;QACC0B,WAAU;QACVC,UAAUV;QACVW,SAAS;QACTC,IAAI;YAAEC,WAAW;YAAUC,YAAY;YAAUC,gBAAgB;YAAUC,IAAI;QAAE;;0BAEjF,KAAC/B;gBAAWgC,SAAQ;gBAAKR,WAAU;gBAAKG,IAAI;oBAAEM,WAAW;gBAAS;0BAC/D,CAAC,UAAU,EAAE3B,MAAM;;0BAEtB,KAACN;gBAAWgC,SAAQ;gBAAKE,OAAM;gBAAiBP,IAAI;oBAAEM,WAAW;gBAAS;0BAAG;;0BAG7E,KAAClC;gBACCsB,OAAOd;gBACP4B,UAAU,CAACnB,QAAUR,QAAQQ,MAAMoB,MAAM,CAACf,KAAK,CAACgB,OAAO,CAAC,OAAO,IAAIC,KAAK,CAAC,GAAG;gBAC5EC,SAAS;gBACTC,cAAa;gBACbC,aAAY;gBACZC,WAAW;oBACTC,WAAW;wBACTC,WAAW;wBACXC,SAAS;wBACTC,WAAW;wBACX,cAAc;wBACdC,OAAO;4BAAEd,WAAW;wBAAS;oBAC/B;gBACF;gBACAN,IAAI,CAACqB,QAAW,CAAA;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxB,WAAW,aAAKsB,MAAMG,UAAU,CAACC,EAAE;4BAAEC,eAAeL,MAAMtB,OAAO,CAAC;;oBACpE,CAAA;;YAEDf,sBACC,KAACf;gBAAM0D,UAAS;gBAAQ3B,IAAI;oBAAEsB,OAAO;oBAAQC,UAAU,CAACF,QAAUA,MAAMtB,OAAO,CAAC;gBAAI;0BACjFf;iBAED;0BACJ,KAACd;gBACC0D,MAAK;gBACLvB,SAAQ;gBACRwB,MAAK;gBACLC,UAAU,CAAC5C,SAASJ;gBACpBkB,IAAI,CAACqB,QAAW;wBACdC,OAAO;wBACPC,UAAUF,MAAMtB,OAAO,CAAC;wBACxBE,WAAWoB,MAAMtB,OAAO,CAAC;uBACtBsB,MAAMG,UAAU,CAACO,EAAE;0BAGvBjD,OAAO,aAAa,CAAC,KAAK,EAAEH,MAAM;;;;AAI3C"}
|
|
@@ -63,8 +63,14 @@ export interface PosDisplayResult<T> {
|
|
|
63
63
|
}
|
|
64
64
|
export declare function readStoredToken(): string | null;
|
|
65
65
|
export declare function storeToken(token: string | null): void;
|
|
66
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Exchanges a register's code for this device's token. `mode` is the kind of
|
|
68
|
+
* screen this page is — a customer display, or a self-service kiosk
|
|
69
|
+
* (AGL-3623) — and a code made for the other kind is refused.
|
|
70
|
+
*/
|
|
71
|
+
export declare function pairDisplay(code: string, mode?: CommerceModel.PosDeviceMode): Promise<PosDisplayResult<{
|
|
67
72
|
token: string;
|
|
73
|
+
mode?: CommerceModel.PosDeviceMode;
|
|
68
74
|
branding: PosDisplayBranding;
|
|
69
75
|
}>>;
|
|
70
76
|
export declare function pollDisplay(token: string, withBranding: boolean): Promise<PosDisplayResult<{
|
|
@@ -76,13 +76,18 @@ async function call(init, token) {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Exchanges a register's code for this device's token. `mode` is the kind of
|
|
81
|
+
* screen this page is — a customer display, or a self-service kiosk
|
|
82
|
+
* (AGL-3623) — and a code made for the other kind is refused.
|
|
83
|
+
*/ export function pairDisplay(code, mode = 'display') {
|
|
80
84
|
return call({
|
|
81
85
|
method: 'POST',
|
|
82
86
|
body: {
|
|
83
87
|
action: 'pair',
|
|
84
88
|
code,
|
|
85
|
-
|
|
89
|
+
mode,
|
|
90
|
+
label: mode === 'kiosk' ? 'Self-service kiosk' : 'Customer display'
|
|
86
91
|
}
|
|
87
92
|
}, null);
|
|
88
93
|
}
|