@aglyn/plugins-commerce 1.0.0-beta.289 → 1.0.0-beta.291
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/package.json +13 -13
- package/src/lib/components/commerce-console-page.js +2 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/commerce-pdf-download.d.ts +30 -0
- package/src/lib/components/console/commerce-pdf-download.js +53 -0
- package/src/lib/components/console/commerce-pdf-download.js.map +1 -0
- package/src/lib/components/console/host-orders-card.component.d.ts +6 -0
- package/src/lib/components/console/host-orders-card.component.js +3 -2
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/host-quotes-card.component.js +20 -4
- package/src/lib/components/console/host-quotes-card.component.js.map +1 -1
- package/src/lib/components/console/invoice-send.component.d.ts +44 -0
- package/src/lib/components/console/invoice-send.component.js +237 -0
- package/src/lib/components/console/invoice-send.component.js.map +1 -0
- package/src/lib/components/console/order-detail-dialog.component.d.ts +5 -0
- package/src/lib/components/console/order-detail-dialog.component.js +9 -2
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-invoice.component.d.ts +15 -4
- package/src/lib/components/console/order-invoice.component.js +93 -12
- package/src/lib/components/console/order-invoice.component.js.map +1 -1
- package/src/lib/components/console/quote-editor-dialog.component.d.ts +29 -0
- package/src/lib/components/console/quote-editor-dialog.component.js +154 -5
- package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/quote-proofs.component.d.ts +48 -0
- package/src/lib/components/console/quote-proofs.component.js +694 -0
- package/src/lib/components/console/quote-proofs.component.js.map +1 -0
- package/src/lib/components/console/quote-send.component.d.ts +42 -0
- package/src/lib/components/console/quote-send.component.js +307 -0
- package/src/lib/components/console/quote-send.component.js.map +1 -0
- package/src/lib/components/console/quote-start.component.d.ts +45 -0
- package/src/lib/components/console/quote-start.component.js +182 -0
- package/src/lib/components/console/quote-start.component.js.map +1 -0
- package/src/lib/components/product-options-field-body.d.ts +44 -0
- package/src/lib/components/product-options-field-body.js +260 -0
- package/src/lib/components/product-options-field-body.js.map +1 -0
- package/src/lib/components/product-options-field.d.ts +32 -0
- package/src/lib/components/product-options-field.js +128 -0
- package/src/lib/components/product-options-field.js.map +1 -0
- package/src/lib/components/quote-page-body.js +67 -20
- package/src/lib/components/quote-page-body.js.map +1 -1
- package/src/lib/components/quote-proof-panel.d.ts +42 -0
- package/src/lib/components/quote-proof-panel.js +436 -0
- package/src/lib/components/quote-proof-panel.js.map +1 -0
- package/src/lib/model/commerce-invoices.d.ts +132 -0
- package/src/lib/model/commerce-invoices.js +332 -0
- package/src/lib/model/commerce-invoices.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +29 -2
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-product-field.d.ts +23 -0
- package/src/lib/model/commerce-product-field.js +26 -0
- package/src/lib/model/commerce-product-field.js.map +1 -0
- package/src/lib/model/commerce-quote-email.d.ts +67 -0
- package/src/lib/model/commerce-quote-email.js +154 -0
- package/src/lib/model/commerce-quote-email.js.map +1 -0
- package/src/lib/model/commerce-quote-pay.d.ts +76 -6
- package/src/lib/model/commerce-quote-pay.js +105 -39
- package/src/lib/model/commerce-quote-pay.js.map +1 -1
- package/src/lib/model/commerce-quote-proofs.d.ts +159 -0
- package/src/lib/model/commerce-quote-proofs.js +348 -0
- package/src/lib/model/commerce-quote-proofs.js.map +1 -0
- package/src/lib/model/commerce-quote-request.d.ts +93 -0
- package/src/lib/model/commerce-quote-request.js +207 -0
- package/src/lib/model/commerce-quote-request.js.map +1 -0
- package/src/lib/model/commerce-quotes.d.ts +140 -3
- package/src/lib/model/commerce-quotes.js.map +1 -1
- package/src/lib/model/index.d.ts +4 -0
- package/src/lib/model/index.js +4 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/plugin.js +19 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +115 -70
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/commerce-pdf.d.ts +104 -0
- package/src/lib/server/commerce-pdf.js +310 -0
- package/src/lib/server/commerce-pdf.js.map +1 -0
- package/src/lib/server/draft-order.js +23 -3
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/invoice-email.d.ts +76 -0
- package/src/lib/server/invoice-email.js +183 -0
- package/src/lib/server/invoice-email.js.map +1 -0
- package/src/lib/server/order-invoice-send.d.ts +43 -0
- package/src/lib/server/order-invoice-send.js +218 -0
- package/src/lib/server/order-invoice-send.js.map +1 -0
- package/src/lib/server/order-print.d.ts +6 -0
- package/src/lib/server/order-print.js +22 -5
- package/src/lib/server/order-print.js.map +1 -1
- package/src/lib/server/order-status.d.ts +11 -0
- package/src/lib/server/order-status.js +44 -8
- package/src/lib/server/order-status.js.map +1 -1
- package/src/lib/server/pdf-response.d.ts +31 -0
- package/src/lib/server/pdf-response.js +30 -0
- package/src/lib/server/pdf-response.js.map +1 -0
- package/src/lib/server/person-eraser.d.ts +3 -2
- package/src/lib/server/person-eraser.js +25 -6
- package/src/lib/server/person-eraser.js.map +1 -1
- package/src/lib/server/pos-reader-splash.d.ts +2 -18
- package/src/lib/server/pos-reader-splash.js +8 -93
- package/src/lib/server/pos-reader-splash.js.map +1 -1
- package/src/lib/server/quote-email.d.ts +85 -0
- package/src/lib/server/quote-email.js +211 -0
- package/src/lib/server/quote-email.js.map +1 -0
- package/src/lib/server/quote-link-token.d.ts +11 -0
- package/src/lib/server/quote-link-token.js +21 -0
- package/src/lib/server/quote-link-token.js.map +1 -1
- package/src/lib/server/quote-pay.d.ts +38 -6
- package/src/lib/server/quote-pay.js +115 -53
- package/src/lib/server/quote-pay.js.map +1 -1
- package/src/lib/server/quote-proofs.d.ts +51 -0
- package/src/lib/server/quote-proofs.js +500 -0
- package/src/lib/server/quote-proofs.js.map +1 -0
- package/src/lib/server/quote-uploads.d.ts +33 -0
- package/src/lib/server/quote-uploads.js +29 -0
- package/src/lib/server/quote-uploads.js.map +1 -0
- package/src/lib/server/quote.d.ts +25 -0
- package/src/lib/server/quote.js +638 -8
- package/src/lib/server/quote.js.map +1 -1
- package/src/lib/server/site-image-source.d.ts +38 -0
- package/src/lib/server/site-image-source.js +130 -0
- package/src/lib/server/site-image-source.js.map +1 -0
- package/src/lib/server/site-page-resolver.js +2 -1
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server.js +24 -1
- package/src/lib/server.js.map +1 -1
- package/src/lib/site.js +8 -0
- package/src/lib/site.js.map +1 -1
- package/src/lib/tenant-emails.js +243 -0
- package/src/lib/tenant-emails.js.map +1 -1
- package/src/lib/utils/commerce-document-pdf.d.ts +82 -0
- package/src/lib/utils/commerce-document-pdf.js +613 -0
- package/src/lib/utils/commerce-document-pdf.js.map +1 -0
- package/src/lib/utils/invoice-email-content.d.ts +45 -0
- package/src/lib/utils/invoice-email-content.js +126 -0
- package/src/lib/utils/invoice-email-content.js.map +1 -0
- package/src/lib/utils/order-invoice.d.ts +52 -3
- package/src/lib/utils/order-invoice.js +124 -64
- package/src/lib/utils/order-invoice.js.map +1 -1
- package/src/lib/utils/quote-email-content.d.ts +62 -0
- package/src/lib/utils/quote-email-content.js +154 -0
- package/src/lib/utils/quote-email-content.js.map +1 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2026 Aglyn LLC
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/ import * as Aglyn from "@aglyn/aglyn";
|
|
19
|
+
import { mdiPackageVariantClosed } from "@aglyn/shared-data-mdi";
|
|
20
|
+
import Box from "@mui/material/Box";
|
|
21
|
+
import CircularProgress from "@mui/material/CircularProgress";
|
|
22
|
+
import { forwardRef, lazy, Suspense } from "react";
|
|
23
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
25
|
+
/*
|
|
26
|
+
* THE PRODUCT AND OPTIONS FIELD (AGL-4098): a form field that asks which of
|
|
27
|
+
* the store's products, and which of its options, a person wants — on a
|
|
28
|
+
* "Request a quote" form, say.
|
|
29
|
+
*
|
|
30
|
+
* It lives in Commerce because the products are Commerce's, and it is a form
|
|
31
|
+
* field like any other: it knows nothing about the form around it and posts
|
|
32
|
+
* plain strings under its name. Its answer is the product and options in
|
|
33
|
+
* words (`Vinyl banner — 3 × 6 ft / Matte`); beside it, under `{name}__data`,
|
|
34
|
+
* it posts the exact product, variant and options for this plugin to read
|
|
35
|
+
* back when a quote is started from the request (`parseProductFieldValue`).
|
|
36
|
+
* The forms plugin keeps that value apart from the answers a person reads.
|
|
37
|
+
*
|
|
38
|
+
* This shell is what a page loads until the field draws; the picker is a
|
|
39
|
+
* chunk of its own. The component id is persisted in documents; never rename
|
|
40
|
+
* it. The core's form reader restates it (`FORM_PLUGIN_ANSWER_ELEMENTS`).
|
|
41
|
+
*/ export const PRODUCT_OPTIONS_FIELD_ID = 'product-options-field';
|
|
42
|
+
const ProductOptionsFieldBody = /*#__PURE__*/ lazy(()=>import("./product-options-field-body.js"));
|
|
43
|
+
/** A product and its options, picked from the store; sent in words. */ const ProductOptionsField = /*#__PURE__*/ forwardRef((props, ref)=>/*#__PURE__*/ _jsx(Suspense, {
|
|
44
|
+
fallback: /*#__PURE__*/ _jsx(Box, {
|
|
45
|
+
sx: {
|
|
46
|
+
py: 1
|
|
47
|
+
},
|
|
48
|
+
children: /*#__PURE__*/ _jsx(CircularProgress, {
|
|
49
|
+
size: 20,
|
|
50
|
+
"aria-label": "Loading the product field"
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
children: /*#__PURE__*/ _jsx(ProductOptionsFieldBody, _extends({
|
|
54
|
+
ref: ref
|
|
55
|
+
}, props))
|
|
56
|
+
}));
|
|
57
|
+
ProductOptionsField.displayName = 'AglynProductOptionsField';
|
|
58
|
+
export const schema = {
|
|
59
|
+
$id: PRODUCT_OPTIONS_FIELD_ID,
|
|
60
|
+
pluginId: BUNDLE_ID,
|
|
61
|
+
displayName: 'Product and options',
|
|
62
|
+
description: 'A form field: the person picks one of your products and its options, such as size and finish. It arrives with the submission, and a quote started from it begins with that product.',
|
|
63
|
+
category: Aglyn.ComponentCategory.FORMS,
|
|
64
|
+
icon: {
|
|
65
|
+
path: mdiPackageVariantClosed.path,
|
|
66
|
+
sx: {
|
|
67
|
+
color: 'info.main'
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
flags: {
|
|
71
|
+
selfClosing: Aglyn.FEATURE_FLAG.ENABLED
|
|
72
|
+
},
|
|
73
|
+
attributes: [
|
|
74
|
+
{
|
|
75
|
+
name: 'label',
|
|
76
|
+
label: 'Label',
|
|
77
|
+
description: 'The question above the picker, such as “What would you like priced?”.',
|
|
78
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'name',
|
|
82
|
+
label: 'Field name',
|
|
83
|
+
description: 'The name the choice is listed under in the Inbox and exports.',
|
|
84
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'productId',
|
|
88
|
+
label: 'Product',
|
|
89
|
+
description: 'Ask about one product only: the person picks its options. Leave it empty to let them pick from your store.',
|
|
90
|
+
component: Aglyn.FieldComponentType.PRODUCT_SELECT
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'required',
|
|
94
|
+
label: 'Required?',
|
|
95
|
+
description: 'The form can’t be sent until a product (and each of its options) is picked.',
|
|
96
|
+
component: Aglyn.FieldComponentType.SWITCH
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
};
|
|
100
|
+
export const presets = [
|
|
101
|
+
{
|
|
102
|
+
$id: generatePresetId(PRODUCT_OPTIONS_FIELD_ID),
|
|
103
|
+
type: Aglyn.NodeType.PRESET,
|
|
104
|
+
displayName: 'Product and options',
|
|
105
|
+
pluginId: BUNDLE_ID,
|
|
106
|
+
description: 'A product from your store and its options, for a quote request',
|
|
107
|
+
category: Aglyn.ComponentCategory.FORMS,
|
|
108
|
+
icon: {
|
|
109
|
+
path: mdiPackageVariantClosed.path,
|
|
110
|
+
sx: {
|
|
111
|
+
color: 'info.main'
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
data: {
|
|
115
|
+
$id: null,
|
|
116
|
+
componentId: PRODUCT_OPTIONS_FIELD_ID,
|
|
117
|
+
pluginId: BUNDLE_ID,
|
|
118
|
+
props: {
|
|
119
|
+
name: 'product',
|
|
120
|
+
label: 'Product',
|
|
121
|
+
required: true
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
];
|
|
126
|
+
export default ProductOptionsField;
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=product-options-field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/product-options-field.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 { mdiPackageVariantClosed } from '@aglyn/shared-data-mdi'\nimport Box from '@mui/material/Box'\nimport CircularProgress from '@mui/material/CircularProgress'\nimport { forwardRef, lazy, Suspense } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n/*\n * THE PRODUCT AND OPTIONS FIELD (AGL-4098): a form field that asks which of\n * the store's products, and which of its options, a person wants — on a\n * \"Request a quote\" form, say.\n *\n * It lives in Commerce because the products are Commerce's, and it is a form\n * field like any other: it knows nothing about the form around it and posts\n * plain strings under its name. Its answer is the product and options in\n * words (`Vinyl banner — 3 × 6 ft / Matte`); beside it, under `{name}__data`,\n * it posts the exact product, variant and options for this plugin to read\n * back when a quote is started from the request (`parseProductFieldValue`).\n * The forms plugin keeps that value apart from the answers a person reads.\n *\n * This shell is what a page loads until the field draws; the picker is a\n * chunk of its own. The component id is persisted in documents; never rename\n * it. The core's form reader restates it (`FORM_PLUGIN_ANSWER_ELEMENTS`).\n */\nexport const PRODUCT_OPTIONS_FIELD_ID: Aglyn.ComponentId = 'product-options-field'\n\nexport interface ProductOptionsFieldProps {\n /** What the product and options are sent as. */\n name?: string\n /** The question, above the picker. */\n label?: string\n /** One product to ask about; empty lets the person pick from the store. */\n productId?: string\n required?: boolean\n}\n\nconst ProductOptionsFieldBody = lazy(() => import('./product-options-field-body'))\n\n/** A product and its options, picked from the store; sent in words. */\nconst ProductOptionsField = forwardRef<HTMLDivElement, ProductOptionsFieldProps>((props, ref) => (\n <Suspense\n fallback={\n <Box sx={{ py: 1 }}>\n <CircularProgress size={20} aria-label=\"Loading the product field\" />\n </Box>\n }\n >\n <ProductOptionsFieldBody ref={ref} {...props} />\n </Suspense>\n))\nProductOptionsField.displayName = 'AglynProductOptionsField'\n\nexport const schema: Aglyn.ComponentSchema<ProductOptionsFieldProps> = {\n $id: PRODUCT_OPTIONS_FIELD_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product and options',\n description:\n 'A form field: the person picks one of your products and its options, such as size and finish. It arrives with the submission, and a quote started from it begins with that product.',\n category: Aglyn.ComponentCategory.FORMS,\n icon: { path: mdiPackageVariantClosed.path, sx: { color: 'info.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'label',\n label: 'Label',\n description: 'The question above the picker, such as “What would you like priced?”.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'name',\n label: 'Field name',\n description: 'The name the choice is listed under in the Inbox and exports.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'productId',\n label: 'Product',\n description: 'Ask about one product only: the person picks its options. Leave it empty to let them pick from your store.',\n component: Aglyn.FieldComponentType.PRODUCT_SELECT,\n },\n {\n name: 'required',\n label: 'Required?',\n description: 'The form can’t be sent until a product (and each of its options) is picked.',\n component: Aglyn.FieldComponentType.SWITCH,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(PRODUCT_OPTIONS_FIELD_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product and options',\n pluginId: BUNDLE_ID,\n description: 'A product from your store and its options, for a quote request',\n category: Aglyn.ComponentCategory.FORMS,\n icon: { path: mdiPackageVariantClosed.path, sx: { color: 'info.main' } },\n data: {\n $id: null,\n componentId: PRODUCT_OPTIONS_FIELD_ID,\n pluginId: BUNDLE_ID,\n props: { name: 'product', label: 'Product', required: true },\n },\n },\n]\n\nexport default ProductOptionsField\n"],"names":["Aglyn","mdiPackageVariantClosed","Box","CircularProgress","forwardRef","lazy","Suspense","BUNDLE_ID","generatePresetId","PRODUCT_OPTIONS_FIELD_ID","ProductOptionsFieldBody","ProductOptionsField","props","ref","fallback","sx","py","size","aria-label","displayName","schema","$id","pluginId","description","category","ComponentCategory","FORMS","icon","path","color","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","label","component","FieldComponentType","TEXT_FIELD","PRODUCT_SELECT","SWITCH","presets","type","NodeType","PRESET","data","componentId","required"],"mappings":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,uBAAuB,QAAQ,yBAAwB;AAChE,OAAOC,SAAS,oBAAmB;AACnC,OAAOC,sBAAsB,iCAAgC;AAC7D,SAASC,UAAU,EAAEC,IAAI,EAAEC,QAAQ,QAAQ,QAAO;AAClD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,2BAA8C,wBAAuB;AAYlF,MAAMC,wCAA0BL,KAAK,IAAM,MAAM,CAAC;AAElD,qEAAqE,GACrE,MAAMM,oCAAsBP,WAAqD,CAACQ,OAAOC,oBACvF,KAACP;QACCQ,wBACE,KAACZ;YAAIa,IAAI;gBAAEC,IAAI;YAAE;sBACf,cAAA,KAACb;gBAAiBc,MAAM;gBAAIC,cAAW;;;kBAI3C,cAAA,KAACR;YAAwBG,KAAKA;WAASD;;AAG3CD,oBAAoBQ,WAAW,GAAG;AAElC,OAAO,MAAMC,SAA0D;IACrEC,KAAKZ;IACLa,UAAUf;IACVY,aAAa;IACbI,aACE;IACFC,UAAUxB,MAAMyB,iBAAiB,CAACC,KAAK;IACvCC,MAAM;QAAEC,MAAM3B,wBAAwB2B,IAAI;QAAEb,IAAI;YAAEc,OAAO;QAAY;IAAE;IACvEC,OAAO;QAAEC,aAAa/B,MAAMgC,YAAY,CAACC,OAAO;IAAC;IACjDC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPb,aAAa;YACbc,WAAWrC,MAAMsC,kBAAkB,CAACC,UAAU;QAChD;QACA;YACEJ,MAAM;YACNC,OAAO;YACPb,aAAa;YACbc,WAAWrC,MAAMsC,kBAAkB,CAACC,UAAU;QAChD;QACA;YACEJ,MAAM;YACNC,OAAO;YACPb,aAAa;YACbc,WAAWrC,MAAMsC,kBAAkB,CAACE,cAAc;QACpD;QACA;YACEL,MAAM;YACNC,OAAO;YACPb,aAAa;YACbc,WAAWrC,MAAMsC,kBAAkB,CAACG,MAAM;QAC5C;KACD;AACH,EAAC;AAED,OAAO,MAAMC,UAAgC;IAC3C;QACErB,KAAKb,iBAAiBC;QACtBkC,MAAM3C,MAAM4C,QAAQ,CAACC,MAAM;QAC3B1B,aAAa;QACbG,UAAUf;QACVgB,aAAa;QACbC,UAAUxB,MAAMyB,iBAAiB,CAACC,KAAK;QACvCC,MAAM;YAAEC,MAAM3B,wBAAwB2B,IAAI;YAAEb,IAAI;gBAAEc,OAAO;YAAY;QAAE;QACvEiB,MAAM;YACJzB,KAAK;YACL0B,aAAatC;YACba,UAAUf;YACVK,OAAO;gBAAEuB,MAAM;gBAAWC,OAAO;gBAAWY,UAAU;YAAK;QAC7D;IACF;CACD,CAAA;AAED,eAAerC,oBAAmB"}
|
|
@@ -28,10 +28,17 @@ 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
|
|
34
35
|
})));
|
|
36
|
+
/** `quote` or `invoice`, as the page says it (AGL-4099). */ const nounOf = (kind)=>kind === 'invoice' ? 'invoice' : 'quote';
|
|
37
|
+
/** What is added when the customer pays: `shipping`, `tax`, `shipping and tax`, or nothing. */ function addedAtPayment(view) {
|
|
38
|
+
if (view.shippingAtPayment && view.taxAtPayment) return 'shipping and tax';
|
|
39
|
+
if (view.shippingAtPayment) return 'shipping';
|
|
40
|
+
return view.taxAtPayment ? 'tax' : '';
|
|
41
|
+
}
|
|
35
42
|
/** After a payment returns here, how often and how long the page asks whether it landed. */ const CONFIRM_POLL_MS = 2000;
|
|
36
43
|
const CONFIRM_POLLS = 15;
|
|
37
44
|
function dateLabel(atMs) {
|
|
@@ -150,20 +157,23 @@ function TotalRow({ label, value, strong }) {
|
|
|
150
157
|
const load = useCallback(async ()=>{
|
|
151
158
|
const { quoteId, token } = link.current;
|
|
152
159
|
try {
|
|
153
|
-
var _payload_storeName;
|
|
154
160
|
const response = await siteFetch(`/api/commerce/quote-view?hostId=${encodeURIComponent(hostId != null ? hostId : '')}` + `&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`);
|
|
155
161
|
const payload = await response.json().catch(()=>({}));
|
|
156
162
|
if (!response.ok) {
|
|
157
163
|
var _ref;
|
|
158
164
|
return {
|
|
159
165
|
kind: 'missing',
|
|
160
|
-
message: String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'We could not find that quote.')
|
|
166
|
+
message: String((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'We could not find that quote or invoice.')
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if ((payload == null ? void 0 : payload.state) === 'replaced') {
|
|
170
|
+
var _payload_storeName;
|
|
171
|
+
return {
|
|
172
|
+
kind: 'replaced',
|
|
173
|
+
storeName: String((_payload_storeName = payload.storeName) != null ? _payload_storeName : ''),
|
|
174
|
+
noun: nounOf(payload.kind)
|
|
161
175
|
};
|
|
162
176
|
}
|
|
163
|
-
if ((payload == null ? void 0 : payload.state) === 'replaced') return {
|
|
164
|
-
kind: 'replaced',
|
|
165
|
-
storeName: String((_payload_storeName = payload.storeName) != null ? _payload_storeName : '')
|
|
166
|
-
};
|
|
167
177
|
return {
|
|
168
178
|
kind: 'ready',
|
|
169
179
|
view: payload
|
|
@@ -171,7 +181,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
171
181
|
} catch (unused) {
|
|
172
182
|
return {
|
|
173
183
|
kind: 'missing',
|
|
174
|
-
message: 'This
|
|
184
|
+
message: 'This page could not be loaded. Check your connection and try again.'
|
|
175
185
|
};
|
|
176
186
|
}
|
|
177
187
|
}, [
|
|
@@ -190,7 +200,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
190
200
|
if (!link.current.quoteId || !link.current.token) {
|
|
191
201
|
setState({
|
|
192
202
|
kind: 'missing',
|
|
193
|
-
message: 'Open this page from the link you were sent with your quote.'
|
|
203
|
+
message: 'Open this page from the link you were sent with your quote or invoice.'
|
|
194
204
|
});
|
|
195
205
|
return;
|
|
196
206
|
}
|
|
@@ -275,7 +285,8 @@ function TotalRow({ label, value, strong }) {
|
|
|
275
285
|
if (payload == null ? void 0 : payload.replaced) {
|
|
276
286
|
setState({
|
|
277
287
|
kind: 'replaced',
|
|
278
|
-
storeName: view.storeName
|
|
288
|
+
storeName: view.storeName,
|
|
289
|
+
noun: nounOf(view.kind)
|
|
279
290
|
});
|
|
280
291
|
return;
|
|
281
292
|
}
|
|
@@ -329,7 +340,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
329
340
|
],
|
|
330
341
|
children: /*#__PURE__*/ _jsx(CircularProgress, {
|
|
331
342
|
size: 28,
|
|
332
|
-
"aria-label": "Loading
|
|
343
|
+
"aria-label": "Loading"
|
|
333
344
|
})
|
|
334
345
|
}));
|
|
335
346
|
}
|
|
@@ -344,7 +355,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
344
355
|
/*#__PURE__*/ _jsx(Typography, {
|
|
345
356
|
variant: "h4",
|
|
346
357
|
component: "h1",
|
|
347
|
-
children: heading || 'Your quote'
|
|
358
|
+
children: heading || 'Your quote or invoice'
|
|
348
359
|
}),
|
|
349
360
|
/*#__PURE__*/ _jsx(Alert, {
|
|
350
361
|
severity: "info",
|
|
@@ -371,12 +382,12 @@ function TotalRow({ label, value, strong }) {
|
|
|
371
382
|
/*#__PURE__*/ _jsx(Typography, {
|
|
372
383
|
variant: "h4",
|
|
373
384
|
component: "h1",
|
|
374
|
-
children:
|
|
385
|
+
children: `This ${state.noun} was updated`
|
|
375
386
|
}),
|
|
376
387
|
/*#__PURE__*/ _jsx(Typography, {
|
|
377
388
|
variant: "body1",
|
|
378
389
|
color: "text.secondary",
|
|
379
|
-
children: `${business} updated this
|
|
390
|
+
children: `${business} updated this ${state.noun} and sent you a newer link. Open their most recent message to see it.`
|
|
380
391
|
})
|
|
381
392
|
]
|
|
382
393
|
})
|
|
@@ -384,7 +395,11 @@ function TotalRow({ label, value, strong }) {
|
|
|
384
395
|
}
|
|
385
396
|
const quote = state.view;
|
|
386
397
|
const money = (cents)=>formatOrderMoney(cents, quote.currency);
|
|
398
|
+
// The same signed link as the page's data; the server makes the PDF from the same view.
|
|
399
|
+
const pdfHref = `/api/commerce/quote-pdf?hostId=${encodeURIComponent(hostId)}` + `&q=${encodeURIComponent(link.current.quoteId)}&t=${encodeURIComponent(link.current.token)}`;
|
|
387
400
|
const unpaid = quote.status === 'unpaid';
|
|
401
|
+
const noun = nounOf(quote.kind);
|
|
402
|
+
const later = addedAtPayment(quote);
|
|
388
403
|
const addresses = [
|
|
389
404
|
quote.customerName || quote.company ? {
|
|
390
405
|
label: 'Prepared for',
|
|
@@ -423,6 +438,12 @@ function TotalRow({ label, value, strong }) {
|
|
|
423
438
|
money(quote.totals.taxCents),
|
|
424
439
|
quote.totals.taxCents > 0
|
|
425
440
|
],
|
|
441
|
+
// The rate an invoiced draft's customer picks when they pay (AGL-4099).
|
|
442
|
+
[
|
|
443
|
+
'Shipping is chosen when you pay',
|
|
444
|
+
'',
|
|
445
|
+
quote.shippingAtPayment === true
|
|
446
|
+
],
|
|
426
447
|
// `Tax is added at payment`, with no figure: Stripe works it out from the address.
|
|
427
448
|
[
|
|
428
449
|
quote.taxLabel,
|
|
@@ -457,7 +478,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
457
478
|
/*#__PURE__*/ _jsx(Typography, {
|
|
458
479
|
variant: "h4",
|
|
459
480
|
component: "h1",
|
|
460
|
-
children: heading || quote.number
|
|
481
|
+
children: quote.kind !== 'invoice' && heading || quote.number
|
|
461
482
|
}),
|
|
462
483
|
/*#__PURE__*/ _jsx(Chip, {
|
|
463
484
|
label: quote.statusLabel,
|
|
@@ -470,7 +491,16 @@ function TotalRow({ label, value, strong }) {
|
|
|
470
491
|
variant: "body2",
|
|
471
492
|
color: "text.secondary",
|
|
472
493
|
children: `Dated ${dateLabel(quote.dateMs)}`
|
|
473
|
-
}) : null
|
|
494
|
+
}) : null,
|
|
495
|
+
/*#__PURE__*/ _jsx(Box, {
|
|
496
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
497
|
+
variant: "outlined",
|
|
498
|
+
size: "small",
|
|
499
|
+
href: pdfHref,
|
|
500
|
+
download: true,
|
|
501
|
+
children: 'Download PDF'
|
|
502
|
+
})
|
|
503
|
+
})
|
|
474
504
|
]
|
|
475
505
|
}),
|
|
476
506
|
addresses.length ? /*#__PURE__*/ _jsx(Stack, {
|
|
@@ -589,6 +619,23 @@ function TotalRow({ label, value, strong }) {
|
|
|
589
619
|
})
|
|
590
620
|
]
|
|
591
621
|
}) : null,
|
|
622
|
+
/*#__PURE__*/ _jsx(QuoteProofPanel, {
|
|
623
|
+
view: quote,
|
|
624
|
+
hostId: hostId,
|
|
625
|
+
quoteId: link.current.quoteId,
|
|
626
|
+
token: link.current.token,
|
|
627
|
+
siteFetch: siteFetch,
|
|
628
|
+
onView: (next)=>setState({
|
|
629
|
+
kind: 'ready',
|
|
630
|
+
view: next
|
|
631
|
+
}),
|
|
632
|
+
onReload: ()=>void load().then(setState),
|
|
633
|
+
onReplaced: ()=>setState({
|
|
634
|
+
kind: 'replaced',
|
|
635
|
+
storeName: quote.storeName,
|
|
636
|
+
noun
|
|
637
|
+
})
|
|
638
|
+
}),
|
|
592
639
|
unpaid ? /*#__PURE__*/ _jsx(Paper, {
|
|
593
640
|
variant: "outlined",
|
|
594
641
|
sx: {
|
|
@@ -623,7 +670,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
623
670
|
clientSecret: nativeCheckout.clientSecret,
|
|
624
671
|
publishableKey: nativeCheckout.publishableKey,
|
|
625
672
|
wallets: nativeCheckout.wallets,
|
|
626
|
-
payLabel:
|
|
673
|
+
payLabel: later ? 'Pay now' : `Pay ${money(quote.totals.totalCents)}`,
|
|
627
674
|
defaultShippingAddress: stripeContact(quote.shipTo),
|
|
628
675
|
// An expired or unloadable session is replaced by a new press.
|
|
629
676
|
onRestart: ()=>{
|
|
@@ -643,7 +690,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
643
690
|
sm: 'flex-start'
|
|
644
691
|
}
|
|
645
692
|
},
|
|
646
|
-
children: paying ? 'Opening…' :
|
|
693
|
+
children: paying ? 'Opening…' : later ? `Pay ${money(quote.totals.totalCents)} plus ${later}` : `Pay ${money(quote.totals.totalCents)}`
|
|
647
694
|
}),
|
|
648
695
|
payError ? /*#__PURE__*/ _jsx(Alert, {
|
|
649
696
|
severity: "error",
|
|
@@ -652,7 +699,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
652
699
|
]
|
|
653
700
|
}) : /*#__PURE__*/ _jsx(Alert, {
|
|
654
701
|
severity: "info",
|
|
655
|
-
children: `Contact ${quote.storeName || 'the business'} to pay this
|
|
702
|
+
children: `Contact ${quote.storeName || 'the business'} to pay this ${noun}.`
|
|
656
703
|
})
|
|
657
704
|
})
|
|
658
705
|
}) : /*#__PURE__*/ _jsx(Paper, {
|
|
@@ -671,7 +718,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
671
718
|
children: [
|
|
672
719
|
/*#__PURE__*/ _jsx(Typography, {
|
|
673
720
|
variant: "body1",
|
|
674
|
-
children: quote.status === 'paid' ? quote.paidAtMs ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.` : 'Paid. Thank you.' : `This
|
|
721
|
+
children: quote.status === 'paid' ? quote.paidAtMs ? `Paid ${dateLabel(quote.paidAtMs)}. Thank you.` : 'Paid. Thank you.' : `This ${noun} is ${quote.statusLabel.toLowerCase()}.`
|
|
675
722
|
}),
|
|
676
723
|
quote.receiptUrl ? /*#__PURE__*/ _jsx(Button, {
|
|
677
724
|
variant: "outlined",
|
|
@@ -684,7 +731,7 @@ function TotalRow({ label, value, strong }) {
|
|
|
684
731
|
/*#__PURE__*/ _jsx(Typography, {
|
|
685
732
|
variant: "body2",
|
|
686
733
|
color: "text.secondary",
|
|
687
|
-
children: `Questions about this
|
|
734
|
+
children: `Questions about this ${noun}? Contact ${quote.storeName || 'the business'}.`
|
|
688
735
|
})
|
|
689
736
|
]
|
|
690
737
|
})
|
|
@@ -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":"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"}
|
|
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; noun: string }\n | { kind: 'ready'; view: QuotePageView }\n\n/** `quote` or `invoice`, as the page says it (AGL-4099). */\nconst nounOf = (kind: unknown) => (kind === 'invoice' ? 'invoice' : 'quote')\n\n/** What is added when the customer pays: `shipping`, `tax`, `shipping and tax`, or nothing. */\nfunction addedAtPayment(view: Pick<QuotePageView, 'shippingAtPayment' | 'taxAtPayment'>): string {\n if (view.shippingAtPayment && view.taxAtPayment) return 'shipping and tax'\n if (view.shippingAtPayment) return 'shipping'\n return view.taxAtPayment ? 'tax' : ''\n}\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 or invoice.') }\n }\n if (payload?.state === 'replaced') {\n return { kind: 'replaced', storeName: String(payload.storeName ?? ''), noun: nounOf(payload.kind) }\n }\n return { kind: 'ready', view: payload as QuotePageView }\n } catch {\n return { kind: 'missing', message: 'This page 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 or invoice.' })\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, noun: nounOf(view.kind) })\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\" />\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 or invoice'}\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 ${state.noun} was updated`}\n </Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">\n {`${business} updated this ${state.noun} 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 noun = nounOf(quote.kind)\n const later = addedAtPayment(quote)\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 // The rate an invoiced draft's customer picks when they pay (AGL-4099).\n ['Shipping is chosen when you pay', '', quote.shippingAtPayment === true],\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 {/* The element's own heading is a quote's; an invoice always says its number. */}\n {(quote.kind !== 'invoice' && 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, noun })}\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={later ? '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 : later\n ? `Pay ${money(quote.totals.totalCents)} plus ${later}`\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 ${noun}.`}\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 ${noun} 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 ${noun}? 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","nounOf","kind","addedAtPayment","view","shippingAtPayment","taxAtPayment","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","paying","setPaying","payError","setPayError","nativeCheckout","setNativeCheckout","returned","setReturned","link","quoteId","token","sessionId","load","current","response","encodeURIComponent","payload","json","catch","ok","message","String","error","storeName","noun","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","later","addresses","customerName","company","billTo","shipTo","block","length","totalRows","totals","itemsCents","discountLabel","discountCents","shippingCents","taxLabel","taxCents","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;
|