@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.
- package/README.md +2 -2
- package/package.json +13 -13
- package/src/lib/components/commerce-console-page.js +29 -2
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/commerce-analytics-card.component.js +4 -2
- package/src/lib/components/console/commerce-analytics-card.component.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.js +5 -1
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/host-quotes-card.component.d.ts +34 -0
- package/src/lib/components/console/host-quotes-card.component.js +263 -0
- package/src/lib/components/console/host-quotes-card.component.js.map +1 -0
- package/src/lib/components/console/order-invoice.component.d.ts +6 -4
- package/src/lib/components/console/order-invoice.component.js +67 -11
- package/src/lib/components/console/order-invoice.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +33 -28
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
- package/src/lib/components/console/quote-editor-dialog.component.d.ts +45 -0
- package/src/lib/components/console/quote-editor-dialog.component.js +1317 -0
- package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -0
- package/src/lib/components/console/quote-pay-link.component.d.ts +38 -0
- package/src/lib/components/console/quote-pay-link.component.js +213 -0
- package/src/lib/components/console/quote-pay-link.component.js.map +1 -0
- package/src/lib/components/console/quote-proofs.component.d.ts +37 -0
- package/src/lib/components/console/quote-proofs.component.js +626 -0
- package/src/lib/components/console/quote-proofs.component.js.map +1 -0
- package/src/lib/components/console/quote-settings-card.component.d.ts +29 -0
- package/src/lib/components/console/quote-settings-card.component.js +121 -0
- package/src/lib/components/console/quote-settings-card.component.js.map +1 -0
- package/src/lib/components/console/tax-settings-card.component.js +4 -1
- package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
- package/src/lib/components/quote-page-body.d.ts +33 -0
- package/src/lib/components/quote-page-body.js +724 -0
- package/src/lib/components/quote-page-body.js.map +1 -0
- package/src/lib/components/quote-page.d.ts +29 -0
- package/src/lib/components/quote-page.js +96 -0
- package/src/lib/components/quote-page.js.map +1 -0
- 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/components/storefront-payment-element.d.ts +7 -1
- package/src/lib/components/storefront-payment-element.js +8 -3
- package/src/lib/components/storefront-payment-element.js.map +1 -1
- package/src/lib/constants/orders-list-query.js +6 -1
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/quote-page.d.ts +30 -0
- package/src/lib/constants/quote-page.js +35 -0
- package/src/lib/constants/quote-page.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +25 -2
- package/src/lib/model/commerce-orders.js +10 -1
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-quote-pay.d.ts +256 -0
- package/src/lib/model/commerce-quote-pay.js +426 -0
- package/src/lib/model/commerce-quote-pay.js.map +1 -0
- 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-quotes.d.ts +335 -0
- package/src/lib/model/commerce-quotes.js +522 -0
- package/src/lib/model/commerce-quotes.js.map +1 -0
- package/src/lib/model/index.d.ts +3 -0
- package/src/lib/model/index.js +3 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/plugin-permissions.d.ts +1 -1
- package/src/lib/model/plugin-permissions.js +20 -0
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/server/api-v1/orders-and-products.js +6 -2
- package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
- package/src/lib/server/billing-webhook.js +127 -52
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/checkout-session-expiry.d.ts +36 -0
- package/src/lib/server/checkout-session-expiry.js +63 -0
- package/src/lib/server/checkout-session-expiry.js.map +1 -0
- package/src/lib/server/commerce-pdf.d.ts +100 -0
- package/src/lib/server/commerce-pdf.js +283 -0
- package/src/lib/server/commerce-pdf.js.map +1 -0
- package/src/lib/server/draft-order.js +16 -8
- package/src/lib/server/draft-order.js.map +1 -1
- 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/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 +7 -0
- package/src/lib/server/person-eraser.js +24 -2
- 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/pos-return.js +3 -1
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/quote-link-token.d.ts +39 -0
- package/src/lib/server/quote-link-token.js +97 -0
- package/src/lib/server/quote-link-token.js.map +1 -0
- package/src/lib/server/quote-pay.d.ts +110 -0
- package/src/lib/server/quote-pay.js +606 -0
- package/src/lib/server/quote-pay.js.map +1 -0
- 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 +63 -0
- package/src/lib/server/quote.js +846 -0
- package/src/lib/server/quote.js.map +1 -0
- package/src/lib/server/related.js +2 -0
- package/src/lib/server/related.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.d.ts +2 -0
- package/src/lib/server/site-page-resolver.js +75 -0
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server.js +33 -1
- package/src/lib/server.js.map +1 -1
- package/src/lib/site.js +6 -0
- package/src/lib/site.js.map +1 -1
- package/src/lib/transfer/tracking.server.js +6 -0
- package/src/lib/transfer/tracking.server.js.map +1 -1
- package/src/lib/utils/commerce-document-pdf.d.ts +77 -0
- package/src/lib/utils/commerce-document-pdf.js +608 -0
- package/src/lib/utils/commerce-document-pdf.js.map +1 -0
- package/src/lib/utils/order-invoice.d.ts +52 -3
- package/src/lib/utils/order-invoice.js +116 -64
- 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
|