@aglyn/plugins-commerce 1.0.0-beta.288 → 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 (129) hide show
  1. package/README.md +2 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/commerce-console-page.js +29 -2
  4. package/src/lib/components/commerce-console-page.js.map +1 -1
  5. package/src/lib/components/console/commerce-analytics-card.component.js +4 -2
  6. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -1
  7. package/src/lib/components/console/commerce-pdf-download.d.ts +30 -0
  8. package/src/lib/components/console/commerce-pdf-download.js +53 -0
  9. package/src/lib/components/console/commerce-pdf-download.js.map +1 -0
  10. package/src/lib/components/console/host-orders-card.component.js +5 -1
  11. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  12. package/src/lib/components/console/host-quotes-card.component.d.ts +34 -0
  13. package/src/lib/components/console/host-quotes-card.component.js +263 -0
  14. package/src/lib/components/console/host-quotes-card.component.js.map +1 -0
  15. package/src/lib/components/console/order-invoice.component.d.ts +6 -4
  16. package/src/lib/components/console/order-invoice.component.js +67 -11
  17. package/src/lib/components/console/order-invoice.component.js.map +1 -1
  18. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +33 -28
  19. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  20. package/src/lib/components/console/quote-editor-dialog.component.d.ts +45 -0
  21. package/src/lib/components/console/quote-editor-dialog.component.js +1317 -0
  22. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -0
  23. package/src/lib/components/console/quote-pay-link.component.d.ts +38 -0
  24. package/src/lib/components/console/quote-pay-link.component.js +213 -0
  25. package/src/lib/components/console/quote-pay-link.component.js.map +1 -0
  26. package/src/lib/components/console/quote-proofs.component.d.ts +37 -0
  27. package/src/lib/components/console/quote-proofs.component.js +626 -0
  28. package/src/lib/components/console/quote-proofs.component.js.map +1 -0
  29. package/src/lib/components/console/quote-settings-card.component.d.ts +29 -0
  30. package/src/lib/components/console/quote-settings-card.component.js +121 -0
  31. package/src/lib/components/console/quote-settings-card.component.js.map +1 -0
  32. package/src/lib/components/console/tax-settings-card.component.js +4 -1
  33. package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
  34. package/src/lib/components/quote-page-body.d.ts +33 -0
  35. package/src/lib/components/quote-page-body.js +724 -0
  36. package/src/lib/components/quote-page-body.js.map +1 -0
  37. package/src/lib/components/quote-page.d.ts +29 -0
  38. package/src/lib/components/quote-page.js +96 -0
  39. package/src/lib/components/quote-page.js.map +1 -0
  40. package/src/lib/components/quote-proof-panel.d.ts +42 -0
  41. package/src/lib/components/quote-proof-panel.js +436 -0
  42. package/src/lib/components/quote-proof-panel.js.map +1 -0
  43. package/src/lib/components/storefront-payment-element.d.ts +7 -1
  44. package/src/lib/components/storefront-payment-element.js +8 -3
  45. package/src/lib/components/storefront-payment-element.js.map +1 -1
  46. package/src/lib/constants/orders-list-query.js +6 -1
  47. package/src/lib/constants/orders-list-query.js.map +1 -1
  48. package/src/lib/constants/quote-page.d.ts +30 -0
  49. package/src/lib/constants/quote-page.js +35 -0
  50. package/src/lib/constants/quote-page.js.map +1 -0
  51. package/src/lib/model/commerce-orders.d.ts +25 -2
  52. package/src/lib/model/commerce-orders.js +10 -1
  53. package/src/lib/model/commerce-orders.js.map +1 -1
  54. package/src/lib/model/commerce-quote-pay.d.ts +256 -0
  55. package/src/lib/model/commerce-quote-pay.js +426 -0
  56. package/src/lib/model/commerce-quote-pay.js.map +1 -0
  57. package/src/lib/model/commerce-quote-proofs.d.ts +159 -0
  58. package/src/lib/model/commerce-quote-proofs.js +348 -0
  59. package/src/lib/model/commerce-quote-proofs.js.map +1 -0
  60. package/src/lib/model/commerce-quotes.d.ts +335 -0
  61. package/src/lib/model/commerce-quotes.js +522 -0
  62. package/src/lib/model/commerce-quotes.js.map +1 -0
  63. package/src/lib/model/index.d.ts +3 -0
  64. package/src/lib/model/index.js +3 -0
  65. package/src/lib/model/index.js.map +1 -1
  66. package/src/lib/model/plugin-permissions.d.ts +1 -1
  67. package/src/lib/model/plugin-permissions.js +20 -0
  68. package/src/lib/model/plugin-permissions.js.map +1 -1
  69. package/src/lib/server/api-v1/orders-and-products.js +6 -2
  70. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  71. package/src/lib/server/billing-webhook.js +127 -52
  72. package/src/lib/server/billing-webhook.js.map +1 -1
  73. package/src/lib/server/checkout-session-expiry.d.ts +36 -0
  74. package/src/lib/server/checkout-session-expiry.js +63 -0
  75. package/src/lib/server/checkout-session-expiry.js.map +1 -0
  76. package/src/lib/server/commerce-pdf.d.ts +100 -0
  77. package/src/lib/server/commerce-pdf.js +283 -0
  78. package/src/lib/server/commerce-pdf.js.map +1 -0
  79. package/src/lib/server/draft-order.js +16 -8
  80. package/src/lib/server/draft-order.js.map +1 -1
  81. package/src/lib/server/order-print.d.ts +6 -0
  82. package/src/lib/server/order-print.js +22 -5
  83. package/src/lib/server/order-print.js.map +1 -1
  84. package/src/lib/server/pdf-response.d.ts +31 -0
  85. package/src/lib/server/pdf-response.js +30 -0
  86. package/src/lib/server/pdf-response.js.map +1 -0
  87. package/src/lib/server/person-eraser.d.ts +7 -0
  88. package/src/lib/server/person-eraser.js +24 -2
  89. package/src/lib/server/person-eraser.js.map +1 -1
  90. package/src/lib/server/pos-reader-splash.d.ts +2 -18
  91. package/src/lib/server/pos-reader-splash.js +8 -93
  92. package/src/lib/server/pos-reader-splash.js.map +1 -1
  93. package/src/lib/server/pos-return.js +3 -1
  94. package/src/lib/server/pos-return.js.map +1 -1
  95. package/src/lib/server/quote-link-token.d.ts +39 -0
  96. package/src/lib/server/quote-link-token.js +97 -0
  97. package/src/lib/server/quote-link-token.js.map +1 -0
  98. package/src/lib/server/quote-pay.d.ts +110 -0
  99. package/src/lib/server/quote-pay.js +606 -0
  100. package/src/lib/server/quote-pay.js.map +1 -0
  101. package/src/lib/server/quote-proofs.d.ts +51 -0
  102. package/src/lib/server/quote-proofs.js +500 -0
  103. package/src/lib/server/quote-proofs.js.map +1 -0
  104. package/src/lib/server/quote-uploads.d.ts +33 -0
  105. package/src/lib/server/quote-uploads.js +29 -0
  106. package/src/lib/server/quote-uploads.js.map +1 -0
  107. package/src/lib/server/quote.d.ts +63 -0
  108. package/src/lib/server/quote.js +846 -0
  109. package/src/lib/server/quote.js.map +1 -0
  110. package/src/lib/server/related.js +2 -0
  111. package/src/lib/server/related.js.map +1 -1
  112. package/src/lib/server/site-image-source.d.ts +38 -0
  113. package/src/lib/server/site-image-source.js +130 -0
  114. package/src/lib/server/site-image-source.js.map +1 -0
  115. package/src/lib/server/site-page-resolver.d.ts +2 -0
  116. package/src/lib/server/site-page-resolver.js +75 -0
  117. package/src/lib/server/site-page-resolver.js.map +1 -1
  118. package/src/lib/server.js +33 -1
  119. package/src/lib/server.js.map +1 -1
  120. package/src/lib/site.js +6 -0
  121. package/src/lib/site.js.map +1 -1
  122. package/src/lib/transfer/tracking.server.js +6 -0
  123. package/src/lib/transfer/tracking.server.js.map +1 -1
  124. package/src/lib/utils/commerce-document-pdf.d.ts +77 -0
  125. package/src/lib/utils/commerce-document-pdf.js +608 -0
  126. package/src/lib/utils/commerce-document-pdf.js.map +1 -0
  127. package/src/lib/utils/order-invoice.d.ts +52 -3
  128. package/src/lib/utils/order-invoice.js +116 -64
  129. package/src/lib/utils/order-invoice.js.map +1 -1
@@ -0,0 +1,436 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { jsx as _jsx, jsxs as _jsxs } 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 { checkVisitorUploadSelection, describeVisitorUploadTypes, formatVisitorUploadBytes, VISITOR_UPLOAD_ACCEPT, VISITOR_UPLOAD_HONEYPOT_FIELD, VISITOR_UPLOAD_MAX_BYTES, VISITOR_UPLOAD_MAX_FILES } from "@aglyn/aglyn/app-utils/visitor-upload";
19
+ import { sendVisitorUpload } from "@aglyn/aglyn/app-utils/visitor-upload-client";
20
+ import Alert from "@mui/material/Alert";
21
+ import Box from "@mui/material/Box";
22
+ import Button from "@mui/material/Button";
23
+ import Chip from "@mui/material/Chip";
24
+ import Paper from "@mui/material/Paper";
25
+ import Stack from "@mui/material/Stack";
26
+ import TextField from "@mui/material/TextField";
27
+ import Typography from "@mui/material/Typography";
28
+ import { useCallback, useRef, useState } from "react";
29
+ function dateLabel(atMs) {
30
+ return new Date(atMs).toLocaleDateString(undefined, {
31
+ month: 'short',
32
+ day: 'numeric',
33
+ year: 'numeric'
34
+ });
35
+ }
36
+ const newKey = ()=>{
37
+ var _ref;
38
+ var _globalThis_crypto_randomUUID, _globalThis_crypto;
39
+ return (_ref = (_globalThis_crypto = globalThis.crypto) == null ? void 0 : (_globalThis_crypto_randomUUID = _globalThis_crypto.randomUUID) == null ? void 0 : _globalThis_crypto_randomUUID.call(_globalThis_crypto)) != null ? _ref : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
40
+ };
41
+ /**
42
+ * The quote's proofs on the customer's page (AGL-4096): each image shown,
43
+ * every other file a download, and while the quote is open for an answer,
44
+ * "Approve this proof" (under a typed name) and "Request changes" (a comment
45
+ * and any artwork). The latest answer is the one that counts, so a customer
46
+ * who asked for changes can still approve, and the panel says what they last
47
+ * said. A paid quote shows its proofs and nothing to press.
48
+ */ export function QuoteProofPanel(props) {
49
+ const { view, hostId, quoteId, token, siteFetch, onView, onReload, onReplaced } = props;
50
+ const [mode, setMode] = useState('idle');
51
+ const [name, setName] = useState('');
52
+ const [comment, setComment] = useState('');
53
+ const [files, setFiles] = useState([]);
54
+ const [uploading, setUploading] = useState(null);
55
+ const [sending, setSending] = useState(false);
56
+ const [error, setError] = useState('');
57
+ // Whatever a bot types into the hidden field, sent as typed.
58
+ const [honeypot, setHoneypot] = useState('');
59
+ const picker = useRef(null);
60
+ const attempt = useRef('');
61
+ const link = `hostId=${encodeURIComponent(hostId)}&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`;
62
+ const proofHref = (id)=>`/api/commerce/quote-proof?${link}&file=${encodeURIComponent(id)}`;
63
+ const business = view.storeName || 'the business';
64
+ const post = useCallback(async (path, body, headers = {})=>{
65
+ const response = await siteFetch(path, {
66
+ method: 'POST',
67
+ headers: _extends({
68
+ 'Content-Type': 'application/json'
69
+ }, headers),
70
+ body: JSON.stringify(_extends({
71
+ hostId,
72
+ q: quoteId,
73
+ t: token
74
+ }, body))
75
+ });
76
+ return {
77
+ response,
78
+ payload: await response.json().catch(()=>({}))
79
+ };
80
+ }, [
81
+ siteFetch,
82
+ hostId,
83
+ quoteId,
84
+ token
85
+ ]);
86
+ const attach = useCallback(async (picked)=>{
87
+ setError('');
88
+ const problem = checkVisitorUploadSelection(picked, files.length);
89
+ if (problem) return void setError(problem);
90
+ setUploading({
91
+ done: 0,
92
+ total: picked.length
93
+ });
94
+ try {
95
+ for (const [index, file] of picked.entries()){
96
+ const sent = await sendVisitorUpload({
97
+ file,
98
+ requestTicket: async (request)=>{
99
+ var _payload_error;
100
+ const { response, payload } = await post('/api/commerce/quote-upload', {
101
+ action: 'ticket',
102
+ file: request,
103
+ [VISITOR_UPLOAD_HONEYPOT_FIELD]: honeypot
104
+ });
105
+ return response.ok && payload['ticket'] ? payload : {
106
+ error: String((_payload_error = payload['error']) != null ? _payload_error : 'The file could not be sent. Try again.')
107
+ };
108
+ },
109
+ finalize: async (ticket)=>{
110
+ var _payload_error;
111
+ const { response, payload } = await post('/api/commerce/quote-upload', {
112
+ action: 'finalize',
113
+ ticket
114
+ });
115
+ return response.ok && payload['file'] ? {
116
+ file: payload['file']
117
+ } : {
118
+ error: String((_payload_error = payload['error']) != null ? _payload_error : 'The file could not be sent. Try again.')
119
+ };
120
+ }
121
+ });
122
+ if ('error' in sent) {
123
+ setError(sent.error);
124
+ break;
125
+ }
126
+ setFiles((prev)=>[
127
+ ...prev,
128
+ sent.file
129
+ ]);
130
+ setUploading({
131
+ done: index + 1,
132
+ total: picked.length
133
+ });
134
+ }
135
+ } finally{
136
+ setUploading(null);
137
+ }
138
+ }, [
139
+ files.length,
140
+ post,
141
+ honeypot
142
+ ]);
143
+ const respond = useCallback(async ()=>{
144
+ if (sending) return;
145
+ setError('');
146
+ if (mode === 'approve' && name.trim().length < 2) return void setError('Type your name to approve the proof.');
147
+ if (mode === 'changes' && !comment.trim()) return void setError('Tell us what to change.');
148
+ setSending(true);
149
+ // One key per answer: a retry of the same press is answered from the first.
150
+ if (!attempt.current) attempt.current = newKey();
151
+ try {
152
+ var _payload_error;
153
+ const { response, payload } = await post('/api/commerce/quote-respond', _extends({
154
+ v: view.version,
155
+ action: mode === 'approve' ? 'approve' : 'changes'
156
+ }, mode === 'approve' ? {
157
+ name: name.trim()
158
+ } : {
159
+ comment: comment.trim(),
160
+ fileIds: files.map((file)=>file.id)
161
+ }, {
162
+ [VISITOR_UPLOAD_HONEYPOT_FIELD]: honeypot
163
+ }), {
164
+ 'Idempotency-Key': attempt.current
165
+ });
166
+ attempt.current = '';
167
+ if (response.ok && payload['view']) {
168
+ setMode('idle');
169
+ setName('');
170
+ setComment('');
171
+ setFiles([]);
172
+ onView(payload['view']);
173
+ return;
174
+ }
175
+ if (payload['replaced']) return onReplaced();
176
+ if (payload['reason'] === 'updated' || payload['reason'] === 'paid') onReload();
177
+ setError(String((_payload_error = payload['error']) != null ? _payload_error : 'Your answer could not be sent. Try again.'));
178
+ } catch (unused) {
179
+ setError('Your answer could not be sent. Check your connection and try again.');
180
+ } finally{
181
+ setSending(false);
182
+ }
183
+ }, [
184
+ sending,
185
+ mode,
186
+ name,
187
+ comment,
188
+ files,
189
+ view.version,
190
+ honeypot,
191
+ post,
192
+ onView,
193
+ onReload,
194
+ onReplaced
195
+ ]);
196
+ if (!view.proofs.length) return null;
197
+ const response = view.response;
198
+ return /*#__PURE__*/ _jsx(Paper, {
199
+ variant: "outlined",
200
+ sx: {
201
+ p: {
202
+ xs: 2,
203
+ sm: 3
204
+ }
205
+ },
206
+ children: /*#__PURE__*/ _jsxs(Stack, {
207
+ spacing: 2,
208
+ children: [
209
+ /*#__PURE__*/ _jsxs(Stack, {
210
+ spacing: 0.5,
211
+ children: [
212
+ /*#__PURE__*/ _jsx(Typography, {
213
+ variant: "h6",
214
+ component: "h2",
215
+ children: view.proofs.length === 1 ? 'Your proof' : 'Your proofs'
216
+ }),
217
+ /*#__PURE__*/ _jsx(Typography, {
218
+ variant: "body2",
219
+ color: "text.secondary",
220
+ children: view.status === 'unpaid' ? `Revision ${view.revision}. Look it over, then approve it or tell ${business} what to change.` : `Revision ${view.revision}.`
221
+ })
222
+ ]
223
+ }),
224
+ /*#__PURE__*/ _jsx(Stack, {
225
+ spacing: 1.5,
226
+ children: view.proofs.map((proof)=>proof.inline ? /*#__PURE__*/ _jsxs(Stack, {
227
+ spacing: 0.5,
228
+ children: [
229
+ /*#__PURE__*/ _jsx(Box, {
230
+ component: "img",
231
+ src: proofHref(proof.id),
232
+ alt: proof.name,
233
+ loading: "lazy",
234
+ sx: {
235
+ display: 'block',
236
+ maxWidth: 1,
237
+ height: 'auto',
238
+ borderRadius: 1,
239
+ border: 1,
240
+ borderColor: 'divider'
241
+ }
242
+ }),
243
+ /*#__PURE__*/ _jsx(Typography, {
244
+ variant: "caption",
245
+ color: "text.secondary",
246
+ children: proof.name
247
+ })
248
+ ]
249
+ }, proof.id) : /*#__PURE__*/ _jsx(Box, {
250
+ children: /*#__PURE__*/ _jsx(Button, {
251
+ variant: "outlined",
252
+ size: "small",
253
+ href: proofHref(proof.id),
254
+ download: proof.name,
255
+ children: `Download ${proof.name} (${formatVisitorUploadBytes(proof.size)})`
256
+ })
257
+ }, proof.id))
258
+ }),
259
+ response ? response.action === 'approve' ? /*#__PURE__*/ _jsx(Alert, {
260
+ severity: "success",
261
+ children: `You approved this proof on ${dateLabel(response.atMs)}${response.name ? ` as ${response.name}` : ''}.`
262
+ }) : /*#__PURE__*/ _jsx(Alert, {
263
+ severity: "info",
264
+ children: `You asked for changes on ${dateLabel(response.atMs)}. ${business.charAt(0).toUpperCase()}${business.slice(1)} will send you a new proof.`
265
+ }) : null,
266
+ view.respondable ? /*#__PURE__*/ _jsxs(Stack, {
267
+ spacing: 2,
268
+ children: [
269
+ /*#__PURE__*/ _jsx(Box, {
270
+ component: "input",
271
+ type: "text",
272
+ name: VISITOR_UPLOAD_HONEYPOT_FIELD,
273
+ tabIndex: -1,
274
+ autoComplete: "off",
275
+ "aria-hidden": "true",
276
+ value: honeypot,
277
+ onChange: (event)=>setHoneypot(event.target.value),
278
+ sx: {
279
+ position: 'absolute',
280
+ left: '-100vw',
281
+ width: 0,
282
+ height: 0,
283
+ opacity: 0
284
+ }
285
+ }),
286
+ mode === 'idle' ? /*#__PURE__*/ _jsxs(Stack, {
287
+ direction: {
288
+ xs: 'column',
289
+ sm: 'row'
290
+ },
291
+ spacing: 1,
292
+ children: [
293
+ (response == null ? void 0 : response.action) !== 'approve' ? /*#__PURE__*/ _jsx(Button, {
294
+ variant: "contained",
295
+ onClick: ()=>setMode('approve'),
296
+ children: 'Approve this proof'
297
+ }) : null,
298
+ /*#__PURE__*/ _jsx(Button, {
299
+ variant: (response == null ? void 0 : response.action) === 'approve' ? 'outlined' : 'text',
300
+ onClick: ()=>setMode('changes'),
301
+ children: 'Request changes'
302
+ })
303
+ ]
304
+ }) : mode === 'approve' ? /*#__PURE__*/ _jsxs(Stack, {
305
+ spacing: 1.5,
306
+ children: [
307
+ /*#__PURE__*/ _jsx(Typography, {
308
+ variant: "body2",
309
+ children: `Type your name to approve revision ${view.revision}. ${business.charAt(0).toUpperCase()}${business.slice(1)} keeps your name and the time as the record of your approval.`
310
+ }),
311
+ /*#__PURE__*/ _jsx(TextField, {
312
+ label: "Your name",
313
+ value: name,
314
+ autoComplete: "name",
315
+ onChange: (event)=>setName(event.target.value),
316
+ slotProps: {
317
+ htmlInput: {
318
+ maxLength: 120
319
+ }
320
+ }
321
+ }),
322
+ /*#__PURE__*/ _jsxs(Stack, {
323
+ direction: "row",
324
+ spacing: 1,
325
+ children: [
326
+ /*#__PURE__*/ _jsx(Button, {
327
+ variant: "contained",
328
+ disabled: sending,
329
+ onClick: ()=>void respond(),
330
+ children: sending ? 'Approving…' : 'Approve'
331
+ }),
332
+ /*#__PURE__*/ _jsx(Button, {
333
+ disabled: sending,
334
+ onClick: ()=>setMode('idle'),
335
+ children: 'Cancel'
336
+ })
337
+ ]
338
+ })
339
+ ]
340
+ }) : /*#__PURE__*/ _jsxs(Stack, {
341
+ spacing: 1.5,
342
+ children: [
343
+ /*#__PURE__*/ _jsx(TextField, {
344
+ label: "What should change?",
345
+ value: comment,
346
+ multiline: true,
347
+ minRows: 3,
348
+ required: true,
349
+ onChange: (event)=>setComment(event.target.value),
350
+ slotProps: {
351
+ htmlInput: {
352
+ maxLength: 5000
353
+ }
354
+ }
355
+ }),
356
+ /*#__PURE__*/ _jsx("input", {
357
+ ref: picker,
358
+ type: "file",
359
+ multiple: true,
360
+ hidden: true,
361
+ accept: VISITOR_UPLOAD_ACCEPT,
362
+ "data-testid": "quote-artwork-picker",
363
+ onChange: (event)=>{
364
+ var _event_target_files;
365
+ const picked = Array.from((_event_target_files = event.target.files) != null ? _event_target_files : []);
366
+ event.target.value = '';
367
+ if (picked.length) void attach(picked);
368
+ }
369
+ }),
370
+ files.length ? /*#__PURE__*/ _jsx(Stack, {
371
+ direction: "row",
372
+ spacing: 1,
373
+ useFlexGap: true,
374
+ sx: {
375
+ flexWrap: 'wrap'
376
+ },
377
+ children: files.map((file)=>/*#__PURE__*/ _jsx(Chip, {
378
+ label: `${file.name} · ${formatVisitorUploadBytes(file.size)}`,
379
+ onDelete: sending ? undefined : ()=>setFiles((prev)=>prev.filter((entry)=>entry.id !== file.id))
380
+ }, file.id))
381
+ }) : null,
382
+ /*#__PURE__*/ _jsxs(Box, {
383
+ children: [
384
+ /*#__PURE__*/ _jsx(Button, {
385
+ size: "small",
386
+ variant: "outlined",
387
+ disabled: sending || Boolean(uploading) || files.length >= VISITOR_UPLOAD_MAX_FILES,
388
+ onClick: ()=>{
389
+ var _picker_current;
390
+ return (_picker_current = picker.current) == null ? void 0 : _picker_current.click();
391
+ },
392
+ children: uploading ? `Sending ${uploading.done + 1} of ${uploading.total}…` : 'Attach artwork'
393
+ }),
394
+ /*#__PURE__*/ _jsx(Typography, {
395
+ variant: "caption",
396
+ color: "text.secondary",
397
+ component: "p",
398
+ sx: {
399
+ mt: 0.5
400
+ },
401
+ children: `Optional. ${describeVisitorUploadTypes()}, up to ${VISITOR_UPLOAD_MAX_FILES} files of ${formatVisitorUploadBytes(VISITOR_UPLOAD_MAX_BYTES)} each.`
402
+ })
403
+ ]
404
+ }),
405
+ /*#__PURE__*/ _jsxs(Stack, {
406
+ direction: "row",
407
+ spacing: 1,
408
+ children: [
409
+ /*#__PURE__*/ _jsx(Button, {
410
+ variant: "contained",
411
+ disabled: sending || Boolean(uploading),
412
+ onClick: ()=>void respond(),
413
+ children: sending ? 'Sending…' : 'Send changes'
414
+ }),
415
+ /*#__PURE__*/ _jsx(Button, {
416
+ disabled: sending,
417
+ onClick: ()=>setMode('idle'),
418
+ children: 'Cancel'
419
+ })
420
+ ]
421
+ })
422
+ ]
423
+ }),
424
+ error ? /*#__PURE__*/ _jsx(Alert, {
425
+ severity: "error",
426
+ children: error
427
+ }) : null
428
+ ]
429
+ }) : null
430
+ ]
431
+ })
432
+ });
433
+ }
434
+ export default QuoteProofPanel;
435
+
436
+ //# sourceMappingURL=quote-proof-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/quote-proof-panel.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 {\n checkVisitorUploadSelection,\n describeVisitorUploadTypes,\n formatVisitorUploadBytes,\n VISITOR_UPLOAD_ACCEPT,\n VISITOR_UPLOAD_HONEYPOT_FIELD,\n VISITOR_UPLOAD_MAX_BYTES,\n VISITOR_UPLOAD_MAX_FILES,\n type VisitorUploadFileView,\n} from '@aglyn/aglyn/app-utils/visitor-upload'\nimport { sendVisitorUpload } from '@aglyn/aglyn/app-utils/visitor-upload-client'\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 Paper from '@mui/material/Paper'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { useCallback, useRef, useState, type ChangeEvent } from 'react'\nimport type { QuotePageView } from '../model'\n\n/** The page's own fetch: the site's API, with the site's preview rules. */\ntype SiteFetch = (input: string, init?: RequestInit) => Promise<Response>\n\nexport interface QuoteProofPanelProps {\n view: QuotePageView\n hostId: string\n quoteId: string\n token: string\n siteFetch: SiteFetch\n /** The quote as the server answered after a response, or after it changed. */\n onView: (view: QuotePageView) => void\n /** Reload the quote: it changed since the page loaded. */\n onReload: () => void\n /** The link was replaced. */\n onReplaced: () => void\n}\n\nfunction dateLabel(atMs: number): string {\n return new Date(atMs).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nconst newKey = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`\n\n/**\n * The quote's proofs on the customer's page (AGL-4096): each image shown,\n * every other file a download, and while the quote is open for an answer,\n * \"Approve this proof\" (under a typed name) and \"Request changes\" (a comment\n * and any artwork). The latest answer is the one that counts, so a customer\n * who asked for changes can still approve, and the panel says what they last\n * said. A paid quote shows its proofs and nothing to press.\n */\nexport function QuoteProofPanel(props: QuoteProofPanelProps) {\n const { view, hostId, quoteId, token, siteFetch, onView, onReload, onReplaced } = props\n const [mode, setMode] = useState<'idle' | 'approve' | 'changes'>('idle')\n const [name, setName] = useState('')\n const [comment, setComment] = useState('')\n const [files, setFiles] = useState<VisitorUploadFileView[]>([])\n const [uploading, setUploading] = useState<{ done: number; total: number } | null>(null)\n const [sending, setSending] = useState(false)\n const [error, setError] = useState('')\n // Whatever a bot types into the hidden field, sent as typed.\n const [honeypot, setHoneypot] = useState('')\n const picker = useRef<HTMLInputElement>(null)\n const attempt = useRef('')\n\n const link = `hostId=${encodeURIComponent(hostId)}&q=${encodeURIComponent(quoteId)}&t=${encodeURIComponent(token)}`\n const proofHref = (id: string) => `/api/commerce/quote-proof?${link}&file=${encodeURIComponent(id)}`\n const business = view.storeName || 'the business'\n\n const post = useCallback(\n async (path: string, body: Record<string, unknown>, headers: Record<string, string> = {}) => {\n const response = await siteFetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify({ hostId, q: quoteId, t: token, ...body }),\n })\n return { response, payload: (await response.json().catch(() => ({}))) as Record<string, any> }\n },\n [siteFetch, hostId, quoteId, token],\n )\n\n const attach = useCallback(\n async (picked: File[]) => {\n setError('')\n const problem = checkVisitorUploadSelection(picked, files.length)\n if (problem) return void setError(problem)\n setUploading({ done: 0, total: picked.length })\n try {\n for (const [index, file] of picked.entries()) {\n const sent = await sendVisitorUpload({\n file,\n requestTicket: async (request) => {\n const { response, payload } = await post('/api/commerce/quote-upload', {\n action: 'ticket',\n file: request,\n [VISITOR_UPLOAD_HONEYPOT_FIELD]: honeypot,\n })\n return response.ok && payload['ticket']\n ? (payload as { ticket: string; upload: { url: string; fields: Record<string, string> } })\n : { error: String(payload['error'] ?? 'The file could not be sent. Try again.') }\n },\n finalize: async (ticket) => {\n const { response, payload } = await post('/api/commerce/quote-upload', { action: 'finalize', ticket })\n return response.ok && payload['file']\n ? { file: payload['file'] as VisitorUploadFileView }\n : { error: String(payload['error'] ?? 'The file could not be sent. Try again.') }\n },\n })\n if ('error' in sent) {\n setError(sent.error)\n break\n }\n setFiles((prev) => [...prev, sent.file])\n setUploading({ done: index + 1, total: picked.length })\n }\n } finally {\n setUploading(null)\n }\n },\n [files.length, post, honeypot],\n )\n\n const respond = useCallback(async () => {\n if (sending) return\n setError('')\n if (mode === 'approve' && name.trim().length < 2) return void setError('Type your name to approve the proof.')\n if (mode === 'changes' && !comment.trim()) return void setError('Tell us what to change.')\n setSending(true)\n // One key per answer: a retry of the same press is answered from the first.\n if (!attempt.current) attempt.current = newKey()\n try {\n const { response, payload } = await post(\n '/api/commerce/quote-respond',\n {\n v: view.version,\n action: mode === 'approve' ? 'approve' : 'changes',\n ...(mode === 'approve' ? { name: name.trim() } : { comment: comment.trim(), fileIds: files.map((file) => file.id) }),\n [VISITOR_UPLOAD_HONEYPOT_FIELD]: honeypot,\n },\n { 'Idempotency-Key': attempt.current },\n )\n attempt.current = ''\n if (response.ok && payload['view']) {\n setMode('idle')\n setName('')\n setComment('')\n setFiles([])\n onView(payload['view'] as QuotePageView)\n return\n }\n if (payload['replaced']) return onReplaced()\n if (payload['reason'] === 'updated' || payload['reason'] === 'paid') onReload()\n setError(String(payload['error'] ?? 'Your answer could not be sent. Try again.'))\n } catch {\n setError('Your answer could not be sent. Check your connection and try again.')\n } finally {\n setSending(false)\n }\n }, [sending, mode, name, comment, files, view.version, honeypot, post, onView, onReload, onReplaced])\n\n if (!view.proofs.length) return null\n const response = view.response\n\n return (\n <Paper variant=\"outlined\" sx={{ p: { xs: 2, sm: 3 } }}>\n <Stack spacing={2}>\n <Stack spacing={0.5}>\n <Typography variant=\"h6\" component=\"h2\">\n {view.proofs.length === 1 ? 'Your proof' : 'Your proofs'}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {view.status === 'unpaid'\n ? `Revision ${view.revision}. Look it over, then approve it or tell ${business} what to change.`\n : `Revision ${view.revision}.`}\n </Typography>\n </Stack>\n\n <Stack spacing={1.5}>\n {view.proofs.map((proof) =>\n proof.inline ? (\n <Stack key={proof.id} spacing={0.5}>\n <Box\n component=\"img\"\n src={proofHref(proof.id)}\n alt={proof.name}\n loading=\"lazy\"\n sx={{ display: 'block', maxWidth: 1, height: 'auto', borderRadius: 1, border: 1, borderColor: 'divider' }}\n />\n <Typography variant=\"caption\" color=\"text.secondary\">\n {proof.name}\n </Typography>\n </Stack>\n ) : (\n <Box key={proof.id}>\n <Button variant=\"outlined\" size=\"small\" href={proofHref(proof.id)} download={proof.name}>\n {`Download ${proof.name} (${formatVisitorUploadBytes(proof.size)})`}\n </Button>\n </Box>\n ),\n )}\n </Stack>\n\n {response ? (\n response.action === 'approve' ? (\n <Alert severity=\"success\">\n {`You approved this proof on ${dateLabel(response.atMs)}${response.name ? ` as ${response.name}` : ''}.`}\n </Alert>\n ) : (\n <Alert severity=\"info\">\n {`You asked for changes on ${dateLabel(response.atMs)}. ${business.charAt(0).toUpperCase()}${business.slice(1)} will send you a new proof.`}\n </Alert>\n )\n ) : null}\n\n {view.respondable ? (\n <Stack spacing={2}>\n {/* Honeypot: people never see or fill this. */}\n <Box\n component=\"input\"\n type=\"text\"\n name={VISITOR_UPLOAD_HONEYPOT_FIELD}\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={honeypot}\n onChange={(event: ChangeEvent<HTMLInputElement>) => setHoneypot(event.target.value)}\n sx={{ position: 'absolute', left: '-100vw', width: 0, height: 0, opacity: 0 }}\n />\n {mode === 'idle' ? (\n <Stack direction={{ xs: 'column', sm: 'row' }} spacing={1}>\n {response?.action !== 'approve' ? (\n <Button variant=\"contained\" onClick={() => setMode('approve')}>\n {'Approve this proof'}\n </Button>\n ) : null}\n <Button variant={response?.action === 'approve' ? 'outlined' : 'text'} onClick={() => setMode('changes')}>\n {'Request changes'}\n </Button>\n </Stack>\n ) : mode === 'approve' ? (\n <Stack spacing={1.5}>\n <Typography variant=\"body2\">\n {`Type your name to approve revision ${view.revision}. ${business.charAt(0).toUpperCase()}${business.slice(1)} keeps your name and the time as the record of your approval.`}\n </Typography>\n <TextField\n label=\"Your name\"\n value={name}\n autoComplete=\"name\"\n onChange={(event) => setName(event.target.value)}\n slotProps={{ htmlInput: { maxLength: 120 } }}\n />\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"contained\" disabled={sending} onClick={() => void respond()}>\n {sending ? 'Approving…' : 'Approve'}\n </Button>\n <Button disabled={sending} onClick={() => setMode('idle')}>\n {'Cancel'}\n </Button>\n </Stack>\n </Stack>\n ) : (\n <Stack spacing={1.5}>\n <TextField\n label=\"What should change?\"\n value={comment}\n multiline\n minRows={3}\n required\n onChange={(event) => setComment(event.target.value)}\n slotProps={{ htmlInput: { maxLength: 5000 } }}\n />\n <input\n ref={picker}\n type=\"file\"\n multiple\n hidden\n accept={VISITOR_UPLOAD_ACCEPT}\n data-testid=\"quote-artwork-picker\"\n onChange={(event) => {\n const picked = Array.from(event.target.files ?? [])\n event.target.value = ''\n if (picked.length) void attach(picked)\n }}\n />\n {files.length ? (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {files.map((file) => (\n <Chip\n key={file.id}\n label={`${file.name} · ${formatVisitorUploadBytes(file.size)}`}\n onDelete={sending ? undefined : () => setFiles((prev) => prev.filter((entry) => entry.id !== file.id))}\n />\n ))}\n </Stack>\n ) : null}\n <Box>\n <Button\n size=\"small\"\n variant=\"outlined\"\n disabled={sending || Boolean(uploading) || files.length >= VISITOR_UPLOAD_MAX_FILES}\n onClick={() => picker.current?.click()}\n >\n {uploading ? `Sending ${uploading.done + 1} of ${uploading.total}…` : 'Attach artwork'}\n </Button>\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" sx={{ mt: 0.5 }}>\n {`Optional. ${describeVisitorUploadTypes()}, up to ${VISITOR_UPLOAD_MAX_FILES} files of ${formatVisitorUploadBytes(VISITOR_UPLOAD_MAX_BYTES)} each.`}\n </Typography>\n </Box>\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"contained\" disabled={sending || Boolean(uploading)} onClick={() => void respond()}>\n {sending ? 'Sending…' : 'Send changes'}\n </Button>\n <Button disabled={sending} onClick={() => setMode('idle')}>\n {'Cancel'}\n </Button>\n </Stack>\n </Stack>\n )}\n {error ? <Alert severity=\"error\">{error}</Alert> : null}\n </Stack>\n ) : null}\n </Stack>\n </Paper>\n )\n}\n\nexport default QuoteProofPanel\n"],"names":["checkVisitorUploadSelection","describeVisitorUploadTypes","formatVisitorUploadBytes","VISITOR_UPLOAD_ACCEPT","VISITOR_UPLOAD_HONEYPOT_FIELD","VISITOR_UPLOAD_MAX_BYTES","VISITOR_UPLOAD_MAX_FILES","sendVisitorUpload","Alert","Box","Button","Chip","Paper","Stack","TextField","Typography","useCallback","useRef","useState","dateLabel","atMs","Date","toLocaleDateString","undefined","month","day","year","newKey","globalThis","crypto","randomUUID","now","Math","random","toString","slice","QuoteProofPanel","props","view","hostId","quoteId","token","siteFetch","onView","onReload","onReplaced","mode","setMode","name","setName","comment","setComment","files","setFiles","uploading","setUploading","sending","setSending","error","setError","honeypot","setHoneypot","picker","attempt","link","encodeURIComponent","proofHref","id","business","storeName","post","path","body","headers","response","method","JSON","stringify","q","t","payload","json","catch","attach","picked","problem","length","done","total","index","file","entries","sent","requestTicket","request","action","ok","String","finalize","ticket","prev","respond","trim","current","v","version","fileIds","map","proofs","variant","sx","p","xs","sm","spacing","component","color","status","revision","proof","inline","src","alt","loading","display","maxWidth","height","borderRadius","border","borderColor","size","href","download","severity","charAt","toUpperCase","respondable","type","tabIndex","autoComplete","aria-hidden","value","onChange","event","target","position","left","width","opacity","direction","onClick","label","slotProps","htmlInput","maxLength","disabled","multiline","minRows","required","input","ref","multiple","hidden","accept","data-testid","Array","from","useFlexGap","flexWrap","onDelete","filter","entry","Boolean","click","mt"],"mappings":"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"}
@@ -14,6 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ import type { StripeCheckoutContact } from '@stripe/stripe-js';
17
18
  import type { StorefrontCheckoutWallets } from '../model/commerce-payment-methods';
18
19
  /**
19
20
  * The storefront Payment Element (AGL-1944) — the shopper pays on the
@@ -118,10 +119,15 @@ export interface StorefrontPaymentElementProps {
118
119
  * Absent means every wallet the device supports shows.
119
120
  */
120
121
  wallets?: StorefrontCheckoutWallets;
122
+ /**
123
+ * An address the shipping fields start with, where the session asks for
124
+ * one: a quote's ship-to (AGL-4094). The shopper can still change it.
125
+ */
126
+ defaultShippingAddress?: StripeCheckoutContact;
121
127
  }
122
128
  /** Test seam: `loadStripe` caches per key across a file's tests otherwise. */
123
129
  export declare function __resetStripePromises(): void;
124
- export declare function StorefrontPaymentElement({ clientSecret, publishableKey, payLabel, defaultEmail, onCancel, onRestart, wallets, }: StorefrontPaymentElementProps): import("react").JSX.Element;
130
+ export declare function StorefrontPaymentElement({ clientSecret, publishableKey, payLabel, defaultEmail, onCancel, onRestart, wallets, defaultShippingAddress, }: StorefrontPaymentElementProps): import("react").JSX.Element;
125
131
  /**
126
132
  * Re-exported so the old import path still resolves, but the definition now
127
133
  * lives in its own module (AGL-2486): a fallback imported FROM the lazily
@@ -14,6 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
17
18
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
19
  // The `/checkout` entry, not the main one: react-stripe-js v6 moved the
19
20
  // Checkout Sessions provider, its hook and its own `PaymentElement` there, and
@@ -430,7 +431,7 @@ function PaymentForm({ payLabel, defaultEmail, onCancel, onRestart, wallets }) {
430
431
  ]
431
432
  });
432
433
  }
433
- export function StorefrontPaymentElement({ clientSecret, publishableKey, payLabel, defaultEmail, onCancel, onRestart, wallets }) {
434
+ export function StorefrontPaymentElement({ clientSecret, publishableKey, payLabel, defaultEmail, onCancel, onRestart, wallets, defaultShippingAddress }) {
434
435
  const stripe = useMemo(()=>getStripe(publishableKey), [
435
436
  publishableKey
436
437
  ]);
@@ -440,13 +441,17 @@ export function StorefrontPaymentElement({ clientSecret, publishableKey, payLabe
440
441
  // suggest a re-theme that never happens.
441
442
  const options = useMemo(()=>{
442
443
  var _theme_typography;
443
- return {
444
+ return _extends({
444
445
  clientSecret,
445
446
  elementsOptions: {
446
447
  appearance: storefrontPaymentAppearance(theme),
447
448
  fonts: storefrontPaymentFonts(typeof ((_theme_typography = theme.typography) == null ? void 0 : _theme_typography.fontFamily) === 'string' ? theme.typography.fontFamily : undefined)
448
449
  }
449
- };
450
+ }, defaultShippingAddress ? {
451
+ defaultValues: {
452
+ shippingAddress: defaultShippingAddress
453
+ }
454
+ } : {});
450
455
  }, // eslint-disable-next-line react-hooks/exhaustive-deps
451
456
  [
452
457
  clientSecret