@aglyn/plugins-commerce 1.0.0-beta.287 → 1.0.0-beta.289

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +2 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/commerce-console-page.js +29 -2
  4. package/src/lib/components/commerce-console-page.js.map +1 -1
  5. package/src/lib/components/console/commerce-analytics-card.component.js +4 -2
  6. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -1
  7. package/src/lib/components/console/host-orders-card.component.js +5 -1
  8. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  9. package/src/lib/components/console/host-quotes-card.component.d.ts +34 -0
  10. package/src/lib/components/console/host-quotes-card.component.js +247 -0
  11. package/src/lib/components/console/host-quotes-card.component.js.map +1 -0
  12. package/src/lib/components/console/order-webhooks-card.component.js +1 -1
  13. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -1
  14. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +33 -28
  15. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  16. package/src/lib/components/console/quote-editor-dialog.component.d.ts +45 -0
  17. package/src/lib/components/console/quote-editor-dialog.component.js +1266 -0
  18. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -0
  19. package/src/lib/components/console/quote-pay-link.component.d.ts +38 -0
  20. package/src/lib/components/console/quote-pay-link.component.js +213 -0
  21. package/src/lib/components/console/quote-pay-link.component.js.map +1 -0
  22. package/src/lib/components/console/quote-settings-card.component.d.ts +29 -0
  23. package/src/lib/components/console/quote-settings-card.component.js +121 -0
  24. package/src/lib/components/console/quote-settings-card.component.js.map +1 -0
  25. package/src/lib/components/console/tax-settings-card.component.js +4 -1
  26. package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
  27. package/src/lib/components/quote-page-body.d.ts +33 -0
  28. package/src/lib/components/quote-page-body.js +696 -0
  29. package/src/lib/components/quote-page-body.js.map +1 -0
  30. package/src/lib/components/quote-page.d.ts +29 -0
  31. package/src/lib/components/quote-page.js +96 -0
  32. package/src/lib/components/quote-page.js.map +1 -0
  33. package/src/lib/components/storefront-payment-element.d.ts +7 -1
  34. package/src/lib/components/storefront-payment-element.js +8 -3
  35. package/src/lib/components/storefront-payment-element.js.map +1 -1
  36. package/src/lib/constants/orders-list-query.js +6 -1
  37. package/src/lib/constants/orders-list-query.js.map +1 -1
  38. package/src/lib/constants/quote-page.d.ts +30 -0
  39. package/src/lib/constants/quote-page.js +35 -0
  40. package/src/lib/constants/quote-page.js.map +1 -0
  41. package/src/lib/declarations.js +5 -1
  42. package/src/lib/declarations.js.map +1 -1
  43. package/src/lib/model/commerce-orders.d.ts +25 -2
  44. package/src/lib/model/commerce-orders.js +10 -1
  45. package/src/lib/model/commerce-orders.js.map +1 -1
  46. package/src/lib/model/commerce-quote-pay.d.ts +229 -0
  47. package/src/lib/model/commerce-quote-pay.js +393 -0
  48. package/src/lib/model/commerce-quote-pay.js.map +1 -0
  49. package/src/lib/model/commerce-quotes.d.ts +279 -0
  50. package/src/lib/model/commerce-quotes.js +522 -0
  51. package/src/lib/model/commerce-quotes.js.map +1 -0
  52. package/src/lib/model/index.d.ts +2 -0
  53. package/src/lib/model/index.js +2 -0
  54. package/src/lib/model/index.js.map +1 -1
  55. package/src/lib/model/plugin-permissions.d.ts +8 -1
  56. package/src/lib/model/plugin-permissions.js +21 -1
  57. package/src/lib/model/plugin-permissions.js.map +1 -1
  58. package/src/lib/model/workspace-site-permissions.d.ts +26 -0
  59. package/src/lib/model/workspace-site-permissions.js +81 -0
  60. package/src/lib/model/workspace-site-permissions.js.map +1 -0
  61. package/src/lib/server/api-v1/orders-and-products.js +6 -2
  62. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  63. package/src/lib/server/billing-webhook.js +127 -52
  64. package/src/lib/server/billing-webhook.js.map +1 -1
  65. package/src/lib/server/checkout-session-expiry.d.ts +36 -0
  66. package/src/lib/server/checkout-session-expiry.js +63 -0
  67. package/src/lib/server/checkout-session-expiry.js.map +1 -0
  68. package/src/lib/server/commerce-site-keys.d.ts +19 -0
  69. package/src/lib/server/commerce-site-keys.js +23 -2
  70. package/src/lib/server/commerce-site-keys.js.map +1 -1
  71. package/src/lib/server/draft-order.js +16 -8
  72. package/src/lib/server/draft-order.js.map +1 -1
  73. package/src/lib/server/order-webhooks.js +8 -8
  74. package/src/lib/server/order-webhooks.js.map +1 -1
  75. package/src/lib/server/person-eraser.d.ts +7 -0
  76. package/src/lib/server/person-eraser.js +24 -2
  77. package/src/lib/server/person-eraser.js.map +1 -1
  78. package/src/lib/server/pos-ops-gate.d.ts +13 -5
  79. package/src/lib/server/pos-ops-gate.js +12 -14
  80. package/src/lib/server/pos-ops-gate.js.map +1 -1
  81. package/src/lib/server/pos-refund-authority.d.ts +3 -1
  82. package/src/lib/server/pos-refund-authority.js +3 -2
  83. package/src/lib/server/pos-refund-authority.js.map +1 -1
  84. package/src/lib/server/pos-return.js +6 -7
  85. package/src/lib/server/pos-return.js.map +1 -1
  86. package/src/lib/server/pos-staff-pin.js +7 -7
  87. package/src/lib/server/pos-staff-pin.js.map +1 -1
  88. package/src/lib/server/quote-link-token.d.ts +39 -0
  89. package/src/lib/server/quote-link-token.js +97 -0
  90. package/src/lib/server/quote-link-token.js.map +1 -0
  91. package/src/lib/server/quote-pay.d.ts +83 -0
  92. package/src/lib/server/quote-pay.js +606 -0
  93. package/src/lib/server/quote-pay.js.map +1 -0
  94. package/src/lib/server/quote.d.ts +49 -0
  95. package/src/lib/server/quote.js +513 -0
  96. package/src/lib/server/quote.js.map +1 -0
  97. package/src/lib/server/refund.js +26 -36
  98. package/src/lib/server/refund.js.map +1 -1
  99. package/src/lib/server/related.js +2 -0
  100. package/src/lib/server/related.js.map +1 -1
  101. package/src/lib/server/site-page-resolver.d.ts +2 -0
  102. package/src/lib/server/site-page-resolver.js +75 -0
  103. package/src/lib/server/site-page-resolver.js.map +1 -1
  104. package/src/lib/server.js +14 -0
  105. package/src/lib/server.js.map +1 -1
  106. package/src/lib/site.js +6 -0
  107. package/src/lib/site.js.map +1 -1
  108. package/src/lib/transfer/tracking.server.js +6 -0
  109. package/src/lib/transfer/tracking.server.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/quote-editor-dialog.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\n'use client'\n\nimport * as CommerceModel from '../../model'\nimport { posMoney } from '../../model/commerce-pos-ops'\nimport { commerceSitePermissionRefusal } from '../../model/plugin-permissions'\nimport { BlockedControl } from '@aglyn/shared-ui-jsx/components/blocked-control.component'\nimport { PrerequisiteNotice } from '@aglyn/shared-ui-jsx/components/prerequisite-notice.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n useFirestore,\n useFirestoreDoc,\n useStoreSettingsHref,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Divider,\n FormControlLabel,\n List,\n ListItemButton,\n ListItemText,\n MenuItem,\n Paper,\n Stack,\n Switch,\n TextField,\n Typography,\n type Theme,\n} from '@mui/material'\nimport { doc } from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { QuotePayLinkSection } from './quote-pay-link.component'\n\n/** A quote as the list reads it: the order document and its id. */\nexport type QuoteRow = CommerceModel.HostOrder & { $id: string }\n\nexport interface QuoteEditorDialogProps {\n hostId: string\n /** The quote to edit, or `null` for a new one. */\n quote: QuoteRow | null\n /** The store's products, for the product picker. */\n products: readonly Record<string, any>[]\n /** Holds \"Create and edit quotes\" (`commerce.quotes`). */\n canEdit: boolean\n /** Holds \"Send quotes and invoices to customers\" (`commerce.quotes.send`). */\n canSend: boolean\n onClose: () => void\n}\n\nconst REFUSAL = commerceSitePermissionRefusal('commerce.quotes')\nconst SEARCH_DEBOUNCE_MS = 250\n\nconst money = (cents: number): string => posMoney(cents)\n\n/** Field widths on a wide screen, from the theme's spacing; full width on a phone. */\nconst narrowField = (theme: Theme) => ({ maxWidth: { sm: theme.spacing(16) } })\nconst mediumField = (theme: Theme) => ({ minWidth: { sm: theme.spacing(20) }, maxWidth: { sm: theme.spacing(24) } })\n\n/** Dollars typed into a field, as whole cents, or `null` when it is not an amount. */\nfunction centsOf(text: string): number | null {\n const trimmed = text.trim()\n if (!trimmed) return 0\n if (!/^\\d+(\\.\\d{0,2})?$/.test(trimmed)) return null\n return Math.round(Number(trimmed) * 100)\n}\n\nconst dollarsOf = (cents: number | undefined): string =>\n cents ? (cents / 100).toFixed(2).replace(/\\.00$/, '') : ''\n\ntype AddressForm = Record<'name' | 'line1' | 'line2' | 'city' | 'state' | 'postalCode' | 'country', string>\n\nfunction addressForm(address: CommerceModel.OrderAddress | null | undefined): AddressForm {\n return {\n name: address?.name ?? '',\n line1: address?.line1 ?? '',\n line2: address?.line2 ?? '',\n city: address?.city ?? '',\n state: address?.state ?? '',\n postalCode: address?.postalCode ?? '',\n country: address?.country ?? '',\n }\n}\n\ntype LineForm =\n | {\n key: string\n kind: 'catalog'\n productId: string\n variantId: string\n quantity: string\n modifiers: CommerceModel.ModifierSelection[]\n description: string\n included: boolean\n }\n | {\n key: string\n kind: 'custom'\n name: string\n description: string\n sku: string\n price: string\n quantity: string\n ships: boolean\n included: boolean\n }\n\ninterface QuoteForm {\n lines: LineForm[]\n customer: { record: { kind: string; id: string } | null; name: string; company: string; email: string; phone: string }\n shipTo: AddressForm\n billTo: AddressForm\n discountKind: 'none' | 'amount' | 'percent'\n discountValue: string\n shipping: string\n notes: string\n terms: string\n requireProofApproval: boolean\n}\n\nlet lineSequence = 0\nconst nextLineKey = () => `line-${++lineSequence}`\n\nfunction formFromQuote(quote: QuoteRow | null, requireProofApproval: boolean): QuoteForm {\n const section = quote?.quote\n const discount = section?.discount ?? null\n return {\n lines: (quote?.lineItems ?? []).map((line): LineForm => {\n const request = CommerceModel.quoteLineRequestFromLine(line)\n return request.kind === 'custom'\n ? {\n key: nextLineKey(),\n kind: 'custom',\n name: request.name,\n description: request.description ?? '',\n sku: request.sku ?? '',\n price: dollarsOf(request.unitAmountCents),\n quantity: String(request.quantity),\n ships: request.ships !== false,\n included: request.included === true,\n }\n : {\n key: nextLineKey(),\n kind: 'catalog',\n productId: request.productId,\n variantId: request.variantId ?? '',\n quantity: String(request.quantity),\n modifiers: request.modifiers ?? [],\n description: request.description ?? '',\n included: request.included === true,\n }\n }),\n customer: {\n record: section?.customer?.record ?? null,\n name: section?.customer?.name ?? '',\n company: section?.customer?.company ?? '',\n email: section?.customer?.email ?? '',\n phone: section?.customer?.phone ?? '',\n },\n shipTo: addressForm(section?.shipTo),\n billTo: addressForm(section?.billTo),\n discountKind: discount?.kind ?? 'none',\n discountValue:\n discount?.kind === 'amount' ? dollarsOf(discount.amountCents) : discount?.kind === 'percent' ? String(discount.pct) : '',\n shipping: dollarsOf(section?.shipping?.amountCents),\n notes: section?.notes ?? '',\n terms: section?.terms ?? '',\n requireProofApproval: section ? section.requireProofApproval === true : requireProofApproval,\n }\n}\n\nfunction lineRequest(line: LineForm): CommerceModel.QuoteLineRequest {\n const quantity = Number(line.quantity)\n if (line.kind === 'catalog') {\n return {\n kind: 'catalog',\n productId: line.productId,\n ...(line.variantId ? { variantId: line.variantId } : {}),\n quantity,\n ...(line.modifiers.length ? { modifiers: line.modifiers } : {}),\n ...(line.included ? { included: true } : {}),\n ...(line.description.trim() ? { description: line.description.trim() } : {}),\n }\n }\n return {\n kind: 'custom',\n name: line.name.trim(),\n ...(line.description.trim() ? { description: line.description.trim() } : {}),\n ...(line.sku.trim() ? { sku: line.sku.trim() } : {}),\n unitAmountCents: line.included ? 0 : (centsOf(line.price) ?? Number.NaN),\n quantity,\n ships: line.ships,\n ...(line.included ? { included: true } : {}),\n }\n}\n\nfunction addressBody(address: AddressForm): Partial<AddressForm> | null {\n const entries = Object.entries(address).filter(([, value]) => value.trim())\n return entries.length ? Object.fromEntries(entries.map(([key, value]) => [key, value.trim()])) : null\n}\n\n/** What the server is sent: choices, never what a product costs. */\nfunction quoteBody(form: QuoteForm): Record<string, unknown> {\n const discountCents = centsOf(form.discountValue)\n return {\n lines: form.lines.map(lineRequest),\n customer: {\n ...(form.customer.record ? { record: form.customer.record } : {}),\n name: form.customer.name,\n company: form.customer.company,\n email: form.customer.email,\n phone: form.customer.phone,\n },\n shipTo: addressBody(form.shipTo),\n billTo: addressBody(form.billTo),\n discount:\n form.discountKind === 'amount'\n ? { kind: 'amount', amountCents: discountCents ?? Number.NaN }\n : form.discountKind === 'percent'\n ? { kind: 'percent', pct: Number(form.discountValue || 0) }\n : null,\n shipping: form.shipping.trim() ? { amountCents: centsOf(form.shipping) ?? Number.NaN } : null,\n notes: form.notes,\n terms: form.terms,\n requireProofApproval: form.requireProofApproval,\n }\n}\n\ninterface FoundCustomer {\n record: { kind: string; id: string }\n name: string\n company: string\n email: string | null\n phone: string | null\n}\n\n/**\n * The quote editor (AGL-4093): who it is for, its lines (products with their\n * options and add-ons, typed items, things included at no charge), discount,\n * shipping, notes and terms, with the totals worked out as it is edited. The\n * server prices and saves it; the totals here are the same function's answer\n * over the same inputs, and a connected tax service's figure arrives on save.\n */\nexport function QuoteEditorDialog(props: QuoteEditorDialogProps) {\n const { hostId, quote, products, canEdit, canSend, onClose } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const taxesHref = useStoreSettingsHref(hostId, 'taxes')\n const { data: store } = useFirestoreDoc<any>(\n () => doc(firestore, 'hosts', hostId, 'settings', 'store'),\n [firestore, hostId],\n )\n const storeDefault = CommerceModel.quoteRequiresProofApprovalByDefault(store?.quotes)\n const [form, setForm] = useState<QuoteForm>(() => formFromQuote(quote, storeDefault))\n // The version this form was opened on. A change saved elsewhere while it is\n // open arrives on `quote`; the save still names this one, so the server\n // refuses rather than overwrite that change.\n const [baseUpdatedAtMs] = useState(() => quote?.quote?.updatedAtMs)\n const [busy, setBusy] = useState(false)\n const [confirmingDelete, setConfirmingDelete] = useState(false)\n /** Whether anything has been changed since the dialog opened. */\n const [edited, setEdited] = useState(false)\n /** Whether the proof-approval switch was set by hand. */\n const [approvalSet, setApprovalSet] = useState(false)\n // A new quote starts with the store's default, which may arrive after the\n // dialog opens; a switch set by hand keeps its setting.\n const requireProofApproval = quote || approvalSet ? form.requireProofApproval : storeDefault\n\n const update = useCallback((patch: Partial<QuoteForm>) => {\n setEdited(true)\n if ('requireProofApproval' in patch) setApprovalSet(true)\n setForm((prev) => ({ ...prev, ...patch }))\n }, [])\n const updateLine = useCallback((key: string, patch: Partial<LineForm>) => {\n setEdited(true)\n setForm((prev) => ({\n ...prev,\n lines: prev.lines.map((line) => (line.key === key ? ({ ...line, ...patch } as LineForm) : line)),\n }))\n }, [])\n\n /*\n * One attempt per change (AGL-1697's rule): a retried Save presents the same\n * key and is answered from the first, an edited quote is a new attempt.\n */\n const attemptKey = useRef('')\n useEffect(() => {\n attemptKey.current = ''\n }, [form])\n\n const productsById = useMemo(\n () => new Map(products.map((product) => [String(product.$id), product])),\n [products],\n )\n\n /** Each line priced as the server will price it, or why it cannot be. */\n const priced = useMemo(\n () =>\n form.lines.map((line) => {\n const request = lineRequest(line)\n if (request.kind === 'custom') {\n if (!request.name) return { error: 'Name the item.' }\n if (!Number.isInteger(request.unitAmountCents)) return { error: 'Enter a price.' }\n if (!(request.quantity >= 1)) return { error: 'Enter a quantity.' }\n return { line: CommerceModel.priceQuoteCustomLine(request) }\n }\n if (!request.productId) return { error: 'Choose a product.' }\n if (!(request.quantity >= 1)) return { error: 'Enter a quantity.' }\n const answer = CommerceModel.priceQuoteCatalogLine(productsById.get(request.productId) as never, request)\n return 'error' in answer ? { error: answer.error } : { line: answer.line }\n }),\n [form.lines, productsById],\n )\n\n const discountCents = centsOf(form.discountValue)\n const discount: CommerceModel.QuoteDiscount | null =\n form.discountKind === 'amount' && discountCents\n ? { kind: 'amount', amountCents: discountCents }\n : form.discountKind === 'percent' && Number(form.discountValue) > 0\n ? { kind: 'percent', pct: Math.min(100, Number(form.discountValue)) }\n : null\n const shippingCents = centsOf(form.shipping) ?? 0\n const taxBasis = CommerceModel.quoteTaxBasisFromSettings(store?.tax, {\n country: form.shipTo.country.trim().toUpperCase(),\n state: form.shipTo.state.trim(),\n })\n const pricedLines = priced.flatMap((entry) => ('line' in entry && entry.line ? [entry.line] : []))\n const totals = CommerceModel.computeQuoteTotals({ lines: pricedLines, discount, shippingCents, tax: taxBasis })\n const problems = priced.some((entry) => 'error' in entry)\n const savedService = quote?.quote?.tax?.kind === 'service' ? quote.quote.tax : null\n\n const save = useCallback(async () => {\n setBusy(true)\n try {\n if (!attemptKey.current) {\n attemptKey.current = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n }\n const response = await authorizedFetch(user, '/api/commerce/quote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Idempotency-Key': attemptKey.current },\n body: JSON.stringify({\n action: quote ? 'update' : 'create',\n hostId,\n ...(quote ? { quoteId: quote.$id, baseUpdatedAtMs } : {}),\n quote: quoteBody({ ...form, requireProofApproval }),\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(payload?.error ?? 'The quote could not be saved', { variant: 'error', allowDuplicate: true })\n }\n enqueueSnackbar(`${CommerceModel.formatQuoteNumber({ number: payload.number ?? undefined }, payload.quoteId)} saved`, {\n variant: 'success',\n persist: false,\n })\n onClose()\n } finally {\n setBusy(false)\n }\n }, [user, quote, hostId, baseUpdatedAtMs, form, requireProofApproval, enqueueSnackbar, onClose])\n\n const remove = useCallback(async () => {\n if (!quote) return\n setBusy(true)\n try {\n const response = await authorizedFetch(user, '/api/commerce/quote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'delete', hostId, quoteId: quote.$id }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(payload?.error ?? 'The quote could not be deleted', { variant: 'error', allowDuplicate: true })\n }\n enqueueSnackbar(`${CommerceModel.formatQuoteNumber(quote, quote.$id)} deleted`, { variant: 'success', persist: false })\n setConfirmingDelete(false)\n onClose()\n } finally {\n setBusy(false)\n }\n }, [user, quote, hostId, enqueueSnackbar, onClose])\n\n const readOnly = !canEdit || busy\n const paid = quote ? !CommerceModel.isUnpaidQuote(quote) : false\n const title = quote ? CommerceModel.formatQuoteNumber(quote, quote.$id) : 'New quote'\n const status = quote ? CommerceModel.quoteDisplayStatus(quote) : null\n const deletable = Boolean(quote) && !paid && (quote?.quote?.stage ?? 'draft') === 'draft'\n\n return (\n <Dialog open onClose={busy ? undefined : onClose} maxWidth=\"md\" fullWidth scroll=\"paper\" aria-labelledby=\"quote-editor-title\">\n <DialogTitle id=\"quote-editor-title\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <span>{title}</span>\n {status ? (\n <Chip size=\"small\" variant=\"outlined\" label={status.label} color={CommerceModel.QUOTE_STATUS_COLOR[status.key]} />\n ) : null}\n </Stack>\n </DialogTitle>\n <DialogContent dividers>\n <Stack spacing={3}>\n {paid ? (\n <Alert severity=\"success\">\n {quote?.quote?.paidAtMs\n ? `Paid ${new Date(quote.quote.paidAtMs).toLocaleDateString()}. It is an order now and can no longer be changed.`\n : 'This quote has been paid, so it is an order now and can no longer be changed.'}\n </Alert>\n ) : null}\n {quote ? (\n <QuotePayLinkSection hostId={hostId} quoteId={quote.$id} quote={quote} canSend={canSend} edited={edited} />\n ) : null}\n {taxBasis.kind === 'none' && taxBasis.reason === 'undecided' ? (\n <PrerequisiteNotice href={taxesHref ?? undefined} actionLabel=\"Open Taxes\">\n {'This store has not chosen how it handles sales tax, so this quote shows no tax. Choose it in Taxes.'}\n </PrerequisiteNotice>\n ) : null}\n\n <QuoteCustomerSection\n hostId={hostId}\n form={form}\n disabled={readOnly || paid}\n onChange={(customer) => update({ customer })}\n />\n\n <Stack spacing={1.5}>\n <Typography variant=\"subtitle2\">{'Items'}</Typography>\n {form.lines.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Add products from your catalog, or type an item that is made to order.'}\n </Typography>\n ) : null}\n {form.lines.map((line, index) => (\n <QuoteLineEditor\n key={line.key}\n line={line}\n priced={priced[index]}\n products={products}\n disabled={readOnly || paid}\n onChange={(patch) => updateLine(line.key, patch)}\n onRemove={() => update({ lines: form.lines.filter((entry) => entry.key !== line.key) })}\n />\n ))}\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n <Button\n size=\"small\"\n disabled={readOnly || paid || products.length === 0}\n onClick={() =>\n update({\n lines: [\n ...form.lines,\n { key: nextLineKey(), kind: 'catalog', productId: '', variantId: '', quantity: '1', modifiers: [], description: '', included: false },\n ],\n })\n }\n >\n {'Add product'}\n </Button>\n <Button\n size=\"small\"\n disabled={readOnly || paid}\n onClick={() =>\n update({\n lines: [\n ...form.lines,\n { key: nextLineKey(), kind: 'custom', name: '', description: '', sku: '', price: '', quantity: '1', ships: true, included: false },\n ],\n })\n }\n >\n {'Add custom item'}\n </Button>\n </Stack>\n </Stack>\n\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n label=\"Discount\"\n select\n size=\"small\"\n value={form.discountKind}\n disabled={readOnly || paid}\n onChange={(event) => update({ discountKind: event.target.value as QuoteForm['discountKind'] })}\n sx={mediumField}\n >\n <MenuItem value=\"none\">{'None'}</MenuItem>\n <MenuItem value=\"amount\">{'Amount off'}</MenuItem>\n <MenuItem value=\"percent\">{'Percent off'}</MenuItem>\n </TextField>\n {form.discountKind !== 'none' ? (\n <TextField\n label={form.discountKind === 'amount' ? 'Amount ($)' : 'Percent (%)'}\n size=\"small\"\n value={form.discountValue}\n disabled={readOnly || paid}\n onChange={(event) => update({ discountValue: event.target.value })}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n error={form.discountKind === 'amount' ? centsOf(form.discountValue) === null : !(Number(form.discountValue) >= 0 && Number(form.discountValue) <= 100)}\n />\n ) : null}\n <TextField\n label=\"Shipping ($)\"\n size=\"small\"\n value={form.shipping}\n disabled={readOnly || paid}\n onChange={(event) => update({ shipping: event.target.value })}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n error={centsOf(form.shipping) === null}\n helperText=\"Leave empty when nothing ships.\"\n />\n </Stack>\n\n <QuoteAddressFields\n label=\"Ship to\"\n value={form.shipTo}\n disabled={readOnly || paid}\n helperText=\"Where the order goes. Store tax rates use its state and country.\"\n onChange={(shipTo) => update({ shipTo })}\n />\n <QuoteAddressFields\n label=\"Bill to\"\n value={form.billTo}\n disabled={readOnly || paid}\n onChange={(billTo) => update({ billTo })}\n />\n\n <Stack spacing={2}>\n <TextField\n label=\"Notes for the customer\"\n multiline\n minRows={2}\n value={form.notes}\n disabled={readOnly || paid}\n onChange={(event) => update({ notes: event.target.value })}\n />\n <TextField\n label=\"Terms\"\n multiline\n minRows={2}\n value={form.terms}\n disabled={readOnly || paid}\n onChange={(event) => update({ terms: event.target.value })}\n />\n <FormControlLabel\n control={\n <Switch\n checked={requireProofApproval}\n disabled={readOnly || paid}\n onChange={(event) => update({ requireProofApproval: event.target.checked })}\n />\n }\n label=\"Customers approve the proof before they can pay\"\n />\n </Stack>\n\n <Divider />\n <QuoteTotalsSummary\n totals={totals}\n tax={taxBasis}\n savedService={edited ? null : savedService}\n savedTotals={edited ? null : (quote?.totals ?? null)}\n />\n </Stack>\n </DialogContent>\n <DialogActions sx={{ flexWrap: 'wrap', rowGap: 1 }}>\n {deletable ? (\n <BlockedControl blocked={!canEdit} reason={REFUSAL}>\n <Button color=\"error\" disabled={busy} onClick={() => setConfirmingDelete(true)} sx={{ mr: 'auto' }}>\n {'Delete'}\n </Button>\n </BlockedControl>\n ) : null}\n <Button onClick={onClose} disabled={busy}>\n {paid || !canEdit ? 'Close' : 'Cancel'}\n </Button>\n {paid ? null : (\n <BlockedControl blocked={!canEdit} reason={REFUSAL}>\n <Button\n variant=\"contained\"\n disabled={busy || form.lines.length === 0 || problems}\n onClick={() => void save()}\n >\n {quote ? 'Save' : 'Create quote'}\n </Button>\n </BlockedControl>\n )}\n </DialogActions>\n <Dialog open={confirmingDelete} onClose={() => setConfirmingDelete(false)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{`Delete ${title}?`}</DialogTitle>\n <DialogContent>\n <DialogContentText>{'The quote and everything on it is removed. This can’t be undone.'}</DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmingDelete(false)} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button color=\"error\" variant=\"contained\" disabled={busy} onClick={() => void remove()}>\n {'Delete'}\n </Button>\n </DialogActions>\n </Dialog>\n </Dialog>\n )\n}\nQuoteEditorDialog.displayName = 'QuoteEditorDialog'\n\n/** Who the quote is for: a person the workspace keeps, or details typed here. */\nfunction QuoteCustomerSection(props: {\n hostId: string\n form: QuoteForm\n disabled: boolean\n onChange: (customer: QuoteForm['customer']) => void\n}) {\n const { hostId, form, disabled, onChange } = props\n const { data: user } = useUser()\n const [text, setText] = useState('')\n const [found, setFound] = useState<FoundCustomer[]>([])\n const [available, setAvailable] = useState(true)\n const ticket = useRef(0)\n const customer = form.customer\n\n useEffect(() => {\n const typed = text.trim()\n if (typed.length < 2 || !user) {\n // Only when something is listed, so an effect that re-runs settles.\n setFound((prev) => (prev.length ? [] : prev))\n return\n }\n const mine = ++ticket.current\n const timer = window.setTimeout(() => {\n void authorizedFetch(user, '/api/commerce/quote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'search-customers', hostId, text: typed }),\n })\n .then((response) => response.json().catch(() => ({})))\n .then((payload) => {\n if (mine !== ticket.current) return\n setAvailable(payload?.available !== false)\n setFound(Array.isArray(payload?.customers) ? payload.customers : [])\n })\n .catch(() => undefined)\n }, SEARCH_DEBOUNCE_MS)\n return () => window.clearTimeout(timer)\n }, [text, user, hostId])\n\n const pick = (person: FoundCustomer) => {\n onChange({\n record: person.record,\n name: person.name,\n company: person.company,\n email: person.email ?? '',\n phone: person.phone ?? '',\n })\n setText('')\n setFound([])\n }\n\n return (\n <Stack spacing={1.5}>\n <Typography variant=\"subtitle2\">{'Customer'}</Typography>\n {customer.record ? (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Chip\n color=\"primary\"\n variant=\"outlined\"\n label={customer.name || customer.email || 'Contact'}\n onDelete={disabled ? undefined : () => onChange({ ...customer, record: null })}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'From your contacts'}\n </Typography>\n </Stack>\n ) : available ? (\n <Box>\n <TextField\n size=\"small\"\n fullWidth\n label=\"Find a contact\"\n placeholder=\"Name, email or phone\"\n value={text}\n disabled={disabled}\n onChange={(event) => setText(event.target.value)}\n />\n {found.length ? (\n <Paper variant=\"outlined\" sx={{ mt: 0.5 }}>\n <List dense disablePadding>\n {found.map((person) => (\n <ListItemButton key={`${person.record.kind}:${person.record.id}`} onClick={() => pick(person)}>\n <ListItemText\n primary={person.name || person.email || 'Contact'}\n secondary={[person.company, person.email, person.phone].filter(Boolean).join(' · ')}\n />\n </ListItemButton>\n ))}\n </List>\n </Paper>\n ) : null}\n </Box>\n ) : null}\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField size=\"small\" fullWidth label=\"Name\" value={customer.name} disabled={disabled} onChange={(event) => onChange({ ...customer, name: event.target.value })} />\n <TextField size=\"small\" fullWidth label=\"Company\" value={customer.company} disabled={disabled} onChange={(event) => onChange({ ...customer, company: event.target.value })} />\n </Stack>\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField size=\"small\" fullWidth label=\"Email\" type=\"email\" value={customer.email} disabled={disabled} onChange={(event) => onChange({ ...customer, email: event.target.value })} />\n <TextField size=\"small\" fullWidth label=\"Phone\" value={customer.phone} disabled={disabled} onChange={(event) => onChange({ ...customer, phone: event.target.value })} />\n </Stack>\n </Stack>\n )\n}\n\n/** One address on the quote. */\nfunction QuoteAddressFields(props: {\n label: string\n value: AddressForm\n disabled: boolean\n helperText?: string\n onChange: (value: AddressForm) => void\n}) {\n const { label, value, disabled, helperText, onChange } = props\n const field = (key: keyof AddressForm, fieldLabel: string, extra: Record<string, unknown> = {}) => (\n <TextField\n size=\"small\"\n fullWidth\n label={fieldLabel}\n value={value[key]}\n disabled={disabled}\n onChange={(event) => onChange({ ...value, [key]: event.target.value })}\n {...extra}\n />\n )\n return (\n <Stack spacing={1.5}>\n <Typography variant=\"subtitle2\">{label}</Typography>\n {helperText ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {helperText}\n </Typography>\n ) : null}\n {field('name', 'Name')}\n {field('line1', 'Address')}\n {field('line2', 'Apartment, suite, unit')}\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n {field('city', 'City')}\n {field('state', 'State or region')}\n {field('postalCode', 'Postal code')}\n {field('country', 'Country code', { placeholder: 'US', slotProps: { htmlInput: { maxLength: 2 } } })}\n </Stack>\n </Stack>\n )\n}\n\n/** One line of the quote: a product with its options and add-ons, or a typed item. */\nfunction QuoteLineEditor(props: {\n line: LineForm\n priced: { line?: CommerceModel.PricedQuoteLine; error?: string } | undefined\n products: readonly Record<string, any>[]\n disabled: boolean\n onChange: (patch: Partial<LineForm>) => void\n onRemove: () => void\n}) {\n const { line, priced, products, disabled, onChange, onRemove } = props\n const product = line.kind === 'catalog' ? products.find((entry) => String(entry.$id) === line.productId) : undefined\n const lifted = product ? CommerceModel.liftLegacyProduct(product) : null\n const groups = lifted ? CommerceModel.productModifierGroups(lifted) : []\n const lineCents = priced?.line ? CommerceModel.quoteLineCents(priced.line) : 0\n\n return (\n <Paper variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={1.5}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'flex-start' }}>\n <Stack spacing={1.5} sx={{ flex: 1, minWidth: 0 }}>\n {line.kind === 'catalog' ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n label=\"Product\"\n select\n size=\"small\"\n fullWidth\n value={line.productId}\n disabled={disabled}\n onChange={(event) => onChange({ productId: event.target.value, variantId: '', modifiers: [] })}\n >\n {products.map((entry) => (\n <MenuItem key={String(entry.$id)} value={String(entry.$id)}>\n {String(entry.name ?? entry.$id)}\n </MenuItem>\n ))}\n </TextField>\n {lifted && lifted.variants.length > 1 ? (\n <TextField\n label=\"Option\"\n select\n size=\"small\"\n fullWidth\n value={line.variantId || lifted.variants[0]?.id || ''}\n disabled={disabled}\n onChange={(event) => onChange({ variantId: event.target.value })}\n >\n {lifted.variants.map((variant) => (\n <MenuItem key={variant.id} value={variant.id}>\n {Object.values(variant.options ?? {}).join(' / ') || 'Default'}\n </MenuItem>\n ))}\n </TextField>\n ) : null}\n </Stack>\n ) : (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>\n <TextField\n label=\"Item\"\n size=\"small\"\n fullWidth\n value={line.name}\n disabled={disabled}\n onChange={(event) => onChange({ name: event.target.value })}\n />\n <TextField\n label=\"SKU (optional)\"\n size=\"small\"\n value={line.sku}\n disabled={disabled}\n onChange={(event) => onChange({ sku: event.target.value })}\n />\n </Stack>\n )}\n {groups.map((group) => {\n const chosen = line.kind === 'catalog' ? line.modifiers.filter((pick) => pick.groupId === group.id).map((pick) => pick.optionId) : []\n return (\n <TextField\n key={group.id}\n label={CommerceModel.modifierGroupRequired(group) ? group.name : `${group.name} (optional)`}\n select\n size=\"small\"\n fullWidth\n value={group.max > 1 ? chosen : (chosen[0] ?? '')}\n disabled={disabled}\n slotProps={{ select: { multiple: group.max > 1 } }}\n onChange={(event) => {\n const raw = event.target.value as unknown\n const picked = (Array.isArray(raw) ? raw : raw ? [raw] : []).map(String)\n if (line.kind !== 'catalog') return\n onChange({\n modifiers: [\n ...line.modifiers.filter((pick) => pick.groupId !== group.id),\n ...picked.map((optionId) => ({ groupId: group.id, optionId })),\n ],\n })\n }}\n >\n {group.max > 1 ? null : <MenuItem value=\"\">{'None'}</MenuItem>}\n {group.options.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.priceCents ? `${option.name} (+${money(option.priceCents)})` : option.name}\n </MenuItem>\n ))}\n </TextField>\n )\n })}\n <TextField\n label=\"Description (optional)\"\n size=\"small\"\n fullWidth\n multiline\n value={line.description}\n disabled={disabled}\n onChange={(event) => onChange({ description: event.target.value })}\n />\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ alignItems: { sm: 'center' } }}>\n <TextField\n label=\"Quantity\"\n size=\"small\"\n value={line.quantity}\n disabled={disabled}\n onChange={(event) => onChange({ quantity: event.target.value.replace(/[^0-9]/g, '') })}\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n sx={narrowField}\n />\n {line.kind === 'custom' ? (\n <TextField\n label=\"Unit price ($)\"\n size=\"small\"\n value={line.included ? '' : line.price}\n disabled={disabled || line.included}\n onChange={(event) => onChange({ price: event.target.value })}\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n error={!line.included && centsOf(line.price) === null}\n sx={mediumField}\n />\n ) : null}\n {line.kind === 'custom' ? (\n <FormControlLabel\n control={<Switch checked={line.ships} disabled={disabled} onChange={(event) => onChange({ ships: event.target.checked })} />}\n label=\"Ships\"\n />\n ) : null}\n <FormControlLabel\n control={\n <Switch checked={line.included} disabled={disabled} onChange={(event) => onChange({ included: event.target.checked })} />\n }\n label=\"Included at no charge\"\n />\n </Stack>\n </Stack>\n <Stack sx={{ alignItems: 'flex-end', flexShrink: 0 }}>\n <Button size=\"small\" color=\"inherit\" disabled={disabled} onClick={onRemove}>\n {'Remove'}\n </Button>\n <Typography variant=\"body2\" sx={{ fontWeight: 'fontWeightMedium' }}>\n {line.included ? 'Included' : money(lineCents)}\n </Typography>\n {priced?.line && !line.included && priced.line.quantity > 1 ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${money(priced.line.unitAmountCents)} each`}\n </Typography>\n ) : null}\n </Stack>\n </Stack>\n {priced?.error ? (\n <Typography variant=\"caption\" color=\"error\">\n {priced.error}\n </Typography>\n ) : null}\n </Stack>\n </Paper>\n )\n}\n\n/** The quote's totals, as the customer will read them. */\nfunction QuoteTotalsSummary(props: {\n totals: CommerceModel.QuoteTotals\n tax: CommerceModel.QuoteTaxBasis\n /** A saved quote's tax service answer, shown until the quote is edited. */\n savedService: CommerceModel.QuoteTaxBasis | null\n savedTotals: CommerceModel.OrderTotals | null\n}) {\n const { totals, tax, savedService, savedTotals } = props\n const shown = savedService && savedTotals ? { ...totals, ...savedTotals } : totals\n const taxLabel = CommerceModel.describeQuoteTax(savedService ?? tax)\n const row = (label: string, value: string, strong = false) => (\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Typography variant={strong ? 'subtitle1' : 'body2'} color={strong ? 'text.primary' : 'text.secondary'}>\n {label}\n </Typography>\n <Typography variant={strong ? 'subtitle1' : 'body2'}>{value}</Typography>\n </Stack>\n )\n return (\n <Stack spacing={0.5} sx={(theme) => ({ alignSelf: { sm: 'flex-end' }, minWidth: { sm: theme.spacing(40) } })}>\n {row('Items', money(shown.itemsCents))}\n {shown.discountCents ? row('Discount', `−${money(shown.discountCents)}`) : null}\n {shown.shippingCents ? row('Shipping', money(shown.shippingCents)) : null}\n {tax.kind === 'at-payment' && !savedService ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {taxLabel}\n </Typography>\n ) : (\n row(taxLabel, money(shown.taxCents))\n )}\n {row(totals.taxAtPayment && !savedService ? 'Total before tax' : 'Total', money(shown.totalCents), true)}\n </Stack>\n )\n}\n\nexport default QuoteEditorDialog\n"],"names":["CommerceModel","posMoney","commerceSitePermissionRefusal","BlockedControl","PrerequisiteNotice","useSnackbar","authorizedFetch","useFirestore","useFirestoreDoc","useStoreSettingsHref","useUser","Alert","Box","Button","Chip","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Divider","FormControlLabel","List","ListItemButton","ListItemText","MenuItem","Paper","Stack","Switch","TextField","Typography","doc","useCallback","useEffect","useMemo","useRef","useState","QuotePayLinkSection","REFUSAL","SEARCH_DEBOUNCE_MS","money","cents","narrowField","theme","maxWidth","sm","spacing","mediumField","minWidth","centsOf","text","trimmed","trim","test","Math","round","Number","dollarsOf","toFixed","replace","addressForm","address","name","line1","line2","city","state","postalCode","country","lineSequence","nextLineKey","formFromQuote","quote","requireProofApproval","section","discount","lines","lineItems","map","line","request","quoteLineRequestFromLine","kind","key","description","sku","price","unitAmountCents","quantity","String","ships","included","productId","variantId","modifiers","customer","record","company","email","phone","shipTo","billTo","discountKind","discountValue","amountCents","pct","shipping","notes","terms","lineRequest","length","NaN","addressBody","entries","Object","filter","value","fromEntries","quoteBody","form","discountCents","QuoteEditorDialog","props","hostId","products","canEdit","canSend","onClose","firestore","data","user","enqueueSnackbar","taxesHref","store","storeDefault","quoteRequiresProofApprovalByDefault","quotes","setForm","baseUpdatedAtMs","updatedAtMs","busy","setBusy","confirmingDelete","setConfirmingDelete","edited","setEdited","approvalSet","setApprovalSet","update","patch","prev","updateLine","attemptKey","current","productsById","Map","product","$id","priced","error","isInteger","priceQuoteCustomLine","answer","priceQuoteCatalogLine","get","min","shippingCents","taxBasis","quoteTaxBasisFromSettings","tax","toUpperCase","pricedLines","flatMap","entry","totals","computeQuoteTotals","problems","some","savedService","save","payload","globalThis","crypto","randomUUID","Date","now","random","toString","slice","response","method","headers","body","JSON","stringify","action","quoteId","json","catch","ok","variant","allowDuplicate","formatQuoteNumber","number","undefined","persist","remove","readOnly","paid","isUnpaidQuote","title","status","quoteDisplayStatus","deletable","Boolean","stage","open","fullWidth","scroll","aria-labelledby","id","direction","sx","alignItems","span","size","label","color","QUOTE_STATUS_COLOR","dividers","severity","paidAtMs","toLocaleDateString","reason","href","actionLabel","QuoteCustomerSection","disabled","onChange","index","QuoteLineEditor","onRemove","useFlexGap","flexWrap","onClick","xs","select","event","target","slotProps","htmlInput","inputMode","helperText","QuoteAddressFields","multiline","minRows","control","checked","QuoteTotalsSummary","savedTotals","rowGap","blocked","mr","displayName","setText","found","setFound","available","setAvailable","ticket","typed","mine","timer","window","setTimeout","then","Array","isArray","customers","clearTimeout","pick","person","onDelete","placeholder","mt","dense","disablePadding","primary","secondary","join","type","field","fieldLabel","extra","maxLength","lifted","find","liftLegacyProduct","groups","productModifierGroups","lineCents","quoteLineCents","p","flex","variants","values","options","group","chosen","groupId","optionId","modifierGroupRequired","max","multiple","raw","picked","option","priceCents","flexShrink","fontWeight","shown","taxLabel","describeQuoteTax","row","strong","justifyContent","alignSelf","itemsCents","taxCents","taxAtPayment","totalCents"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as CommerceModel from '../../model';
18
+ export interface QuotePayLinkSectionProps {
19
+ hostId: string;
20
+ quoteId: string;
21
+ quote: Pick<CommerceModel.HostOrder, 'status' | 'channel' | 'number'>;
22
+ /** Holds "Send quotes and invoices to customers" (`commerce.quotes.send`). */
23
+ canSend: boolean;
24
+ /** The editor holds changes not saved yet, which the link does not show. */
25
+ edited: boolean;
26
+ }
27
+ /**
28
+ * A quote's pay link (AGL-4094): the address the business sends the
29
+ * customer, which opens the quote on the business's own site with a Pay
30
+ * button. "Copy pay link" asks the server for it (it is signed there) and puts
31
+ * it on the clipboard and on screen; "Replace link" makes a new one and the
32
+ * one sent before stops opening the quote.
33
+ */
34
+ export declare function QuotePayLinkSection(props: QuotePayLinkSectionProps): import("react").JSX.Element;
35
+ export declare namespace QuotePayLinkSection {
36
+ var displayName: string;
37
+ }
38
+ export default QuotePayLinkSection;
@@ -0,0 +1,213 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import * as CommerceModel from "../../model/index.js";
19
+ import { commerceSitePermissionRefusal } from "../../model/plugin-permissions.js";
20
+ import { BlockedControl } from "@aglyn/shared-ui-jsx/components/blocked-control.component";
21
+ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
22
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
23
+ import { useUser } from "@aglyn/tenant-feature-instance";
24
+ import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Stack, TextField, Typography } from "@mui/material";
25
+ import { useCallback, useState } from "react";
26
+ const SEND_REFUSAL = commerceSitePermissionRefusal('commerce.quotes.send');
27
+ /**
28
+ * A quote's pay link (AGL-4094): the address the business sends the
29
+ * customer, which opens the quote on the business's own site with a Pay
30
+ * button. "Copy pay link" asks the server for it (it is signed there) and puts
31
+ * it on the clipboard and on screen; "Replace link" makes a new one and the
32
+ * one sent before stops opening the quote.
33
+ */ export function QuotePayLinkSection(props) {
34
+ const { hostId, quoteId, quote, canSend, edited } = props;
35
+ const { data: user } = useUser();
36
+ const { enqueueSnackbar } = useSnackbar();
37
+ const [url, setUrl] = useState('');
38
+ const [busy, setBusy] = useState(false);
39
+ const [confirmingReplace, setConfirmingReplace] = useState(false);
40
+ const unpaid = CommerceModel.isUnpaidQuote(quote);
41
+ const ask = useCallback(async (action)=>{
42
+ setBusy(true);
43
+ try {
44
+ const response = await authorizedFetch(user, '/api/commerce/quote', {
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json'
48
+ },
49
+ body: JSON.stringify({
50
+ action,
51
+ hostId,
52
+ quoteId
53
+ })
54
+ });
55
+ const payload = await response.json().catch(()=>({}));
56
+ if (!response.ok || !(payload == null ? void 0 : payload.url)) {
57
+ var _ref;
58
+ enqueueSnackbar((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'The pay link could not be made', {
59
+ variant: 'error',
60
+ allowDuplicate: true
61
+ });
62
+ return null;
63
+ }
64
+ setUrl(String(payload.url));
65
+ return String(payload.url);
66
+ } finally{
67
+ setBusy(false);
68
+ }
69
+ }, [
70
+ user,
71
+ hostId,
72
+ quoteId,
73
+ enqueueSnackbar
74
+ ]);
75
+ const copy = useCallback(async (link, done)=>{
76
+ try {
77
+ await navigator.clipboard.writeText(link);
78
+ enqueueSnackbar(done, {
79
+ variant: 'success',
80
+ persist: false
81
+ });
82
+ } catch (unused) {
83
+ // The link is on screen to copy by hand when the clipboard is refused.
84
+ enqueueSnackbar('Copy the link below to send it', {
85
+ variant: 'info',
86
+ persist: false
87
+ });
88
+ }
89
+ }, [
90
+ enqueueSnackbar
91
+ ]);
92
+ const copyLink = useCallback(async ()=>{
93
+ const link = url || await ask('pay-link');
94
+ if (link) await copy(link, 'Pay link copied');
95
+ }, [
96
+ url,
97
+ ask,
98
+ copy
99
+ ]);
100
+ const replaceLink = useCallback(async ()=>{
101
+ const link = await ask('replace-link');
102
+ setConfirmingReplace(false);
103
+ if (link) await copy(link, 'New pay link copied. The earlier link no longer opens the quote.');
104
+ }, [
105
+ ask,
106
+ copy
107
+ ]);
108
+ return /*#__PURE__*/ _jsxs(Stack, {
109
+ spacing: 1.5,
110
+ children: [
111
+ /*#__PURE__*/ _jsxs(Stack, {
112
+ spacing: 0.5,
113
+ children: [
114
+ /*#__PURE__*/ _jsx(Typography, {
115
+ variant: "subtitle2",
116
+ children: 'Pay link'
117
+ }),
118
+ /*#__PURE__*/ _jsx(Typography, {
119
+ variant: "body2",
120
+ color: "text.secondary",
121
+ children: unpaid ? 'Send this link to the customer. It opens the quote on your site, where they can pay it.' : 'The link opens the paid quote and the customer’s order.'
122
+ }),
123
+ edited && unpaid ? /*#__PURE__*/ _jsx(Typography, {
124
+ variant: "body2",
125
+ color: "text.secondary",
126
+ children: 'Save your changes first: the link opens the quote as it was last saved.'
127
+ }) : null
128
+ ]
129
+ }),
130
+ url ? /*#__PURE__*/ _jsx(TextField, {
131
+ label: "Pay link",
132
+ value: url,
133
+ size: "small",
134
+ fullWidth: true,
135
+ slotProps: {
136
+ htmlInput: {
137
+ readOnly: true
138
+ },
139
+ inputLabel: {
140
+ shrink: true
141
+ }
142
+ },
143
+ onFocus: (event)=>event.target.select()
144
+ }) : null,
145
+ /*#__PURE__*/ _jsxs(Stack, {
146
+ direction: "row",
147
+ spacing: 1,
148
+ sx: {
149
+ flexWrap: 'wrap',
150
+ rowGap: 1
151
+ },
152
+ children: [
153
+ /*#__PURE__*/ _jsx(BlockedControl, {
154
+ blocked: !canSend,
155
+ reason: SEND_REFUSAL,
156
+ children: /*#__PURE__*/ _jsx(Button, {
157
+ variant: "outlined",
158
+ size: "small",
159
+ disabled: busy,
160
+ onClick: ()=>void copyLink(),
161
+ children: 'Copy pay link'
162
+ })
163
+ }),
164
+ unpaid ? /*#__PURE__*/ _jsx(BlockedControl, {
165
+ blocked: !canSend,
166
+ reason: SEND_REFUSAL,
167
+ children: /*#__PURE__*/ _jsx(Button, {
168
+ size: "small",
169
+ disabled: busy,
170
+ onClick: ()=>setConfirmingReplace(true),
171
+ children: 'Replace link'
172
+ })
173
+ }) : null
174
+ ]
175
+ }),
176
+ /*#__PURE__*/ _jsxs(Dialog, {
177
+ open: confirmingReplace,
178
+ onClose: ()=>setConfirmingReplace(false),
179
+ maxWidth: "xs",
180
+ fullWidth: true,
181
+ children: [
182
+ /*#__PURE__*/ _jsx(DialogTitle, {
183
+ children: 'Replace the pay link?'
184
+ }),
185
+ /*#__PURE__*/ _jsx(DialogContent, {
186
+ children: /*#__PURE__*/ _jsx(DialogContentText, {
187
+ children: 'The link you sent before will stop working: it will tell the customer the quote was updated, ' + 'and show nothing of it. Send them the new link.'
188
+ })
189
+ }),
190
+ /*#__PURE__*/ _jsxs(DialogActions, {
191
+ children: [
192
+ /*#__PURE__*/ _jsx(Button, {
193
+ onClick: ()=>setConfirmingReplace(false),
194
+ disabled: busy,
195
+ children: 'Cancel'
196
+ }),
197
+ /*#__PURE__*/ _jsx(Button, {
198
+ variant: "contained",
199
+ disabled: busy,
200
+ onClick: ()=>void replaceLink(),
201
+ children: 'Replace link'
202
+ })
203
+ ]
204
+ })
205
+ ]
206
+ })
207
+ ]
208
+ });
209
+ }
210
+ QuotePayLinkSection.displayName = 'QuotePayLinkSection';
211
+ export default QuotePayLinkSection;
212
+
213
+ //# sourceMappingURL=quote-pay-link.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/quote-pay-link.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\n'use client'\n\nimport * as CommerceModel from '../../model'\nimport { commerceSitePermissionRefusal } from '../../model/plugin-permissions'\nimport { BlockedControl } from '@aglyn/shared-ui-jsx/components/blocked-control.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useState } from 'react'\n\nconst SEND_REFUSAL = commerceSitePermissionRefusal('commerce.quotes.send')\n\nexport interface QuotePayLinkSectionProps {\n hostId: string\n quoteId: string\n quote: Pick<CommerceModel.HostOrder, 'status' | 'channel' | 'number'>\n /** Holds \"Send quotes and invoices to customers\" (`commerce.quotes.send`). */\n canSend: boolean\n /** The editor holds changes not saved yet, which the link does not show. */\n edited: boolean\n}\n\n/**\n * A quote's pay link (AGL-4094): the address the business sends the\n * customer, which opens the quote on the business's own site with a Pay\n * button. \"Copy pay link\" asks the server for it (it is signed there) and puts\n * it on the clipboard and on screen; \"Replace link\" makes a new one and the\n * one sent before stops opening the quote.\n */\nexport function QuotePayLinkSection(props: QuotePayLinkSectionProps) {\n const { hostId, quoteId, quote, canSend, edited } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [url, setUrl] = useState('')\n const [busy, setBusy] = useState(false)\n const [confirmingReplace, setConfirmingReplace] = useState(false)\n const unpaid = CommerceModel.isUnpaidQuote(quote)\n\n const ask = useCallback(\n async (action: 'pay-link' | 'replace-link'): Promise<string | null> => {\n setBusy(true)\n try {\n const response = await authorizedFetch(user, '/api/commerce/quote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action, hostId, quoteId }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok || !payload?.url) {\n enqueueSnackbar(payload?.error ?? 'The pay link could not be made', { variant: 'error', allowDuplicate: true })\n return null\n }\n setUrl(String(payload.url))\n return String(payload.url)\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, quoteId, enqueueSnackbar],\n )\n\n const copy = useCallback(\n async (link: string, done: string) => {\n try {\n await navigator.clipboard.writeText(link)\n enqueueSnackbar(done, { variant: 'success', persist: false })\n } catch {\n // The link is on screen to copy by hand when the clipboard is refused.\n enqueueSnackbar('Copy the link below to send it', { variant: 'info', persist: false })\n }\n },\n [enqueueSnackbar],\n )\n\n const copyLink = useCallback(async () => {\n const link = url || (await ask('pay-link'))\n if (link) await copy(link, 'Pay link copied')\n }, [url, ask, copy])\n\n const replaceLink = useCallback(async () => {\n const link = await ask('replace-link')\n setConfirmingReplace(false)\n if (link) await copy(link, 'New pay link copied. The earlier link no longer opens the quote.')\n }, [ask, copy])\n\n return (\n <Stack spacing={1.5}>\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{'Pay link'}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {unpaid\n ? 'Send this link to the customer. It opens the quote on your site, where they can pay it.'\n : 'The link opens the paid quote and the customer’s order.'}\n </Typography>\n {edited && unpaid ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Save your changes first: the link opens the quote as it was last saved.'}\n </Typography>\n ) : null}\n </Stack>\n {url ? (\n <TextField\n label=\"Pay link\"\n value={url}\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { readOnly: true }, inputLabel: { shrink: true } }}\n onFocus={(event) => event.target.select()}\n />\n ) : null}\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap', rowGap: 1 }}>\n <BlockedControl blocked={!canSend} reason={SEND_REFUSAL}>\n <Button variant=\"outlined\" size=\"small\" disabled={busy} onClick={() => void copyLink()}>\n {'Copy pay link'}\n </Button>\n </BlockedControl>\n {unpaid ? (\n <BlockedControl blocked={!canSend} reason={SEND_REFUSAL}>\n <Button size=\"small\" disabled={busy} onClick={() => setConfirmingReplace(true)}>\n {'Replace link'}\n </Button>\n </BlockedControl>\n ) : null}\n </Stack>\n <Dialog open={confirmingReplace} onClose={() => setConfirmingReplace(false)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{'Replace the pay link?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {'The link you sent before will stop working: it will tell the customer the quote was updated, ' +\n 'and show nothing of it. Send them the new link.'}\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmingReplace(false)} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button variant=\"contained\" disabled={busy} onClick={() => void replaceLink()}>\n {'Replace link'}\n </Button>\n </DialogActions>\n </Dialog>\n </Stack>\n )\n}\nQuotePayLinkSection.displayName = 'QuotePayLinkSection'\n\nexport default QuotePayLinkSection\n"],"names":["CommerceModel","commerceSitePermissionRefusal","BlockedControl","useSnackbar","authorizedFetch","useUser","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","TextField","Typography","useCallback","useState","SEND_REFUSAL","QuotePayLinkSection","props","hostId","quoteId","quote","canSend","edited","data","user","enqueueSnackbar","url","setUrl","busy","setBusy","confirmingReplace","setConfirmingReplace","unpaid","isUnpaidQuote","ask","action","response","method","headers","body","JSON","stringify","payload","json","catch","ok","error","variant","allowDuplicate","String","copy","link","done","navigator","clipboard","writeText","persist","copyLink","replaceLink","spacing","color","label","value","size","fullWidth","slotProps","htmlInput","readOnly","inputLabel","shrink","onFocus","event","target","select","direction","sx","flexWrap","rowGap","blocked","reason","disabled","onClick","open","onClose","maxWidth","displayName"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ export interface QuoteSettingsCardProps {
18
+ hostId: string;
19
+ }
20
+ /**
21
+ * The store's quote defaults (AGL-4093), on `hosts/{hostId}/settings/store`
22
+ * under `quotes`: whether a new quote starts out asking the customer to
23
+ * approve the proof before they can pay. Each quote keeps its own setting.
24
+ */
25
+ export declare function QuoteSettingsCard(props: QuoteSettingsCardProps): import("react").JSX.Element;
26
+ export declare namespace QuoteSettingsCard {
27
+ var displayName: string;
28
+ }
29
+ export default QuoteSettingsCard;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import * as CommerceModel from "../../model/index.js";
19
+ import { pluginDocsHelp } from "@aglyn/aglyn";
20
+ import { CardDisplay } from "@aglyn/shared-ui-jsx";
21
+ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
22
+ import { useFirestore, useFirestoreDoc, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
23
+ import { Button, FormControlLabel, FormHelperText, Stack, Switch } from "@mui/material";
24
+ import { doc, setDoc } from "firebase/firestore";
25
+ import { useCallback, useState } from "react";
26
+ /**
27
+ * The store's quote defaults (AGL-4093), on `hosts/{hostId}/settings/store`
28
+ * under `quotes`: whether a new quote starts out asking the customer to
29
+ * approve the proof before they can pay. Each quote keeps its own setting.
30
+ */ export function QuoteSettingsCard(props) {
31
+ const { hostId } = props;
32
+ const firestore = useFirestore();
33
+ const { enqueueSnackbar } = useSnackbar();
34
+ const { data: store, status, // The switch is seeded from this document; a seed the server never
35
+ // confirmed must not be written back over the saved setting (AGL-1358).
36
+ fromCache } = useFirestoreDoc(()=>doc(firestore, 'hosts', hostId, 'settings', 'store'), [
37
+ firestore,
38
+ hostId
39
+ ]);
40
+ const saved = CommerceModel.quoteRequiresProofApprovalByDefault(store == null ? void 0 : store.quotes);
41
+ const [draft, setDraft] = useState(null);
42
+ const current = draft != null ? draft : saved;
43
+ const [busy, setBusy] = useState(false);
44
+ const save = useCallback(async ()=>{
45
+ setBusy(true);
46
+ try {
47
+ const verdict = await writeGuardedBySeed({
48
+ subject: 'quote settings',
49
+ unreadable: status === 'error',
50
+ fromCache
51
+ }, async ()=>{
52
+ await setDoc(doc(firestore, 'hosts', hostId, 'settings', 'store'), {
53
+ quotes: {
54
+ requireProofApproval: current
55
+ }
56
+ }, {
57
+ merge: true
58
+ });
59
+ });
60
+ if (!verdict.ok) {
61
+ return void enqueueSnackbar(verdict.message, {
62
+ variant: 'warning',
63
+ persist: false
64
+ });
65
+ }
66
+ setDraft(null);
67
+ enqueueSnackbar('Quote settings saved', {
68
+ variant: 'success',
69
+ persist: false
70
+ });
71
+ } finally{
72
+ setBusy(false);
73
+ }
74
+ }, [
75
+ current,
76
+ firestore,
77
+ hostId,
78
+ status,
79
+ fromCache,
80
+ enqueueSnackbar
81
+ ]);
82
+ return /*#__PURE__*/ _jsx(CardDisplay, {
83
+ header: 'Quotes',
84
+ help: pluginDocsHelp('quotes', {
85
+ anchor: '#quote-defaults',
86
+ title: 'Quotes',
87
+ excerpt: 'What every new quote starts with. Each quote can change it.'
88
+ }),
89
+ HeaderProps: {
90
+ action: /*#__PURE__*/ _jsx(Button, {
91
+ size: "small",
92
+ variant: "contained",
93
+ disabled: busy || draft === null || status === 'loading',
94
+ onClick: ()=>void save(),
95
+ children: 'Save'
96
+ })
97
+ },
98
+ contentGutterX: true,
99
+ contentGutterY: true,
100
+ children: /*#__PURE__*/ _jsxs(Stack, {
101
+ spacing: 0.5,
102
+ children: [
103
+ /*#__PURE__*/ _jsx(FormControlLabel, {
104
+ control: /*#__PURE__*/ _jsx(Switch, {
105
+ checked: current,
106
+ disabled: busy || status === 'loading',
107
+ onChange: (event)=>setDraft(event.target.checked)
108
+ }),
109
+ label: "Customers approve the proof before they can pay"
110
+ }),
111
+ /*#__PURE__*/ _jsx(FormHelperText, {
112
+ children: 'New quotes start with this setting. You can change it on each quote.'
113
+ })
114
+ ]
115
+ })
116
+ });
117
+ }
118
+ QuoteSettingsCard.displayName = 'QuoteSettingsCard';
119
+ export default QuoteSettingsCard;
120
+
121
+ //# sourceMappingURL=quote-settings-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/quote-settings-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\n'use client'\n\nimport * as CommerceModel from '../../model'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { useFirestore, useFirestoreDoc, writeGuardedBySeed } from '@aglyn/tenant-feature-instance'\nimport { Button, FormControlLabel, FormHelperText, Stack, Switch } from '@mui/material'\nimport { doc, setDoc } from 'firebase/firestore'\nimport { useCallback, useState } from 'react'\n\nexport interface QuoteSettingsCardProps {\n hostId: string\n}\n\n/**\n * The store's quote defaults (AGL-4093), on `hosts/{hostId}/settings/store`\n * under `quotes`: whether a new quote starts out asking the customer to\n * approve the proof before they can pay. Each quote keeps its own setting.\n */\nexport function QuoteSettingsCard(props: QuoteSettingsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { enqueueSnackbar } = useSnackbar()\n const {\n data: store,\n status,\n // The switch is seeded from this document; a seed the server never\n // confirmed must not be written back over the saved setting (AGL-1358).\n fromCache,\n } = useFirestoreDoc<any>(() => doc(firestore, 'hosts', hostId, 'settings', 'store'), [firestore, hostId])\n const saved = CommerceModel.quoteRequiresProofApprovalByDefault(store?.quotes)\n const [draft, setDraft] = useState<boolean | null>(null)\n const current = draft ?? saved\n const [busy, setBusy] = useState(false)\n\n const save = useCallback(async () => {\n setBusy(true)\n try {\n const verdict = await writeGuardedBySeed(\n { subject: 'quote settings', unreadable: status === 'error', fromCache },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'settings', 'store'),\n { quotes: { requireProofApproval: current } },\n { merge: true },\n )\n },\n )\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, { variant: 'warning', persist: false })\n }\n setDraft(null)\n enqueueSnackbar('Quote settings saved', { variant: 'success', persist: false })\n } finally {\n setBusy(false)\n }\n }, [current, firestore, hostId, status, fromCache, enqueueSnackbar])\n\n return (\n <CardDisplay\n header={'Quotes'}\n help={pluginDocsHelp('quotes', {\n anchor: '#quote-defaults',\n title: 'Quotes',\n excerpt: 'What every new quote starts with. Each quote can change it.',\n })}\n HeaderProps={{\n action: (\n <Button size=\"small\" variant=\"contained\" disabled={busy || draft === null || status === 'loading'} onClick={() => void save()}>\n {'Save'}\n </Button>\n ),\n }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={0.5}>\n <FormControlLabel\n control={\n <Switch\n checked={current}\n disabled={busy || status === 'loading'}\n onChange={(event) => setDraft(event.target.checked)}\n />\n }\n label=\"Customers approve the proof before they can pay\"\n />\n <FormHelperText>{'New quotes start with this setting. You can change it on each quote.'}</FormHelperText>\n </Stack>\n </CardDisplay>\n )\n}\nQuoteSettingsCard.displayName = 'QuoteSettingsCard'\n\nexport default QuoteSettingsCard\n"],"names":["CommerceModel","pluginDocsHelp","CardDisplay","useSnackbar","useFirestore","useFirestoreDoc","writeGuardedBySeed","Button","FormControlLabel","FormHelperText","Stack","Switch","doc","setDoc","useCallback","useState","QuoteSettingsCard","props","hostId","firestore","enqueueSnackbar","data","store","status","fromCache","saved","quoteRequiresProofApprovalByDefault","quotes","draft","setDraft","current","busy","setBusy","save","verdict","subject","unreadable","requireProofApproval","merge","ok","message","variant","persist","header","help","anchor","title","excerpt","HeaderProps","action","size","disabled","onClick","contentGutterX","contentGutterY","spacing","control","checked","onChange","event","target","label","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;AAEA,YAAYA,mBAAmB,uBAAa;AAC5C,SAASC,cAAc,QAAQ,eAAc;AAC7C,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SAASC,YAAY,EAAEC,eAAe,EAAEC,kBAAkB,QAAQ,iCAAgC;AAClG,SAASC,MAAM,EAAEC,gBAAgB,EAAEC,cAAc,EAAEC,KAAK,EAAEC,MAAM,QAAQ,gBAAe;AACvF,SAASC,GAAG,EAAEC,MAAM,QAAQ,qBAAoB;AAChD,SAASC,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAM7C;;;;CAIC,GACD,OAAO,SAASC,kBAAkBC,KAA6B;IAC7D,MAAM,EAAEC,MAAM,EAAE,GAAGD;IACnB,MAAME,YAAYf;IAClB,MAAM,EAAEgB,eAAe,EAAE,GAAGjB;IAC5B,MAAM,EACJkB,MAAMC,KAAK,EACXC,MAAM,EACN,mEAAmE;IACnE,wEAAwE;IACxEC,SAAS,EACV,GAAGnB,gBAAqB,IAAMO,IAAIO,WAAW,SAASD,QAAQ,YAAY,UAAU;QAACC;QAAWD;KAAO;IACxG,MAAMO,QAAQzB,cAAc0B,mCAAmC,CAACJ,yBAAAA,MAAOK,MAAM;IAC7E,MAAM,CAACC,OAAOC,SAAS,GAAGd,SAAyB;IACnD,MAAMe,UAAUF,gBAAAA,QAASH;IACzB,MAAM,CAACM,MAAMC,QAAQ,GAAGjB,SAAS;IAEjC,MAAMkB,OAAOnB,YAAY;QACvBkB,QAAQ;QACR,IAAI;YACF,MAAME,UAAU,MAAM5B,mBACpB;gBAAE6B,SAAS;gBAAkBC,YAAYb,WAAW;gBAASC;YAAU,GACvE;gBACE,MAAMX,OACJD,IAAIO,WAAW,SAASD,QAAQ,YAAY,UAC5C;oBAAES,QAAQ;wBAAEU,sBAAsBP;oBAAQ;gBAAE,GAC5C;oBAAEQ,OAAO;gBAAK;YAElB;YAEF,IAAI,CAACJ,QAAQK,EAAE,EAAE;gBACf,OAAO,KAAKnB,gBAAgBc,QAAQM,OAAO,EAAE;oBAAEC,SAAS;oBAAWC,SAAS;gBAAM;YACpF;YACAb,SAAS;YACTT,gBAAgB,wBAAwB;gBAAEqB,SAAS;gBAAWC,SAAS;YAAM;QAC/E,SAAU;YACRV,QAAQ;QACV;IACF,GAAG;QAACF;QAASX;QAAWD;QAAQK;QAAQC;QAAWJ;KAAgB;IAEnE,qBACE,KAAClB;QACCyC,QAAQ;QACRC,MAAM3C,eAAe,UAAU;YAC7B4C,QAAQ;YACRC,OAAO;YACPC,SAAS;QACX;QACAC,aAAa;YACXC,sBACE,KAAC1C;gBAAO2C,MAAK;gBAAQT,SAAQ;gBAAYU,UAAUpB,QAAQH,UAAU,QAAQL,WAAW;gBAAW6B,SAAS,IAAM,KAAKnB;0BACpH;;QAGP;QACAoB,cAAc;QACdC,cAAc;kBAEd,cAAA,MAAC5C;YAAM6C,SAAS;;8BACd,KAAC/C;oBACCgD,uBACE,KAAC7C;wBACC8C,SAAS3B;wBACTqB,UAAUpB,QAAQR,WAAW;wBAC7BmC,UAAU,CAACC,QAAU9B,SAAS8B,MAAMC,MAAM,CAACH,OAAO;;oBAGtDI,OAAM;;8BAER,KAACpD;8BAAgB;;;;;AAIzB;AACAO,kBAAkB8C,WAAW,GAAG;AAEhC,eAAe9C,kBAAiB"}