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

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 (66) hide show
  1. package/README.md +2 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/console/commerce-pdf-download.d.ts +30 -0
  4. package/src/lib/components/console/commerce-pdf-download.js +53 -0
  5. package/src/lib/components/console/commerce-pdf-download.js.map +1 -0
  6. package/src/lib/components/console/host-quotes-card.component.js +20 -4
  7. package/src/lib/components/console/host-quotes-card.component.js.map +1 -1
  8. package/src/lib/components/console/order-invoice.component.d.ts +6 -4
  9. package/src/lib/components/console/order-invoice.component.js +67 -11
  10. package/src/lib/components/console/order-invoice.component.js.map +1 -1
  11. package/src/lib/components/console/quote-editor-dialog.component.js +53 -2
  12. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -1
  13. package/src/lib/components/console/quote-proofs.component.d.ts +37 -0
  14. package/src/lib/components/console/quote-proofs.component.js +626 -0
  15. package/src/lib/components/console/quote-proofs.component.js.map +1 -0
  16. package/src/lib/components/quote-page-body.js +29 -1
  17. package/src/lib/components/quote-page-body.js.map +1 -1
  18. package/src/lib/components/quote-proof-panel.d.ts +42 -0
  19. package/src/lib/components/quote-proof-panel.js +436 -0
  20. package/src/lib/components/quote-proof-panel.js.map +1 -0
  21. package/src/lib/model/commerce-quote-pay.d.ts +27 -0
  22. package/src/lib/model/commerce-quote-pay.js +36 -3
  23. package/src/lib/model/commerce-quote-pay.js.map +1 -1
  24. package/src/lib/model/commerce-quote-proofs.d.ts +159 -0
  25. package/src/lib/model/commerce-quote-proofs.js +348 -0
  26. package/src/lib/model/commerce-quote-proofs.js.map +1 -0
  27. package/src/lib/model/commerce-quotes.d.ts +59 -3
  28. package/src/lib/model/commerce-quotes.js.map +1 -1
  29. package/src/lib/model/index.d.ts +1 -0
  30. package/src/lib/model/index.js +1 -0
  31. package/src/lib/model/index.js.map +1 -1
  32. package/src/lib/server/commerce-pdf.d.ts +100 -0
  33. package/src/lib/server/commerce-pdf.js +283 -0
  34. package/src/lib/server/commerce-pdf.js.map +1 -0
  35. package/src/lib/server/order-print.d.ts +6 -0
  36. package/src/lib/server/order-print.js +22 -5
  37. package/src/lib/server/order-print.js.map +1 -1
  38. package/src/lib/server/pdf-response.d.ts +31 -0
  39. package/src/lib/server/pdf-response.js +30 -0
  40. package/src/lib/server/pdf-response.js.map +1 -0
  41. package/src/lib/server/pos-reader-splash.d.ts +2 -18
  42. package/src/lib/server/pos-reader-splash.js +8 -93
  43. package/src/lib/server/pos-reader-splash.js.map +1 -1
  44. package/src/lib/server/quote-pay.d.ts +31 -4
  45. package/src/lib/server/quote-pay.js +11 -11
  46. package/src/lib/server/quote-pay.js.map +1 -1
  47. package/src/lib/server/quote-proofs.d.ts +51 -0
  48. package/src/lib/server/quote-proofs.js +500 -0
  49. package/src/lib/server/quote-proofs.js.map +1 -0
  50. package/src/lib/server/quote-uploads.d.ts +33 -0
  51. package/src/lib/server/quote-uploads.js +29 -0
  52. package/src/lib/server/quote-uploads.js.map +1 -0
  53. package/src/lib/server/quote.d.ts +14 -0
  54. package/src/lib/server/quote.js +336 -3
  55. package/src/lib/server/quote.js.map +1 -1
  56. package/src/lib/server/site-image-source.d.ts +38 -0
  57. package/src/lib/server/site-image-source.js +130 -0
  58. package/src/lib/server/site-image-source.js.map +1 -0
  59. package/src/lib/server.js +19 -1
  60. package/src/lib/server.js.map +1 -1
  61. package/src/lib/utils/commerce-document-pdf.d.ts +77 -0
  62. package/src/lib/utils/commerce-document-pdf.js +608 -0
  63. package/src/lib/utils/commerce-document-pdf.js.map +1 -0
  64. package/src/lib/utils/order-invoice.d.ts +52 -3
  65. package/src/lib/utils/order-invoice.js +116 -64
  66. package/src/lib/utils/order-invoice.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/quote-proofs.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 {\n checkVisitorUploadSelection,\n formatVisitorUploadBytes,\n visitorUploadIsInline,\n VISITOR_UPLOAD_ACCEPT,\n VISITOR_UPLOAD_MAX_BYTES,\n} from '@aglyn/aglyn/app-utils/visitor-upload'\nimport { sendVisitorUpload } from '@aglyn/aglyn/app-utils/visitor-upload-client'\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 Alert,\n Box,\n Button,\n Chip,\n CircularProgress,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Divider,\n Paper,\n Stack,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\n\nconst REFUSAL = commerceSitePermissionRefusal('commerce.quotes')\n\ntype User = Parameters<typeof authorizedFetch>[0]\n\n/** A file the console lists: a proof, or one the customer sent. Never its storage path. */\ninterface ListedFile {\n id: string\n name: string\n contentType: string\n size: number\n}\n\n/** An earlier revision as the route lists it. */\ntype RevisionView = Omit<CommerceModel.QuoteRevisionSnapshot, 'proofs' | 'responses'> & {\n proofs: ListedFile[]\n responses: Array<Omit<CommerceModel.QuoteCustomerResponse, 'files'> & { files?: ListedFile[] }>\n}\n\nexport interface QuoteProofsSectionProps {\n hostId: string\n quoteId: string\n quote: CommerceModel.HostOrder\n /** Holds \"Create and edit quotes\" (`commerce.quotes`). */\n canEdit: boolean\n /** A change here moved the quote's edit stamp; the editor saves against the new one. */\n onEdited: (updatedAtMs: number) => void\n}\n\nasync function postQuote(user: User, body: Record<string, unknown>): Promise<{ ok: boolean; payload: Record<string, any> }> {\n const response = await authorizedFetch(user, '/api/commerce/quote', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n return { ok: response.ok, payload: await response.json().catch(() => ({})) }\n}\n\n/** One of the quote's files as a blob, fetched with the member's token; null when refused. */\nasync function fetchQuoteFile(\n user: User,\n body: { hostId: string; quoteId: string; fileId: string; revision?: number },\n): Promise<Blob | null> {\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: 'file', ...body }),\n })\n return response.ok ? await response.blob() : null\n } catch {\n return null\n }\n}\n\nfunction dateTime(atMs: number | undefined): string {\n return atMs ? new Date(atMs).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : ''\n}\n\n/** A picture of an image proof, loaded with the member's token. */\nfunction ProofThumbnail(props: { user: User; hostId: string; quoteId: string; file: ListedFile; revision?: number }) {\n const { user, hostId, quoteId, file, revision } = props\n const [src, setSrc] = useState<string | null>(null)\n useEffect(() => {\n let live = true\n let url = ''\n void fetchQuoteFile(user, { hostId, quoteId, fileId: file.id, ...(revision ? { revision } : {}) }).then((blob) => {\n if (!live || !blob) return\n url = URL.createObjectURL(blob)\n setSrc(url)\n })\n return () => {\n live = false\n if (url) URL.revokeObjectURL(url)\n }\n }, [user, hostId, quoteId, file.id, revision])\n return (\n <Box\n sx={(theme) => ({\n width: theme.spacing(16),\n height: theme.spacing(12),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: 'action.hover',\n borderRadius: 1,\n overflow: 'hidden',\n })}\n >\n {src ? (\n <Box component=\"img\" src={src} alt={file.name} sx={{ maxWidth: 1, maxHeight: 1, objectFit: 'contain' }} />\n ) : (\n <CircularProgress size={20} aria-label={`Loading ${file.name}`} />\n )}\n </Box>\n )\n}\n\n/** A file: a picture for an image, a chip naming it for anything else; both download it. */\nfunction QuoteFileTile(props: {\n user: User\n hostId: string\n quoteId: string\n file: ListedFile\n revision?: number\n onDownload: (file: ListedFile, revision?: number) => void\n onRemove?: () => void\n removeBlocked?: boolean\n}) {\n const { file, revision, onDownload, onRemove, removeBlocked } = props\n const image = visitorUploadIsInline(file.contentType)\n return (\n <Paper variant=\"outlined\" sx={{ p: 1 }}>\n <Stack spacing={1} sx={(theme) => ({ width: image ? theme.spacing(16) : 'auto', maxWidth: theme.spacing(32) })}>\n {image ? <ProofThumbnail {...props} /> : null}\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`${file.name} · ${formatVisitorUploadBytes(file.size)}`}\n onClick={() => onDownload(file, revision)}\n title={`Download ${file.name}`}\n />\n {onRemove ? (\n <BlockedControl blocked={Boolean(removeBlocked)} reason={REFUSAL}>\n <Button size=\"small\" color=\"inherit\" onClick={onRemove} aria-label={`Remove ${file.name}`}>\n {'Remove'}\n </Button>\n </BlockedControl>\n ) : null}\n </Stack>\n </Paper>\n )\n}\n\n/** What the customer said, with any files they sent. */\nfunction QuoteResponseNote(props: {\n response: Omit<CommerceModel.QuoteCustomerResponse, 'files'> & { files?: ListedFile[] }\n tile: (file: ListedFile) => ReactNode\n}) {\n const { response, tile } = props\n if (response.action === 'approve') {\n return (\n <Alert severity=\"success\">\n <Stack spacing={0.5}>\n <Typography variant=\"body2\">{`Approved by ${response.name || 'the customer'} on ${dateTime(response.atMs)}.`}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[response.ip ? `From ${response.ip}` : '', response.userAgent ?? ''].filter(Boolean).join(' · ')}\n </Typography>\n </Stack>\n </Alert>\n )\n }\n return (\n <Alert severity=\"warning\">\n <Stack spacing={1}>\n <Typography variant=\"body2\">{`Changes requested on ${dateTime(response.atMs)}:`}</Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-line' }}>\n {response.comment}\n </Typography>\n {response.files?.length ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {response.files.map((file) => tile(file))}\n </Stack>\n ) : null}\n </Stack>\n </Alert>\n )\n}\n\n/**\n * A quote's proofs and revisions (AGL-4096), in its editor: the current\n * revision's proofs (a picture for an image, a chip for a PDF or a design\n * file), Add proof, what the customer last said with any files they sent,\n * \"Start revision N+1\", and every earlier revision as it was kept.\n */\nexport function QuoteProofsSection(props: QuoteProofsSectionProps) {\n const { hostId, quoteId, quote, canEdit, onEdited } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const section = quote.quote\n const revision = Math.max(1, Number(section?.revision ?? 1) || 1)\n const proofs = CommerceModel.currentQuoteProofs(section)\n const latest = CommerceModel.latestQuoteResponse(section)\n const unpaid = CommerceModel.isUnpaidQuote(quote)\n const addRefusal = CommerceModel.quoteProofChangeRefusal(quote, 'add')\n const removable = CommerceModel.quoteProofChangeRefusal(quote, 'remove') === null\n const [sending, setSending] = useState<{ done: number; total: number } | null>(null)\n const [busy, setBusy] = useState(false)\n const [confirmingRevision, setConfirmingRevision] = useState(false)\n const [history, setHistory] = useState<RevisionView[] | null>(null)\n const [historyError, setHistoryError] = useState('')\n const picker = useRef<HTMLInputElement>(null)\n\n const loadHistory = useCallback(async () => {\n setHistoryError('')\n const answer = await postQuote(user, { action: 'revisions', hostId, quoteId }).catch(() => null)\n if (!answer?.ok) {\n setHistoryError(String(answer?.payload?.error ?? 'Earlier revisions could not be loaded.'))\n return\n }\n setHistory(Array.isArray(answer.payload['revisions']) ? (answer.payload['revisions'] as RevisionView[]) : [])\n }, [user, hostId, quoteId])\n\n // Earlier revisions are read when there are some, and again after one is added.\n useEffect(() => {\n if (revision > 1) void loadHistory()\n }, [revision, loadHistory])\n\n const download = useCallback(\n async (file: ListedFile, fromRevision?: number) => {\n const blob = await fetchQuoteFile(user, { hostId, quoteId, fileId: file.id, ...(fromRevision ? { revision: fromRevision } : {}) })\n if (!blob) return void enqueueSnackbar('The file could not be downloaded', { variant: 'error', allowDuplicate: true })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = file.name\n link.click()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n },\n [user, hostId, quoteId, enqueueSnackbar],\n )\n\n const addProofs = useCallback(\n async (files: File[]) => {\n const problem = checkVisitorUploadSelection(files, proofs.length, CommerceModel.QUOTE_MAX_PROOFS)\n if (problem) return void enqueueSnackbar(problem, { variant: 'error', allowDuplicate: true })\n setSending({ done: 0, total: files.length })\n try {\n for (const [index, file] of files.entries()) {\n let stamp = 0\n const sent = await sendVisitorUpload({\n file,\n requestTicket: async (request) => {\n const answer = await postQuote(user, { action: 'proof-ticket', hostId, quoteId, file: request })\n return answer.ok\n ? (answer.payload as { ticket: string; upload: { url: string; fields: Record<string, string> } })\n : { error: String(answer.payload['error'] ?? 'The proof could not be sent') }\n },\n finalize: async (ticket) => {\n const answer = await postQuote(user, { action: 'proof-finalize', hostId, quoteId, ticket })\n if (!answer.ok) return { error: String(answer.payload['error'] ?? 'The proof could not be kept') }\n stamp = Number(answer.payload['updatedAtMs']) || 0\n return { file: answer.payload['proof'] }\n },\n })\n if ('error' in sent) {\n enqueueSnackbar(sent.error, { variant: 'error', allowDuplicate: true })\n break\n }\n if (stamp) onEdited(stamp)\n setSending({ done: index + 1, total: files.length })\n }\n } finally {\n setSending(null)\n }\n },\n [user, hostId, quoteId, proofs.length, onEdited, enqueueSnackbar],\n )\n\n const removeProof = useCallback(\n async (proofId: string) => {\n setBusy(true)\n try {\n const answer = await postQuote(user, { action: 'proof-remove', hostId, quoteId, proofId })\n if (!answer.ok) {\n return void enqueueSnackbar(String(answer.payload['error'] ?? 'The proof could not be removed'), {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n onEdited(Number(answer.payload['updatedAtMs']) || 0)\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, quoteId, onEdited, enqueueSnackbar],\n )\n\n const startRevision = useCallback(async () => {\n setBusy(true)\n try {\n const answer = await postQuote(user, { action: 'start-revision', hostId, quoteId })\n if (!answer.ok) {\n return void enqueueSnackbar(String(answer.payload['error'] ?? 'The revision could not be started'), {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n onEdited(Number(answer.payload['updatedAtMs']) || 0)\n enqueueSnackbar(`Revision ${Number(answer.payload['revision']) || revision + 1} started`, { variant: 'success', persist: false })\n setConfirmingRevision(false)\n } finally {\n setBusy(false)\n }\n }, [user, hostId, quoteId, revision, onEdited, enqueueSnackbar])\n\n const tile = (file: ListedFile, fromRevision?: number, onRemove?: () => void) => (\n <QuoteFileTile\n key={`${fromRevision ?? 'current'}-${file.id}`}\n user={user}\n hostId={hostId}\n quoteId={quoteId}\n file={file}\n revision={fromRevision}\n onDownload={(picked, at) => void download(picked, at)}\n onRemove={onRemove}\n removeBlocked={!canEdit}\n />\n )\n\n const earlier = (history ?? []).filter((entry) => Number(entry.revision) < revision).reverse()\n\n return (\n <Stack spacing={1.5}>\n <Stack spacing={0.5}>\n <Typography variant=\"subtitle2\">{`Proofs · Revision ${revision}`}</Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {section?.requireProofApproval\n ? 'The customer sees these on the quote page and approves them before they can pay.'\n : 'The customer sees these on the quote page, and can approve them or ask for changes. Paying doesn’t wait on it.'}\n </Typography>\n </Stack>\n\n {latest ? <QuoteResponseNote response={latest} tile={(file) => tile(file)} /> : null}\n\n {proofs.length ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {proofs.map((proof) =>\n tile(proof, undefined, removable ? () => void removeProof(proof.id) : undefined),\n )}\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No proofs on this revision yet. Add an image, a PDF or a design file for the customer to approve.'}\n </Typography>\n )}\n\n {unpaid ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap', alignItems: 'center' }}>\n <input\n ref={picker}\n type=\"file\"\n multiple\n hidden\n accept={VISITOR_UPLOAD_ACCEPT}\n data-testid=\"quote-proof-picker\"\n onChange={(event) => {\n const files = Array.from(event.target.files ?? [])\n event.target.value = ''\n if (files.length) void addProofs(files)\n }}\n />\n <BlockedControl\n blocked={!canEdit || Boolean(addRefusal)}\n reason={!canEdit ? REFUSAL : addRefusal ? CommerceModel.quoteProofRefusalMessage(addRefusal) : ''}\n >\n <Button variant=\"outlined\" size=\"small\" disabled={busy || Boolean(sending)} onClick={() => picker.current?.click()}>\n {sending ? `Sending ${sending.done + 1} of ${sending.total}…` : 'Add proof'}\n </Button>\n </BlockedControl>\n <BlockedControl blocked={!canEdit} reason={REFUSAL}>\n <Button size=\"small\" disabled={busy || Boolean(sending)} onClick={() => setConfirmingRevision(true)}>\n {`Start revision ${revision + 1}`}\n </Button>\n </BlockedControl>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Up to ${CommerceModel.QUOTE_MAX_PROOFS} files, ${formatVisitorUploadBytes(VISITOR_UPLOAD_MAX_BYTES)} each.`}\n </Typography>\n </Stack>\n ) : null}\n\n {revision > 1 ? (\n <Stack spacing={1.5}>\n <Divider />\n <Typography variant=\"subtitle2\">{'Earlier revisions'}</Typography>\n {historyError ? <Alert severity=\"error\">{historyError}</Alert> : null}\n {history === null && !historyError ? <CircularProgress size={20} aria-label=\"Loading earlier revisions\" /> : null}\n {earlier.map((entry) => (\n <Paper key={entry.revision} variant=\"outlined\" sx={{ p: 2 }}>\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 0.5 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 'fontWeightMedium' }}>{`Revision ${entry.revision}`}</Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={CommerceModel.QUOTE_STAGE_LABELS[entry.stage] ?? entry.stage}\n color={CommerceModel.QUOTE_STATUS_COLOR[entry.stage] ?? 'default'}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Replaced ${dateTime(entry.closedAtMs)}`}\n </Typography>\n </Stack>\n {entry.proofs.length ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {entry.proofs.map((proof) => tile(proof, entry.revision))}\n </Stack>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No proofs.'}\n </Typography>\n )}\n {entry.responses.map((response, index) => (\n <QuoteResponseNote key={index} response={response} tile={(file) => tile(file, entry.revision)} />\n ))}\n </Stack>\n </Paper>\n ))}\n </Stack>\n ) : null}\n\n <Dialog open={confirmingRevision} onClose={() => setConfirmingRevision(false)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>{`Start revision ${revision + 1}?`}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {`Revision ${revision} is kept as it is now, with its proofs and the customer’s answers. ` +\n `Revision ${revision + 1} starts with no proofs, ready for new ones and any changes to the quote.`}\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmingRevision(false)} disabled={busy}>\n {'Cancel'}\n </Button>\n <Button variant=\"contained\" disabled={busy} onClick={() => void startRevision()}>\n {`Start revision ${revision + 1}`}\n </Button>\n </DialogActions>\n </Dialog>\n </Stack>\n )\n}\nQuoteProofsSection.displayName = 'QuoteProofsSection'\n\nexport default QuoteProofsSection\n"],"names":["CommerceModel","commerceSitePermissionRefusal","checkVisitorUploadSelection","formatVisitorUploadBytes","visitorUploadIsInline","VISITOR_UPLOAD_ACCEPT","VISITOR_UPLOAD_MAX_BYTES","sendVisitorUpload","BlockedControl","useSnackbar","authorizedFetch","useUser","Alert","Box","Button","Chip","CircularProgress","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Divider","Paper","Stack","Typography","useCallback","useEffect","useRef","useState","REFUSAL","postQuote","user","body","response","method","headers","JSON","stringify","ok","payload","json","catch","fetchQuoteFile","action","blob","dateTime","atMs","Date","toLocaleString","undefined","dateStyle","timeStyle","ProofThumbnail","props","hostId","quoteId","file","revision","src","setSrc","live","url","fileId","id","then","URL","createObjectURL","revokeObjectURL","sx","theme","width","spacing","height","display","alignItems","justifyContent","bgcolor","borderRadius","overflow","component","alt","name","maxWidth","maxHeight","objectFit","size","aria-label","QuoteFileTile","onDownload","onRemove","removeBlocked","image","contentType","variant","p","label","onClick","title","blocked","Boolean","reason","color","QuoteResponseNote","tile","severity","ip","userAgent","filter","join","whiteSpace","comment","files","length","direction","useFlexGap","flexWrap","map","QuoteProofsSection","quote","canEdit","onEdited","data","enqueueSnackbar","section","Math","max","Number","proofs","currentQuoteProofs","latest","latestQuoteResponse","unpaid","isUnpaidQuote","addRefusal","quoteProofChangeRefusal","removable","sending","setSending","busy","setBusy","confirmingRevision","setConfirmingRevision","history","setHistory","historyError","setHistoryError","picker","loadHistory","answer","String","error","Array","isArray","download","fromRevision","allowDuplicate","link","document","createElement","href","click","setTimeout","addProofs","problem","QUOTE_MAX_PROOFS","done","total","index","entries","stamp","sent","requestTicket","request","finalize","ticket","removeProof","proofId","startRevision","persist","picked","at","earlier","entry","reverse","requireProofApproval","proof","input","ref","type","multiple","hidden","accept","data-testid","onChange","event","from","target","value","quoteProofRefusalMessage","disabled","current","rowGap","fontWeight","QUOTE_STAGE_LABELS","stage","QUOTE_STATUS_COLOR","closedAtMs","responses","open","onClose","fullWidth","displayName"],"mappings":"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"}
@@ -28,6 +28,7 @@ import Stack from "@mui/material/Stack";
28
28
  import Typography from "@mui/material/Typography";
29
29
  import { forwardRef, lazy, Suspense, useCallback, useEffect, useRef, useState } from "react";
30
30
  import { formatOrderMoney, readStorefrontCheckoutWallets } from "../model/index.js";
31
+ import { QuoteProofPanel } from "./quote-proof-panel.js";
31
32
  import { StorefrontPaymentElementFallback } from "./storefront-payment-element-fallback.js";
32
33
  /** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */ const StorefrontPaymentElement = /*#__PURE__*/ lazy(()=>import("./storefront-payment-element.js").then((module)=>({
33
34
  default: module.StorefrontPaymentElement
@@ -384,6 +385,8 @@ function TotalRow({ label, value, strong }) {
384
385
  }
385
386
  const quote = state.view;
386
387
  const money = (cents)=>formatOrderMoney(cents, quote.currency);
388
+ // The same signed link as the page's data; the server makes the PDF from the same view.
389
+ const pdfHref = `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` + `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`;
387
390
  const unpaid = quote.status === 'unpaid';
388
391
  const addresses = [
389
392
  quote.customerName || quote.company ? {
@@ -470,7 +473,16 @@ function TotalRow({ label, value, strong }) {
470
473
  variant: "body2",
471
474
  color: "text.secondary",
472
475
  children: `Dated ${dateLabel(quote.dateMs)}`
473
- }) : null
476
+ }) : null,
477
+ /*#__PURE__*/ _jsx(Box, {
478
+ children: /*#__PURE__*/ _jsx(Button, {
479
+ variant: "outlined",
480
+ size: "small",
481
+ href: pdfHref,
482
+ download: true,
483
+ children: 'Download PDF'
484
+ })
485
+ })
474
486
  ]
475
487
  }),
476
488
  addresses.length ? /*#__PURE__*/ _jsx(Stack, {
@@ -589,6 +601,22 @@ function TotalRow({ label, value, strong }) {
589
601
  })
590
602
  ]
591
603
  }) : null,
604
+ /*#__PURE__*/ _jsx(QuoteProofPanel, {
605
+ view: quote,
606
+ hostId: hostId,
607
+ quoteId: link.current.quoteId,
608
+ token: link.current.token,
609
+ siteFetch: siteFetch,
610
+ onView: (next)=>setState({
611
+ kind: 'ready',
612
+ view: next
613
+ }),
614
+ onReload: ()=>void load().then(setState),
615
+ onReplaced: ()=>setState({
616
+ kind: 'replaced',
617
+ storeName: quote.storeName
618
+ })
619
+ }),
592
620
  unpaid ? /*#__PURE__*/ _jsx(Paper, {
593
621
  variant: "outlined",
594
622
  sx: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/quote-page-body.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 * as Aglyn from '@aglyn/aglyn'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport type { StripeCheckoutContact } from '@stripe/stripe-js'\nimport { forwardRef, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'\nimport {\n formatOrderMoney,\n readStorefrontCheckoutWallets,\n type QuotePageAddress,\n type QuotePageView,\n type StorefrontCheckoutWallets,\n} from '../model'\nimport type { QuotePageProps } from './quote-page'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\n\n/** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'replaced'; storeName: string }\n | { kind: 'ready'; view: QuotePageView }\n\n/** After a payment returns here, how often and how long the page asks whether it landed. */\nconst CONFIRM_POLL_MS = 2_000\nconst CONFIRM_POLLS = 15\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nfunction addressLines(address: QuotePageAddress): string[] {\n const cityLine = [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')]\n .filter(Boolean)\n .join(', ')\n return [address.name, address.line1, address.line2, cityLine, address.country].filter(\n (line): line is string => Boolean(line),\n )\n}\n\nfunction stripeContact(address: QuotePageAddress | null): StripeCheckoutContact | undefined {\n if (!address?.country) return undefined\n return {\n name: address.name,\n address: {\n country: address.country,\n line1: address.line1,\n line2: address.line2,\n city: address.city,\n state: address.state,\n postal_code: address.postalCode,\n },\n }\n}\n\nfunction AddressBlock({ label, lines }: { label: string; lines: string[] }) {\n return (\n <Stack spacing={0.25} sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n {lines.map((line, index) => (\n <Typography key={index} variant=\"body2\">\n {line}\n </Typography>\n ))}\n </Stack>\n )\n}\n\nfunction TotalRow({ label, value, strong }: { label: string; value: string; strong?: boolean }) {\n return (\n <Stack direction=\"row\" spacing={2} 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'} color={strong ? 'text.primary' : 'text.secondary'}>\n {value}\n </Typography>\n </Stack>\n )\n}\n\n/**\n * The customer's quote page (AGL-4094), loaded when the page draws it (see\n * `quote-page.tsx`): what a customer sees when they open\n * the pay link a business sent them. The commerce page resolver serves it at\n * `/pay-quote` inside the site's own header and footer; a business can also\n * place it on a page of their own design at that address.\n *\n * The quote is read AFTER hydration from `?q=&t=`, so the page itself is the\n * same for every customer and may be cached, and the quote never is. Pay asks\n * the server for a fresh payment for the quote as the page shows it: Stripe's\n * own page, or the payment form here when in-page payments are on. Nothing\n * here decides a quote is paid; after paying, the page reads that from the\n * server like any other visit.\n */\nconst QuotePageBody = forwardRef<HTMLDivElement, QuotePageProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n const [paying, setPaying] = useState(false)\n const [payError, setPayError] = useState('')\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n wallets?: StorefrontCheckoutWallets\n } | null>(null)\n /** What a return from paying turned out to be: still being confirmed, or not paid. */\n const [returned, setReturned] = useState<'confirming' | 'unconfirmed' | 'failed' | null>(null)\n const link = useRef({ quoteId: '', token: '', sessionId: '' })\n\n const load = useCallback(async (): Promise<LoadState> => {\n const { quoteId, token } = link.current\n try {\n const response = await siteFetch(\n `/api/commerce/quote-view?hostId=${encodeURIComponent(hostId ?? '')}` +\n `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return { kind: 'missing', message: String(payload?.error ?? 'We could not find that quote.') }\n }\n if (payload?.state === 'replaced') return { kind: 'replaced', storeName: String(payload.storeName ?? '') }\n return { kind: 'ready', view: payload as QuotePageView }\n } catch {\n return { kind: 'missing', message: 'This quote could not be loaded. Check your connection and try again.' }\n }\n }, [hostId, siteFetch])\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n link.current = {\n quoteId: params.get('q') ?? '',\n token: params.get('t') ?? '',\n sessionId: params.get('session_id') ?? '',\n }\n if (!link.current.quoteId || !link.current.token) {\n setState({ kind: 'missing', message: 'Open this page from the link you were sent with your quote.' })\n return\n }\n let live = true\n void (async () => {\n const first = await load()\n if (!live) return\n setState(first)\n const sessionId = link.current.sessionId\n if (first.kind !== 'ready' || first.view.status !== 'unpaid' || !sessionId) return\n // Back from paying: the payment may have landed before the record of it.\n const status = await siteFetch(\n `/api/commerce/checkout-status?hostId=${encodeURIComponent(hostId)}` +\n `&sessionId=${encodeURIComponent(sessionId)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .catch(() => null)\n if (!live) return\n if (status?.status === 'open') {\n setReturned('failed')\n return\n }\n if (status?.status !== 'complete') return\n setReturned('confirming')\n for (let poll = 0; poll < CONFIRM_POLLS && live; poll++) {\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS))\n if (!live) return\n const next = await load()\n if (!live) return\n if (next.kind === 'ready' && next.view.status !== 'unpaid') {\n setState(next)\n setReturned(null)\n return\n }\n }\n if (live) setReturned('unconfirmed')\n })()\n return () => {\n live = false\n }\n }, [hostId, load, siteFetch])\n\n const view = state.kind === 'ready' ? state.view : null\n\n const pay = useCallback(async () => {\n if (!view || paying) return\n setPaying(true)\n setPayError('')\n setReturned(null)\n // One key per press: a press is one attempt, and a retry after a failure is a new one.\n const attemptKey =\n globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n try {\n const response = await siteFetch('/api/commerce/quote-pay', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Idempotency-Key': attemptKey },\n body: JSON.stringify({\n hostId,\n q: link.current.quoteId,\n t: link.current.token,\n v: view.version,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // A session with a client secret is the in-page form; checked before the\n // redirect, so a form is never navigated away from.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: readStorefrontCheckoutWallets(payload.wallets),\n })\n setPaying(false)\n return\n }\n if (response.ok && payload?.url) {\n window.location.assign(String(payload.url))\n return\n }\n if (payload?.replaced) {\n setState({ kind: 'replaced', storeName: view.storeName })\n return\n }\n if (payload?.reason === 'paid' || payload?.reason === 'updated') {\n const next = await load()\n setState(next)\n }\n setPayError(String(payload?.error ?? 'Your payment could not be set up. Try again.'))\n setPaying(false)\n } catch {\n setPayError('Your payment could not be set up. Check your connection and try again.')\n setPaying(false)\n }\n }, [view, paying, siteFetch, hostId, load])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[{ p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 }, ...nodeSx]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Quote — a customer’s quote and its Pay button render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading your quote\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || 'Your quote'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Stack>\n </Box>\n )\n }\n\n if (state.kind === 'replaced') {\n const business = state.storeName || 'The business'\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n {state.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {state.storeName}\n </Typography>\n ) : null}\n <Typography variant=\"h4\" component=\"h1\">\n {'This quote was updated'}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {`${business} updated this quote and sent you a newer link. Open their most recent message to see it.`}\n </Typography>\n </Stack>\n </Box>\n )\n }\n\n const quote = state.view\n const money = (cents: number) => formatOrderMoney(cents, quote.currency)\n const unpaid = quote.status === 'unpaid'\n const addresses = [\n quote.customerName || quote.company\n ? { label: 'Prepared for', lines: [quote.customerName, quote.company].filter((line): line is string => Boolean(line)) }\n : null,\n quote.billTo ? { label: 'Bill to', lines: addressLines(quote.billTo) } : null,\n quote.shipTo ? { label: 'Ship to', lines: addressLines(quote.shipTo) } : null,\n ].filter((block): block is { label: string; lines: string[] } => Boolean(block && block.lines.length))\n const totalRows = (\n [\n ['Subtotal', money(quote.totals.itemsCents), true],\n [\n quote.discountLabel ? `Discount (${quote.discountLabel})` : 'Discount',\n `−${money(quote.totals.discountCents)}`,\n quote.totals.discountCents > 0,\n ],\n ['Shipping', money(quote.totals.shippingCents), quote.totals.shippingCents > 0],\n [quote.taxLabel, money(quote.totals.taxCents), quote.totals.taxCents > 0],\n // `Tax is added at payment`, with no figure: Stripe works it out from the address.\n [quote.taxLabel, '', quote.taxAtPayment],\n ] as Array<[string, string, boolean]>\n ).filter(([, , shown]) => shown)\n\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {quote.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {quote.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || quote.number}\n </Typography>\n <Chip\n label={quote.statusLabel}\n color={quote.status === 'paid' ? 'success' : unpaid ? 'primary' : 'default'}\n size=\"small\"\n />\n </Stack>\n {quote.dateMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Dated ${dateLabel(quote.dateMs)}`}\n </Typography>\n ) : null}\n </Stack>\n\n {addresses.length ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 2, sm: 3 }}>\n {addresses.map((block) => (\n <AddressBlock key={block.label} label={block.label} lines={block.lines} />\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {quote.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Stack spacing={0.25} sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\">\n {line.name}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.description ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {line.description}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n line.included ? `${line.quantity} included` : `${line.quantity} × ${money(line.unitAmountCents)}`,\n line.sku ? `SKU ${line.sku}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n </Stack>\n <Typography variant=\"body2\" sx={{ flexShrink: 0 }}>\n {line.included ? 'Included' : money(line.amountCents)}\n </Typography>\n </Stack>\n ))}\n <Divider />\n {totalRows.map(([label, value]) => (\n <TotalRow key={`${label}-${value}`} label={label} value={value} />\n ))}\n <TotalRow label=\"Total\" value={money(quote.totals.totalCents)} strong />\n </Stack>\n\n {quote.notes ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Notes'}\n </Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.notes}\n </Typography>\n </Stack>\n ) : null}\n {quote.terms ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Terms'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.terms}\n </Typography>\n </Stack>\n ) : null}\n\n {unpaid ? (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={2}>\n {returned === 'confirming' ? (\n <Alert severity=\"info\" icon={<CircularProgress size={20} />}>\n {'Thank you. We’re confirming your payment.'}\n </Alert>\n ) : returned === 'unconfirmed' ? (\n <Alert severity=\"info\">\n {'Your payment is still being confirmed. Your receipt will arrive by email.'}\n </Alert>\n ) : quote.approvalRequired ? (\n <Alert severity=\"info\">\n {`${quote.storeName || 'The business'} asks you to approve the proof before you pay.`}\n </Alert>\n ) : quote.payable ? (\n <>\n {returned === 'failed' ? (\n <Alert severity=\"warning\">{'Your payment did not go through. Nothing was charged.'}</Alert>\n ) : null}\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={quote.taxAtPayment ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`}\n defaultShippingAddress={stripeContact(quote.shipTo)}\n // An expired or unloadable session is replaced by a new press.\n onRestart={() => {\n setNativeCheckout(null)\n void pay()\n }}\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : (\n <Button\n variant=\"contained\"\n size=\"large\"\n onClick={() => void pay()}\n disabled={paying}\n sx={{ alignSelf: { xs: 'stretch', sm: 'flex-start' } }}\n >\n {paying\n ? 'Opening…'\n : quote.taxAtPayment\n ? `Pay ${money(quote.totals.totalCents)} plus tax`\n : `Pay ${money(quote.totals.totalCents)}`}\n </Button>\n )}\n {payError ? <Alert severity=\"error\">{payError}</Alert> : null}\n </>\n ) : (\n <Alert severity=\"info\">\n {`Contact ${quote.storeName || 'the business'} to pay this quote.`}\n </Alert>\n )}\n </Stack>\n </Paper>\n ) : (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={1.5} sx={{ alignItems: 'flex-start' }}>\n <Typography variant=\"body1\">\n {quote.status === 'paid'\n ? quote.paidAtMs\n ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.`\n : 'Paid. Thank you.'\n : `This quote is ${quote.statusLabel.toLowerCase()}.`}\n </Typography>\n {quote.receiptUrl ? (\n <Button variant=\"outlined\" href={quote.receiptUrl}>\n {'View your order'}\n </Button>\n ) : null}\n </Stack>\n </Paper>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Questions about this quote? Contact ${quote.storeName || 'the business'}.`}\n </Typography>\n </Stack>\n </Box>\n )\n})\nQuotePageBody.displayName = 'QuotePageBody'\n\nexport default QuotePageBody\n\n"],"names":["Aglyn","Alert","Box","Button","Chip","CircularProgress","Divider","Paper","Stack","Typography","forwardRef","lazy","Suspense","useCallback","useEffect","useRef","useState","formatOrderMoney","readStorefrontCheckoutWallets","StorefrontPaymentElementFallback","StorefrontPaymentElement","then","module","default","CONFIRM_POLL_MS","CONFIRM_POLLS","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","addressLines","address","cityLine","city","state","postalCode","filter","Boolean","join","name","line1","line2","country","line","stripeContact","postal_code","AddressBlock","label","lines","spacing","sx","minWidth","flex","variant","color","map","index","TotalRow","value","strong","direction","justifyContent","QuotePageBody","props","ref","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","setState","kind","paying","setPaying","payError","setPayError","nativeCheckout","setNativeCheckout","returned","setReturned","link","quoteId","token","sessionId","load","current","payload","response","encodeURIComponent","json","catch","ok","message","String","error","storeName","view","params","URLSearchParams","window","location","search","get","live","first","status","poll","Promise","resolve","setTimeout","next","pay","globalThis","attemptKey","crypto","randomUUID","now","Math","random","toString","slice","method","headers","body","JSON","stringify","q","t","v","version","clientSecret","publishableKey","wallets","url","assign","replaced","reason","p","border","borderColor","borderRadius","py","textAlign","size","aria-label","component","severity","business","quote","money","cents","currency","unpaid","addresses","customerName","company","billTo","shipTo","block","length","totalRows","totals","itemsCents","discountLabel","discountCents","shippingCents","taxLabel","taxCents","taxAtPayment","shown","alignItems","flexWrap","rowGap","number","statusLabel","dateMs","xs","sm","variantLabel","description","whiteSpace","included","quantity","unitAmountCents","sku","flexShrink","amountCents","totalCents","notes","terms","icon","approvalRequired","payable","fallback","payLabel","defaultShippingAddress","onRestart","onCancel","onClick","disabled","alignSelf","paidAtMs","toLowerCase","receiptUrl","href","displayName"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,SAAS,oBAAmB;AACnC,OAAOC,YAAY,uBAAsB;AACzC,OAAOC,UAAU,qBAAoB;AACrC,OAAOC,sBAAsB,iCAAgC;AAC7D,OAAOC,aAAa,wBAAuB;AAC3C,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,WAAW,sBAAqB;AACvC,OAAOC,gBAAgB,2BAA0B;AAEjD,SAASC,UAAU,EAAEC,IAAI,EAAEC,QAAQ,EAAEC,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAC5F,SACEC,gBAAgB,EAChBC,6BAA6B,QAIxB,oBAAU;AAEjB,SAASC,gCAAgC,QAAQ,2CAAuC;AAExF,mFAAmF,GACnF,MAAMC,yCAA2BT,KAAK,IACpC,MAAM,CAAC,mCAAgCU,IAAI,CAAC,CAACC,SAAY,CAAA;YACvDC,SAASD,OAAOF,wBAAwB;QAC1C,CAAA;AASF,0FAA0F,GAC1F,MAAMI,kBAAkB;AACxB,MAAMC,gBAAgB;AAEtB,SAASC,UAAUC,IAAmB;IACpC,IAAI,CAACA,MAAM,OAAO;IAClB,OAAO,IAAIC,KAAKD,MAAME,kBAAkB,CAACC,WAAW;QAAEC,OAAO;QAASC,KAAK;QAAWC,MAAM;IAAU;AACxG;AAEA,SAASC,aAAaC,OAAyB;IAC7C,MAAMC,WAAW;QAACD,QAAQE,IAAI;QAAE;YAACF,QAAQG,KAAK;YAAEH,QAAQI,UAAU;SAAC,CAACC,MAAM,CAACC,SAASC,IAAI,CAAC;KAAK,CAC3FF,MAAM,CAACC,SACPC,IAAI,CAAC;IACR,OAAO;QAACP,QAAQQ,IAAI;QAAER,QAAQS,KAAK;QAAET,QAAQU,KAAK;QAAET;QAAUD,QAAQW,OAAO;KAAC,CAACN,MAAM,CACnF,CAACO,OAAyBN,QAAQM;AAEtC;AAEA,SAASC,cAAcb,OAAgC;IACrD,IAAI,EAACA,2BAAAA,QAASW,OAAO,GAAE,OAAOhB;IAC9B,OAAO;QACLa,MAAMR,QAAQQ,IAAI;QAClBR,SAAS;YACPW,SAASX,QAAQW,OAAO;YACxBF,OAAOT,QAAQS,KAAK;YACpBC,OAAOV,QAAQU,KAAK;YACpBR,MAAMF,QAAQE,IAAI;YAClBC,OAAOH,QAAQG,KAAK;YACpBW,aAAad,QAAQI,UAAU;QACjC;IACF;AACF;AAEA,SAASW,aAAa,EAAEC,KAAK,EAAEC,KAAK,EAAsC;IACxE,qBACE,MAAC5C;QAAM6C,SAAS;QAAMC,IAAI;YAAEC,UAAU;YAAGC,MAAM;QAAE;;0BAC/C,KAAC/C;gBAAWgD,SAAQ;gBAAWC,OAAM;0BAClCP;;YAEFC,MAAMO,GAAG,CAAC,CAACZ,MAAMa,sBAChB,KAACnD;oBAAuBgD,SAAQ;8BAC7BV;mBADca;;;AAMzB;AAEA,SAASC,SAAS,EAAEV,KAAK,EAAEW,KAAK,EAAEC,MAAM,EAAsD;IAC5F,qBACE,MAACvD;QAAMwD,WAAU;QAAMX,SAAS;QAAGC,IAAI;YAAEW,gBAAgB;QAAgB;;0BACvE,KAACxD;gBAAWgD,SAASM,SAAS,cAAc;gBAASL,OAAOK,SAAS,iBAAiB;0BACnFZ;;0BAEH,KAAC1C;gBAAWgD,SAASM,SAAS,cAAc;gBAASL,OAAOK,SAAS,iBAAiB;0BACnFD;;;;AAIT;AAEA;;;;;;;;;;;;;CAaC,GACD,MAAMI,8BAAgBxD,WAA2C,CAACyD,OAAOC;IACvE,MAAM,EAAEC,OAAO,EAAW,GAAGF,OAATG,wCAASH;;;IAC7B,MAAMI,SAASC,MAAMC,OAAO,CAACN,KAAK,CAAC,KAAK,IAAIA,KAAK,CAAC,KAAK,GAAG;QAACA,KAAK,CAAC,KAAK;KAAC;IACvE,MAAM,EAAEO,MAAM,EAAE,GAAG1E,MAAM2E,OAAO;IAChC,MAAMC,YAAY5E,MAAM6E,YAAY;IACpC,MAAM,CAACvC,OAAOwC,SAAS,GAAG9D,SAAoB;QAAE+D,MAAM;IAAU;IAChE,MAAM,CAACC,QAAQC,UAAU,GAAGjE,SAAS;IACrC,MAAM,CAACkE,UAAUC,YAAY,GAAGnE,SAAS;IACzC,MAAM,CAACoE,gBAAgBC,kBAAkB,GAAGrE,SAIlC;IACV,oFAAoF,GACpF,MAAM,CAACsE,UAAUC,YAAY,GAAGvE,SAAyD;IACzF,MAAMwE,OAAOzE,OAAO;QAAE0E,SAAS;QAAIC,OAAO;QAAIC,WAAW;IAAG;IAE5D,MAAMC,OAAO/E,YAAY;QACvB,MAAM,EAAE4E,OAAO,EAAEC,KAAK,EAAE,GAAGF,KAAKK,OAAO;QACvC,IAAI;gBAS8EC;YARhF,MAAMC,WAAW,MAAMnB,UACrB,CAAC,gCAAgC,EAAEoB,mBAAmBtB,iBAAAA,SAAU,KAAK,GACnE,CAAC,GAAG,EAAEsB,mBAAmBP,SAAS,GAAG,EAAEO,mBAAmBN,QAAQ;YAEtE,MAAMI,UAAU,MAAMC,SAASE,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACpD,IAAI,CAACH,SAASI,EAAE,EAAE;;gBAChB,OAAO;oBAAEpB,MAAM;oBAAWqB,SAASC,eAAOP,2BAAAA,QAASQ,KAAK,mBAAI;gBAAiC;YAC/F;YACA,IAAIR,CAAAA,2BAAAA,QAASxD,KAAK,MAAK,YAAY,OAAO;gBAAEyC,MAAM;gBAAYwB,WAAWF,QAAOP,qBAAAA,QAAQS,SAAS,YAAjBT,qBAAqB;YAAI;YACzG,OAAO;gBAAEf,MAAM;gBAASyB,MAAMV;YAAyB;QACzD,EAAE,eAAM;YACN,OAAO;gBAAEf,MAAM;gBAAWqB,SAAS;YAAuE;QAC5G;IACF,GAAG;QAAC1B;QAAQE;KAAU;IAEtB9D,UAAU;YAIG2F,aACFA,cACIA;QALb,IAAI,CAAC/B,QAAQ;QACb,MAAM+B,SAAS,IAAIC,gBAAgBC,OAAOC,QAAQ,CAACC,MAAM;QACzDrB,KAAKK,OAAO,GAAG;YACbJ,OAAO,GAAEgB,cAAAA,OAAOK,GAAG,CAAC,gBAAXL,cAAmB;YAC5Bf,KAAK,GAAEe,eAAAA,OAAOK,GAAG,CAAC,gBAAXL,eAAmB;YAC1Bd,SAAS,GAAEc,eAAAA,OAAOK,GAAG,CAAC,yBAAXL,eAA4B;QACzC;QACA,IAAI,CAACjB,KAAKK,OAAO,CAACJ,OAAO,IAAI,CAACD,KAAKK,OAAO,CAACH,KAAK,EAAE;YAChDZ,SAAS;gBAAEC,MAAM;gBAAWqB,SAAS;YAA8D;YACnG;QACF;QACA,IAAIW,OAAO;QACX,KAAK,AAAC,CAAA;YACJ,MAAMC,QAAQ,MAAMpB;YACpB,IAAI,CAACmB,MAAM;YACXjC,SAASkC;YACT,MAAMrB,YAAYH,KAAKK,OAAO,CAACF,SAAS;YACxC,IAAIqB,MAAMjC,IAAI,KAAK,WAAWiC,MAAMR,IAAI,CAACS,MAAM,KAAK,YAAY,CAACtB,WAAW;YAC5E,yEAAyE;YACzE,MAAMsB,SAAS,MAAMrC,UACnB,CAAC,qCAAqC,EAAEoB,mBAAmBtB,SAAS,GAClE,CAAC,WAAW,EAAEsB,mBAAmBL,YAAY,EAE9CtE,IAAI,CAAC,CAAC0E,WAAcA,SAASI,EAAE,GAAGJ,SAASE,IAAI,KAAK,MACpDC,KAAK,CAAC,IAAM;YACf,IAAI,CAACa,MAAM;YACX,IAAIE,CAAAA,0BAAAA,OAAQA,MAAM,MAAK,QAAQ;gBAC7B1B,YAAY;gBACZ;YACF;YACA,IAAI0B,CAAAA,0BAAAA,OAAQA,MAAM,MAAK,YAAY;YACnC1B,YAAY;YACZ,IAAK,IAAI2B,OAAO,GAAGA,OAAOzF,iBAAiBsF,MAAMG,OAAQ;gBACvD,MAAM,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAAS5F;gBACnD,IAAI,CAACuF,MAAM;gBACX,MAAMO,OAAO,MAAM1B;gBACnB,IAAI,CAACmB,MAAM;gBACX,IAAIO,KAAKvC,IAAI,KAAK,WAAWuC,KAAKd,IAAI,CAACS,MAAM,KAAK,UAAU;oBAC1DnC,SAASwC;oBACT/B,YAAY;oBACZ;gBACF;YACF;YACA,IAAIwB,MAAMxB,YAAY;QACxB,CAAA;QACA,OAAO;YACLwB,OAAO;QACT;IACF,GAAG;QAACrC;QAAQkB;QAAMhB;KAAU;IAE5B,MAAM4B,OAAOlE,MAAMyC,IAAI,KAAK,UAAUzC,MAAMkE,IAAI,GAAG;IAEnD,MAAMe,MAAM1G,YAAY;;YAOpB2G,+BAAAA;QANF,IAAI,CAAChB,QAAQxB,QAAQ;QACrBC,UAAU;QACVE,YAAY;QACZI,YAAY;QACZ,uFAAuF;QACvF,MAAMkC,sBACJD,qBAAAA,WAAWE,MAAM,sBAAjBF,gCAAAA,mBAAmBG,UAAU,qBAA7BH,mCAAAA,sCAAqC,GAAG5F,KAAKgG,GAAG,GAAG,CAAC,EAAEC,KAAKC,MAAM,GAAGC,QAAQ,CAAC,IAAIC,KAAK,CAAC,IAAI;QAC7F,IAAI;;YACF,MAAMjC,WAAW,MAAMnB,UAAU,2BAA2B;gBAC1DqD,QAAQ;gBACRC,SAAS;oBAAE,gBAAgB;oBAAoB,mBAAmBT;gBAAW;gBAC7EU,MAAMC,KAAKC,SAAS,CAAC;oBACnB3D;oBACA4D,GAAG9C,KAAKK,OAAO,CAACJ,OAAO;oBACvB8C,GAAG/C,KAAKK,OAAO,CAACH,KAAK;oBACrB8C,GAAGhC,KAAKiC,OAAO;gBACjB;YACF;YACA,MAAM3C,UAAU,MAAMC,SAASE,IAAI,GAAGC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;YACpD,yEAAyE;YACzE,oDAAoD;YACpD,IAAIH,SAASI,EAAE,KAAIL,2BAAAA,QAAS4C,YAAY,MAAI5C,2BAAAA,QAAS6C,cAAc,GAAE;gBACnEtD,kBAAkB;oBAChBqD,cAAcrC,OAAOP,QAAQ4C,YAAY;oBACzCC,gBAAgBtC,OAAOP,QAAQ6C,cAAc;oBAC7CC,SAAS1H,8BAA8B4E,QAAQ8C,OAAO;gBACxD;gBACA3D,UAAU;gBACV;YACF;YACA,IAAIc,SAASI,EAAE,KAAIL,2BAAAA,QAAS+C,GAAG,GAAE;gBAC/BlC,OAAOC,QAAQ,CAACkC,MAAM,CAACzC,OAAOP,QAAQ+C,GAAG;gBACzC;YACF;YACA,IAAI/C,2BAAAA,QAASiD,QAAQ,EAAE;gBACrBjE,SAAS;oBAAEC,MAAM;oBAAYwB,WAAWC,KAAKD,SAAS;gBAAC;gBACvD;YACF;YACA,IAAIT,CAAAA,2BAAAA,QAASkD,MAAM,MAAK,UAAUlD,CAAAA,2BAAAA,QAASkD,MAAM,MAAK,WAAW;gBAC/D,MAAM1B,OAAO,MAAM1B;gBACnBd,SAASwC;YACX;YACAnC,YAAYkB,gBAAOP,2BAAAA,QAASQ,KAAK,oBAAI;YACrCrB,UAAU;QACZ,EAAE,eAAM;YACNE,YAAY;YACZF,UAAU;QACZ;IACF,GAAG;QAACuB;QAAMxB;QAAQJ;QAAWF;QAAQkB;KAAK;IAE1C,IAAI,CAAClB,QAAQ;QACX,qBACE,KAACxE;YACCkE,KAAKA;WACDE;YACJhB,IAAI;gBAAC;oBAAE2F,GAAG;oBAAGC,QAAQ;oBAAcC,aAAa;oBAAWC,cAAc;gBAAE;mBAAM7E;aAAO;sBAExF,cAAA,KAAC9D;gBAAWgD,SAAQ;gBAAQC,OAAM;0BAC/B;;;IAIT;IAEA,IAAIpB,MAAMyC,IAAI,KAAK,WAAW;QAC5B,qBACE,KAAC7E;YAAIkE,KAAKA;WAASE;YAAMhB,IAAI;gBAAC;oBAAE+F,IAAI;oBAAGC,WAAW;gBAAS;mBAAM/E;aAAO;sBACtE,cAAA,KAAClE;gBAAiBkJ,MAAM;gBAAIC,cAAW;;;IAG7C;IAEA,IAAIlH,MAAMyC,IAAI,KAAK,WAAW;QAC5B,qBACE,KAAC7E;YAAIkE,KAAKA;WAASE;YAAMhB,IAAIiB;sBAC3B,cAAA,MAAC/D;gBAAM6C,SAAS;;kCACd,KAAC5C;wBAAWgD,SAAQ;wBAAKgG,WAAU;kCAChCpF,WAAW;;kCAEd,KAACpE;wBAAMyJ,UAAS;kCAAQpH,MAAM8D,OAAO;;;;;IAI7C;IAEA,IAAI9D,MAAMyC,IAAI,KAAK,YAAY;QAC7B,MAAM4E,WAAWrH,MAAMiE,SAAS,IAAI;QACpC,qBACE,KAACrG;YAAIkE,KAAKA;WAASE;YAAMhB,IAAIiB;sBAC3B,cAAA,MAAC/D;gBAAM6C,SAAS;;oBACbf,MAAMiE,SAAS,iBACd,KAAC9F;wBAAWgD,SAAQ;wBAAWC,OAAM;kCAClCpB,MAAMiE,SAAS;yBAEhB;kCACJ,KAAC9F;wBAAWgD,SAAQ;wBAAKgG,WAAU;kCAChC;;kCAEH,KAAChJ;wBAAWgD,SAAQ;wBAAQC,OAAM;kCAC/B,GAAGiG,SAAS,wFAAwF,CAAC;;;;;IAKhH;IAEA,MAAMC,QAAQtH,MAAMkE,IAAI;IACxB,MAAMqD,QAAQ,CAACC,QAAkB7I,iBAAiB6I,OAAOF,MAAMG,QAAQ;IACvE,MAAMC,SAASJ,MAAM3C,MAAM,KAAK;IAChC,MAAMgD,YAAY;QAChBL,MAAMM,YAAY,IAAIN,MAAMO,OAAO,GAC/B;YAAEhH,OAAO;YAAgBC,OAAO;gBAACwG,MAAMM,YAAY;gBAAEN,MAAMO,OAAO;aAAC,CAAC3H,MAAM,CAAC,CAACO,OAAyBN,QAAQM;QAAO,IACpH;QACJ6G,MAAMQ,MAAM,GAAG;YAAEjH,OAAO;YAAWC,OAAOlB,aAAa0H,MAAMQ,MAAM;QAAE,IAAI;QACzER,MAAMS,MAAM,GAAG;YAAElH,OAAO;YAAWC,OAAOlB,aAAa0H,MAAMS,MAAM;QAAE,IAAI;KAC1E,CAAC7H,MAAM,CAAC,CAAC8H,QAAuD7H,QAAQ6H,SAASA,MAAMlH,KAAK,CAACmH,MAAM;IACpG,MAAMC,YAAY,AAChB;QACE;YAAC;YAAYX,MAAMD,MAAMa,MAAM,CAACC,UAAU;YAAG;SAAK;QAClD;YACEd,MAAMe,aAAa,GAAG,CAAC,UAAU,EAAEf,MAAMe,aAAa,CAAC,CAAC,CAAC,GAAG;YAC5D,CAAC,CAAC,EAAEd,MAAMD,MAAMa,MAAM,CAACG,aAAa,GAAG;YACvChB,MAAMa,MAAM,CAACG,aAAa,GAAG;SAC9B;QACD;YAAC;YAAYf,MAAMD,MAAMa,MAAM,CAACI,aAAa;YAAGjB,MAAMa,MAAM,CAACI,aAAa,GAAG;SAAE;QAC/E;YAACjB,MAAMkB,QAAQ;YAAEjB,MAAMD,MAAMa,MAAM,CAACM,QAAQ;YAAGnB,MAAMa,MAAM,CAACM,QAAQ,GAAG;SAAE;QACzE,mFAAmF;QACnF;YAACnB,MAAMkB,QAAQ;YAAE;YAAIlB,MAAMoB,YAAY;SAAC;KACzC,CACDxI,MAAM,CAAC,CAAC,KAAKyI,MAAM,GAAKA;IAE1B,qBACE,KAAC/K;QAAIkE,KAAKA;OAASE;QAAMhB,IAAIiB;kBAC3B,cAAA,MAAC/D;YAAM6C,SAAS;;8BACd,MAAC7C;oBAAM6C,SAAS;;wBACbuG,MAAMrD,SAAS,iBACd,KAAC9F;4BAAWgD,SAAQ;4BAAWC,OAAM;sCAClCkG,MAAMrD,SAAS;6BAEhB;sCACJ,MAAC/F;4BAAMwD,WAAU;4BAAMX,SAAS;4BAAKC,IAAI;gCAAE4H,YAAY;gCAAUC,UAAU;gCAAQC,QAAQ;4BAAE;;8CAC3F,KAAC3K;oCAAWgD,SAAQ;oCAAKgG,WAAU;8CAChCpF,WAAWuF,MAAMyB,MAAM;;8CAE1B,KAACjL;oCACC+C,OAAOyG,MAAM0B,WAAW;oCACxB5H,OAAOkG,MAAM3C,MAAM,KAAK,SAAS,YAAY+C,SAAS,YAAY;oCAClET,MAAK;;;;wBAGRK,MAAM2B,MAAM,iBACX,KAAC9K;4BAAWgD,SAAQ;4BAAQC,OAAM;sCAC/B,CAAC,MAAM,EAAEhC,UAAUkI,MAAM2B,MAAM,GAAG;6BAEnC;;;gBAGLtB,UAAUM,MAAM,iBACf,KAAC/J;oBAAMwD,WAAW;wBAAEwH,IAAI;wBAAUC,IAAI;oBAAM;oBAAGpI,SAAS;wBAAEmI,IAAI;wBAAGC,IAAI;oBAAE;8BACpExB,UAAUtG,GAAG,CAAC,CAAC2G,sBACd,KAACpH;4BAA+BC,OAAOmH,MAAMnH,KAAK;4BAAEC,OAAOkH,MAAMlH,KAAK;2BAAnDkH,MAAMnH,KAAK;qBAGhC;8BAEJ,MAAC3C;oBAAM6C,SAAS;;sCACd,KAAC5C;4BAAWgD,SAAQ;4BAAKgG,WAAU;sCAChC;;wBAEFG,MAAMxG,KAAK,CAACO,GAAG,CAAC,CAACZ,MAAMa,sBACtB,MAACpD;gCAAkBwD,WAAU;gCAAMX,SAAS;gCAAGC,IAAI;oCAAEW,gBAAgB;gCAAgB;;kDACnF,MAACzD;wCAAM6C,SAAS;wCAAMC,IAAI;4CAAEC,UAAU;wCAAE;;0DACtC,MAAC9C;gDAAWgD,SAAQ;;oDACjBV,KAAKJ,IAAI;oDACTI,KAAK2I,YAAY,GAAG,CAAC,EAAE,EAAE3I,KAAK2I,YAAY,CAAC,CAAC,CAAC,GAAG;;;4CAElD3I,KAAK4I,WAAW,iBACf,KAAClL;gDAAWgD,SAAQ;gDAAQC,OAAM;gDAAiBJ,IAAI;oDAAEsI,YAAY;gDAAW;0DAC7E7I,KAAK4I,WAAW;iDAEjB;0DACJ,KAAClL;gDAAWgD,SAAQ;gDAAUC,OAAM;0DACjC;oDACCX,KAAK8I,QAAQ,GAAG,GAAG9I,KAAK+I,QAAQ,CAAC,SAAS,CAAC,GAAG,GAAG/I,KAAK+I,QAAQ,CAAC,GAAG,EAAEjC,MAAM9G,KAAKgJ,eAAe,GAAG;oDACjGhJ,KAAKiJ,GAAG,GAAG,CAAC,IAAI,EAAEjJ,KAAKiJ,GAAG,EAAE,GAAG;iDAChC,CACExJ,MAAM,CAACC,SACPC,IAAI,CAAC;;;;kDAGZ,KAACjC;wCAAWgD,SAAQ;wCAAQH,IAAI;4CAAE2I,YAAY;wCAAE;kDAC7ClJ,KAAK8I,QAAQ,GAAG,aAAahC,MAAM9G,KAAKmJ,WAAW;;;+BArB5CtI;sCAyBd,KAACtD;wBACAkK,UAAU7G,GAAG,CAAC,CAAC,CAACR,OAAOW,MAAM,iBAC5B,KAACD;gCAAmCV,OAAOA;gCAAOW,OAAOA;+BAA1C,GAAGX,MAAM,CAAC,EAAEW,OAAO;sCAEpC,KAACD;4BAASV,OAAM;4BAAQW,OAAO+F,MAAMD,MAAMa,MAAM,CAAC0B,UAAU;4BAAGpI,MAAM;;;;gBAGtE6F,MAAMwC,KAAK,iBACV,MAAC5L;oBAAM6C,SAAS;;sCACd,KAAC5C;4BAAWgD,SAAQ;4BAAKgG,WAAU;sCAChC;;sCAEH,KAAChJ;4BAAWgD,SAAQ;4BAAQH,IAAI;gCAAEsI,YAAY;4BAAW;sCACtDhC,MAAMwC,KAAK;;;qBAGd;gBACHxC,MAAMyC,KAAK,iBACV,MAAC7L;oBAAM6C,SAAS;;sCACd,KAAC5C;4BAAWgD,SAAQ;4BAAKgG,WAAU;sCAChC;;sCAEH,KAAChJ;4BAAWgD,SAAQ;4BAAQC,OAAM;4BAAiBJ,IAAI;gCAAEsI,YAAY;4BAAW;sCAC7EhC,MAAMyC,KAAK;;;qBAGd;gBAEHrC,uBACC,KAACzJ;oBAAMkD,SAAQ;oBAAWH,IAAI;wBAAE2F,GAAG;4BAAEuC,IAAI;4BAAGC,IAAI;wBAAE;oBAAE;8BAClD,cAAA,KAACjL;wBAAM6C,SAAS;kCACbiC,aAAa,6BACZ,KAACrF;4BAAMyJ,UAAS;4BAAO4C,oBAAM,KAACjM;gCAAiBkJ,MAAM;;sCAClD;6BAEDjE,aAAa,8BACf,KAACrF;4BAAMyJ,UAAS;sCACb;6BAEDE,MAAM2C,gBAAgB,iBACxB,KAACtM;4BAAMyJ,UAAS;sCACb,GAAGE,MAAMrD,SAAS,IAAI,eAAe,8CAA8C,CAAC;6BAErFqD,MAAM4C,OAAO,iBACf;;gCACGlH,aAAa,yBACZ,KAACrF;oCAAMyJ,UAAS;8CAAW;qCACzB;gCACHtE,+BACC,KAACxE;oCAAS6L,wBAAU,KAACtL;8CACnB,cAAA,KAACC;wCACCsH,cAActD,eAAesD,YAAY;wCACzCC,gBAAgBvD,eAAeuD,cAAc;wCAC7CC,SAASxD,eAAewD,OAAO;wCAC/B8D,UAAU9C,MAAMoB,YAAY,GAAG,YAAY,CAAC,IAAI,EAAEnB,MAAMD,MAAMa,MAAM,CAAC0B,UAAU,GAAG;wCAClFQ,wBAAwB3J,cAAc4G,MAAMS,MAAM;wCAClD,+DAA+D;wCAC/DuC,WAAW;4CACTvH,kBAAkB;4CAClB,KAAKkC;wCACP;wCACAsF,UAAU,IAAMxH,kBAAkB;;mDAItC,KAAClF;oCACCsD,SAAQ;oCACR8F,MAAK;oCACLuD,SAAS,IAAM,KAAKvF;oCACpBwF,UAAU/H;oCACV1B,IAAI;wCAAE0J,WAAW;4CAAExB,IAAI;4CAAWC,IAAI;wCAAa;oCAAE;8CAEpDzG,SACG,aACA4E,MAAMoB,YAAY,GAChB,CAAC,IAAI,EAAEnB,MAAMD,MAAMa,MAAM,CAAC0B,UAAU,EAAE,SAAS,CAAC,GAChD,CAAC,IAAI,EAAEtC,MAAMD,MAAMa,MAAM,CAAC0B,UAAU,GAAG;;gCAGhDjH,yBAAW,KAACjF;oCAAMyJ,UAAS;8CAASxE;qCAAoB;;2CAG3D,KAACjF;4BAAMyJ,UAAS;sCACb,CAAC,QAAQ,EAAEE,MAAMrD,SAAS,IAAI,eAAe,mBAAmB,CAAC;;;mCAM1E,KAAChG;oBAAMkD,SAAQ;oBAAWH,IAAI;wBAAE2F,GAAG;4BAAEuC,IAAI;4BAAGC,IAAI;wBAAE;oBAAE;8BAClD,cAAA,MAACjL;wBAAM6C,SAAS;wBAAKC,IAAI;4BAAE4H,YAAY;wBAAa;;0CAClD,KAACzK;gCAAWgD,SAAQ;0CACjBmG,MAAM3C,MAAM,KAAK,SACd2C,MAAMqD,QAAQ,GACZ,CAAC,KAAK,EAAEvL,UAAUkI,MAAMqD,QAAQ,EAAE,YAAY,CAAC,GAC/C,qBACF,CAAC,cAAc,EAAErD,MAAM0B,WAAW,CAAC4B,WAAW,GAAG,CAAC,CAAC;;4BAExDtD,MAAMuD,UAAU,iBACf,KAAChN;gCAAOsD,SAAQ;gCAAW2J,MAAMxD,MAAMuD,UAAU;0CAC9C;iCAED;;;;8BAKV,KAAC1M;oBAAWgD,SAAQ;oBAAQC,OAAM;8BAC/B,CAAC,oCAAoC,EAAEkG,MAAMrD,SAAS,IAAI,eAAe,CAAC,CAAC;;;;;AAKtF;AACArC,cAAcmJ,WAAW,GAAG;AAE5B,eAAenJ,cAAa"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/quote-page-body.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 * as Aglyn from '@aglyn/aglyn'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport Divider from '@mui/material/Divider'\nimport Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport type { StripeCheckoutContact } from '@stripe/stripe-js'\nimport { forwardRef, lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react'\nimport {\n formatOrderMoney,\n readStorefrontCheckoutWallets,\n type QuotePageAddress,\n type QuotePageView,\n type StorefrontCheckoutWallets,\n} from '../model'\nimport type { QuotePageProps } from './quote-page'\nimport { QuoteProofPanel } from './quote-proof-panel'\nimport { StorefrontPaymentElementFallback } from './storefront-payment-element-fallback'\n\n/** The Payment Element, lazily: Stripe.js loads only when a customer presses Pay. */\nconst StorefrontPaymentElement = lazy(() =>\n import('./storefront-payment-element').then((module) => ({\n default: module.StorefrontPaymentElement,\n })),\n)\n\ntype LoadState =\n | { kind: 'loading' }\n | { kind: 'missing'; message: string }\n | { kind: 'replaced'; storeName: string }\n | { kind: 'ready'; view: QuotePageView }\n\n/** After a payment returns here, how often and how long the page asks whether it landed. */\nconst CONFIRM_POLL_MS = 2_000\nconst CONFIRM_POLLS = 15\n\nfunction dateLabel(atMs: number | null): string {\n if (!atMs) return ''\n return new Date(atMs).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nfunction addressLines(address: QuotePageAddress): string[] {\n const cityLine = [address.city, [address.state, address.postalCode].filter(Boolean).join(' ')]\n .filter(Boolean)\n .join(', ')\n return [address.name, address.line1, address.line2, cityLine, address.country].filter(\n (line): line is string => Boolean(line),\n )\n}\n\nfunction stripeContact(address: QuotePageAddress | null): StripeCheckoutContact | undefined {\n if (!address?.country) return undefined\n return {\n name: address.name,\n address: {\n country: address.country,\n line1: address.line1,\n line2: address.line2,\n city: address.city,\n state: address.state,\n postal_code: address.postalCode,\n },\n }\n}\n\nfunction AddressBlock({ label, lines }: { label: string; lines: string[] }) {\n return (\n <Stack spacing={0.25} sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n {lines.map((line, index) => (\n <Typography key={index} variant=\"body2\">\n {line}\n </Typography>\n ))}\n </Stack>\n )\n}\n\nfunction TotalRow({ label, value, strong }: { label: string; value: string; strong?: boolean }) {\n return (\n <Stack direction=\"row\" spacing={2} 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'} color={strong ? 'text.primary' : 'text.secondary'}>\n {value}\n </Typography>\n </Stack>\n )\n}\n\n/**\n * The customer's quote page (AGL-4094), loaded when the page draws it (see\n * `quote-page.tsx`): what a customer sees when they open\n * the pay link a business sent them. The commerce page resolver serves it at\n * `/pay-quote` inside the site's own header and footer; a business can also\n * place it on a page of their own design at that address.\n *\n * The quote is read AFTER hydration from `?q=&t=`, so the page itself is the\n * same for every customer and may be cached, and the quote never is. Pay asks\n * the server for a fresh payment for the quote as the page shows it: Stripe's\n * own page, or the payment form here when in-page payments are on. Nothing\n * here decides a quote is paid; after paying, the page reads that from the\n * server like any other visit.\n */\nconst QuotePageBody = forwardRef<HTMLDivElement, QuotePageProps>((props, ref) => {\n const { heading, ...rest } = props\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [state, setState] = useState<LoadState>({ kind: 'loading' })\n const [paying, setPaying] = useState(false)\n const [payError, setPayError] = useState('')\n const [nativeCheckout, setNativeCheckout] = useState<{\n clientSecret: string\n publishableKey: string\n wallets?: StorefrontCheckoutWallets\n } | null>(null)\n /** What a return from paying turned out to be: still being confirmed, or not paid. */\n const [returned, setReturned] = useState<'confirming' | 'unconfirmed' | 'failed' | null>(null)\n const link = useRef({ quoteId: '', token: '', sessionId: '' })\n\n const load = useCallback(async (): Promise<LoadState> => {\n const { quoteId, token } = link.current\n try {\n const response = await siteFetch(\n `/api/commerce/quote-view?hostId=${encodeURIComponent(hostId ?? '')}` +\n `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`,\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return { kind: 'missing', message: String(payload?.error ?? 'We could not find that quote.') }\n }\n if (payload?.state === 'replaced') return { kind: 'replaced', storeName: String(payload.storeName ?? '') }\n return { kind: 'ready', view: payload as QuotePageView }\n } catch {\n return { kind: 'missing', message: 'This quote could not be loaded. Check your connection and try again.' }\n }\n }, [hostId, siteFetch])\n\n useEffect(() => {\n if (!hostId) return\n const params = new URLSearchParams(window.location.search)\n link.current = {\n quoteId: params.get('q') ?? '',\n token: params.get('t') ?? '',\n sessionId: params.get('session_id') ?? '',\n }\n if (!link.current.quoteId || !link.current.token) {\n setState({ kind: 'missing', message: 'Open this page from the link you were sent with your quote.' })\n return\n }\n let live = true\n void (async () => {\n const first = await load()\n if (!live) return\n setState(first)\n const sessionId = link.current.sessionId\n if (first.kind !== 'ready' || first.view.status !== 'unpaid' || !sessionId) return\n // Back from paying: the payment may have landed before the record of it.\n const status = await siteFetch(\n `/api/commerce/checkout-status?hostId=${encodeURIComponent(hostId)}` +\n `&sessionId=${encodeURIComponent(sessionId)}`,\n )\n .then((response) => (response.ok ? response.json() : null))\n .catch(() => null)\n if (!live) return\n if (status?.status === 'open') {\n setReturned('failed')\n return\n }\n if (status?.status !== 'complete') return\n setReturned('confirming')\n for (let poll = 0; poll < CONFIRM_POLLS && live; poll++) {\n await new Promise((resolve) => setTimeout(resolve, CONFIRM_POLL_MS))\n if (!live) return\n const next = await load()\n if (!live) return\n if (next.kind === 'ready' && next.view.status !== 'unpaid') {\n setState(next)\n setReturned(null)\n return\n }\n }\n if (live) setReturned('unconfirmed')\n })()\n return () => {\n live = false\n }\n }, [hostId, load, siteFetch])\n\n const view = state.kind === 'ready' ? state.view : null\n\n const pay = useCallback(async () => {\n if (!view || paying) return\n setPaying(true)\n setPayError('')\n setReturned(null)\n // One key per press: a press is one attempt, and a retry after a failure is a new one.\n const attemptKey =\n globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n try {\n const response = await siteFetch('/api/commerce/quote-pay', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Idempotency-Key': attemptKey },\n body: JSON.stringify({\n hostId,\n q: link.current.quoteId,\n t: link.current.token,\n v: view.version,\n }),\n })\n const payload = await response.json().catch(() => ({}))\n // A session with a client secret is the in-page form; checked before the\n // redirect, so a form is never navigated away from.\n if (response.ok && payload?.clientSecret && payload?.publishableKey) {\n setNativeCheckout({\n clientSecret: String(payload.clientSecret),\n publishableKey: String(payload.publishableKey),\n wallets: readStorefrontCheckoutWallets(payload.wallets),\n })\n setPaying(false)\n return\n }\n if (response.ok && payload?.url) {\n window.location.assign(String(payload.url))\n return\n }\n if (payload?.replaced) {\n setState({ kind: 'replaced', storeName: view.storeName })\n return\n }\n if (payload?.reason === 'paid' || payload?.reason === 'updated') {\n const next = await load()\n setState(next)\n }\n setPayError(String(payload?.error ?? 'Your payment could not be set up. Try again.'))\n setPaying(false)\n } catch {\n setPayError('Your payment could not be set up. Check your connection and try again.')\n setPaying(false)\n }\n }, [view, paying, siteFetch, hostId, load])\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[{ p: 3, border: '1px dashed', borderColor: 'divider', borderRadius: 1 }, ...nodeSx]}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Quote — a customer’s quote and its Pay button render here'}\n </Typography>\n </Box>\n )\n }\n\n if (state.kind === 'loading') {\n return (\n <Box ref={ref} {...rest} sx={[{ py: 6, textAlign: 'center' }, ...nodeSx]}>\n <CircularProgress size={28} aria-label=\"Loading your quote\" />\n </Box>\n )\n }\n\n if (state.kind === 'missing') {\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || 'Your quote'}\n </Typography>\n <Alert severity=\"info\">{state.message}</Alert>\n </Stack>\n </Box>\n )\n }\n\n if (state.kind === 'replaced') {\n const business = state.storeName || 'The business'\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={2}>\n {state.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {state.storeName}\n </Typography>\n ) : null}\n <Typography variant=\"h4\" component=\"h1\">\n {'This quote was updated'}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {`${business} updated this quote and sent you a newer link. Open their most recent message to see it.`}\n </Typography>\n </Stack>\n </Box>\n )\n }\n\n const quote = state.view\n const money = (cents: number) => formatOrderMoney(cents, quote.currency)\n // The same signed link as the page's data; the server makes the PDF from the same view.\n const pdfHref =\n `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` +\n `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`\n const unpaid = quote.status === 'unpaid'\n const addresses = [\n quote.customerName || quote.company\n ? { label: 'Prepared for', lines: [quote.customerName, quote.company].filter((line): line is string => Boolean(line)) }\n : null,\n quote.billTo ? { label: 'Bill to', lines: addressLines(quote.billTo) } : null,\n quote.shipTo ? { label: 'Ship to', lines: addressLines(quote.shipTo) } : null,\n ].filter((block): block is { label: string; lines: string[] } => Boolean(block && block.lines.length))\n const totalRows = (\n [\n ['Subtotal', money(quote.totals.itemsCents), true],\n [\n quote.discountLabel ? `Discount (${quote.discountLabel})` : 'Discount',\n `−${money(quote.totals.discountCents)}`,\n quote.totals.discountCents > 0,\n ],\n ['Shipping', money(quote.totals.shippingCents), quote.totals.shippingCents > 0],\n [quote.taxLabel, money(quote.totals.taxCents), quote.totals.taxCents > 0],\n // `Tax is added at payment`, with no figure: Stripe works it out from the address.\n [quote.taxLabel, '', quote.taxAtPayment],\n ] as Array<[string, string, boolean]>\n ).filter(([, , shown]) => shown)\n\n return (\n <Box ref={ref} {...rest} sx={nodeSx}>\n <Stack spacing={3}>\n <Stack spacing={1}>\n {quote.storeName ? (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {quote.storeName}\n </Typography>\n ) : null}\n <Stack direction=\"row\" spacing={1.5} sx={{ alignItems: 'center', flexWrap: 'wrap', rowGap: 1 }}>\n <Typography variant=\"h4\" component=\"h1\">\n {heading || quote.number}\n </Typography>\n <Chip\n label={quote.statusLabel}\n color={quote.status === 'paid' ? 'success' : unpaid ? 'primary' : 'default'}\n size=\"small\"\n />\n </Stack>\n {quote.dateMs ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Dated ${dateLabel(quote.dateMs)}`}\n </Typography>\n ) : null}\n <Box>\n <Button variant=\"outlined\" size=\"small\" href={pdfHref} download>\n {'Download PDF'}\n </Button>\n </Box>\n </Stack>\n\n {addresses.length ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={{ xs: 2, sm: 3 }}>\n {addresses.map((block) => (\n <AddressBlock key={block.label} label={block.label} lines={block.lines} />\n ))}\n </Stack>\n ) : null}\n\n <Stack spacing={1.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Items'}\n </Typography>\n {quote.lines.map((line, index) => (\n <Stack key={index} direction=\"row\" spacing={2} sx={{ justifyContent: 'space-between' }}>\n <Stack spacing={0.25} sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\">\n {line.name}\n {line.variantLabel ? ` (${line.variantLabel})` : ''}\n </Typography>\n {line.description ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {line.description}\n </Typography>\n ) : null}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {[\n line.included ? `${line.quantity} included` : `${line.quantity} × ${money(line.unitAmountCents)}`,\n line.sku ? `SKU ${line.sku}` : '',\n ]\n .filter(Boolean)\n .join(' · ')}\n </Typography>\n </Stack>\n <Typography variant=\"body2\" sx={{ flexShrink: 0 }}>\n {line.included ? 'Included' : money(line.amountCents)}\n </Typography>\n </Stack>\n ))}\n <Divider />\n {totalRows.map(([label, value]) => (\n <TotalRow key={`${label}-${value}`} label={label} value={value} />\n ))}\n <TotalRow label=\"Total\" value={money(quote.totals.totalCents)} strong />\n </Stack>\n\n {quote.notes ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Notes'}\n </Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.notes}\n </Typography>\n </Stack>\n ) : null}\n {quote.terms ? (\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {'Terms'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ whiteSpace: 'pre-line' }}>\n {quote.terms}\n </Typography>\n </Stack>\n ) : null}\n\n <QuoteProofPanel\n view={quote}\n hostId={hostId}\n quoteId={link.current.quoteId}\n token={link.current.token}\n siteFetch={siteFetch}\n onView={(next) => setState({ kind: 'ready', view: next })}\n onReload={() => void load().then(setState)}\n onReplaced={() => setState({ kind: 'replaced', storeName: quote.storeName })}\n />\n\n {unpaid ? (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={2}>\n {returned === 'confirming' ? (\n <Alert severity=\"info\" icon={<CircularProgress size={20} />}>\n {'Thank you. We’re confirming your payment.'}\n </Alert>\n ) : returned === 'unconfirmed' ? (\n <Alert severity=\"info\">\n {'Your payment is still being confirmed. Your receipt will arrive by email.'}\n </Alert>\n ) : quote.approvalRequired ? (\n <Alert severity=\"info\">\n {`${quote.storeName || 'The business'} asks you to approve the proof before you pay.`}\n </Alert>\n ) : quote.payable ? (\n <>\n {returned === 'failed' ? (\n <Alert severity=\"warning\">{'Your payment did not go through. Nothing was charged.'}</Alert>\n ) : null}\n {nativeCheckout ? (\n <Suspense fallback={<StorefrontPaymentElementFallback />}>\n <StorefrontPaymentElement\n clientSecret={nativeCheckout.clientSecret}\n publishableKey={nativeCheckout.publishableKey}\n wallets={nativeCheckout.wallets}\n payLabel={quote.taxAtPayment ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`}\n defaultShippingAddress={stripeContact(quote.shipTo)}\n // An expired or unloadable session is replaced by a new press.\n onRestart={() => {\n setNativeCheckout(null)\n void pay()\n }}\n onCancel={() => setNativeCheckout(null)}\n />\n </Suspense>\n ) : (\n <Button\n variant=\"contained\"\n size=\"large\"\n onClick={() => void pay()}\n disabled={paying}\n sx={{ alignSelf: { xs: 'stretch', sm: 'flex-start' } }}\n >\n {paying\n ? 'Opening…'\n : quote.taxAtPayment\n ? `Pay ${money(quote.totals.totalCents)} plus tax`\n : `Pay ${money(quote.totals.totalCents)}`}\n </Button>\n )}\n {payError ? <Alert severity=\"error\">{payError}</Alert> : null}\n </>\n ) : (\n <Alert severity=\"info\">\n {`Contact ${quote.storeName || 'the business'} to pay this quote.`}\n </Alert>\n )}\n </Stack>\n </Paper>\n ) : (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={1.5} sx={{ alignItems: 'flex-start' }}>\n <Typography variant=\"body1\">\n {quote.status === 'paid'\n ? quote.paidAtMs\n ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.`\n : 'Paid. Thank you.'\n : `This quote is ${quote.statusLabel.toLowerCase()}.`}\n </Typography>\n {quote.receiptUrl ? (\n <Button variant=\"outlined\" href={quote.receiptUrl}>\n {'View your order'}\n </Button>\n ) : null}\n </Stack>\n </Paper>\n )}\n\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Questions about this quote? Contact ${quote.storeName || 'the business'}.`}\n </Typography>\n </Stack>\n </Box>\n )\n})\nQuotePageBody.displayName = 'QuotePageBody'\n\nexport default QuotePageBody\n\n"],"names":["Aglyn","Alert","Box","Button","Chip","CircularProgress","Divider","Paper","Stack","Typography","forwardRef","lazy","Suspense","useCallback","useEffect","useRef","useState","formatOrderMoney","readStorefrontCheckoutWallets","QuoteProofPanel","StorefrontPaymentElementFallback","StorefrontPaymentElement","then","module","default","CONFIRM_POLL_MS","CONFIRM_POLLS","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","addressLines","address","cityLine","city","state","postalCode","filter","Boolean","join","name","line1","line2","country","line","stripeContact","postal_code","AddressBlock","label","lines","spacing","sx","minWidth","flex","variant","color","map","index","TotalRow","value","strong","direction","justifyContent","QuotePageBody","props","ref","heading","rest","nodeSx","Array","isArray","hostId","useSite","siteFetch","useSiteFetch","setState","kind","paying","setPaying","payError","setPayError","nativeCheckout","setNativeCheckout","returned","setReturned","link","quoteId","token","sessionId","load","current","payload","response","encodeURIComponent","json","catch","ok","message","String","error","storeName","view","params","URLSearchParams","window","location","search","get","live","first","status","poll","Promise","resolve","setTimeout","next","pay","globalThis","attemptKey","crypto","randomUUID","now","Math","random","toString","slice","method","headers","body","JSON","stringify","q","t","v","version","clientSecret","publishableKey","wallets","url","assign","replaced","reason","p","border","borderColor","borderRadius","py","textAlign","size","aria-label","component","severity","business","quote","money","cents","currency","pdfHref","unpaid","addresses","customerName","company","billTo","shipTo","block","length","totalRows","totals","itemsCents","discountLabel","discountCents","shippingCents","taxLabel","taxCents","taxAtPayment","shown","alignItems","flexWrap","rowGap","number","statusLabel","dateMs","href","download","xs","sm","variantLabel","description","whiteSpace","included","quantity","unitAmountCents","sku","flexShrink","amountCents","totalCents","notes","terms","onView","onReload","onReplaced","icon","approvalRequired","payable","fallback","payLabel","defaultShippingAddress","onRestart","onCancel","onClick","disabled","alignSelf","paidAtMs","toLowerCase","receiptUrl","displayName"],"mappings":"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"}
@@ -0,0 +1,42 @@
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 type { QuotePageView } from '../model';
18
+ /** The page's own fetch: the site's API, with the site's preview rules. */
19
+ type SiteFetch = (input: string, init?: RequestInit) => Promise<Response>;
20
+ export interface QuoteProofPanelProps {
21
+ view: QuotePageView;
22
+ hostId: string;
23
+ quoteId: string;
24
+ token: string;
25
+ siteFetch: SiteFetch;
26
+ /** The quote as the server answered after a response, or after it changed. */
27
+ onView: (view: QuotePageView) => void;
28
+ /** Reload the quote: it changed since the page loaded. */
29
+ onReload: () => void;
30
+ /** The link was replaced. */
31
+ onReplaced: () => void;
32
+ }
33
+ /**
34
+ * The quote's proofs on the customer's page (AGL-4096): each image shown,
35
+ * every other file a download, and while the quote is open for an answer,
36
+ * "Approve this proof" (under a typed name) and "Request changes" (a comment
37
+ * and any artwork). The latest answer is the one that counts, so a customer
38
+ * who asked for changes can still approve, and the panel says what they last
39
+ * said. A paid quote shows its proofs and nothing to press.
40
+ */
41
+ export declare function QuoteProofPanel(props: QuoteProofPanelProps): import("react").JSX.Element;
42
+ export default QuoteProofPanel;