@springmicro/cart 0.7.0 → 0.7.2
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/.eslintrc.cjs +21 -21
- package/README.md +64 -64
- package/dist/index.js +5456 -5353
- package/dist/index.umd.cjs +63 -63
- package/package.json +3 -3
- package/src/AddToCartForm.tsx +16 -16
- package/src/CartButton.tsx +27 -11
- package/src/ProductCard.css +106 -106
- package/src/ProductCard.tsx +6 -1
- package/src/checkout/ReviewCartAndCalculateTaxes.css +93 -93
- package/src/checkout/ReviewCartAndCalculateTaxes.tsx +187 -81
- package/src/checkout/components/AddCard.tsx +9 -5
- package/src/checkout/components/Address.tsx +1 -1
- package/src/checkout/components/CartList.tsx +2 -2
- package/src/checkout/components/CartProductCard.css +67 -67
- package/src/checkout/components/CartProductCard.tsx +0 -0
- package/src/checkout/components/Invoice.tsx +145 -145
- package/src/checkout/components/ProviderLogos.tsx +93 -93
- package/src/checkout/components/StatusBar.tsx +0 -0
- package/src/checkout/index.tsx +19 -10
- package/src/index.css +5 -5
- package/src/index.ts +0 -0
- package/src/types.d.ts +58 -56
- package/src/utils/api.ts +67 -67
- package/src/utils/cartAuthHandler.ts +50 -50
- package/src/utils/index.ts +0 -0
- package/src/utils/storage.ts +31 -11
- package/tsconfig.json +24 -24
- package/tsconfig.node.json +11 -11
- package/vite.config.ts +25 -25
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import "./ReviewCartAndCalculateTaxes.css";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
useTheme,
|
|
5
|
+
useMediaQuery,
|
|
6
|
+
Button,
|
|
7
|
+
TextField,
|
|
8
|
+
Modal,
|
|
9
|
+
Backdrop,
|
|
10
|
+
Fade,
|
|
11
|
+
Typography,
|
|
12
|
+
IconButton,
|
|
13
|
+
} from "@mui/material";
|
|
3
14
|
import { setOrder as cartSetOrder } from "../utils/storage";
|
|
4
15
|
import { AddCard, CCFocus, CreditCardValues } from "./components/AddCard";
|
|
5
16
|
import { CartList } from "./components/CartList";
|
|
@@ -25,6 +36,8 @@ import {
|
|
|
25
36
|
import { AddressValues } from "./components/Address";
|
|
26
37
|
import { useFormik } from "formik";
|
|
27
38
|
import { postCheckout } from "../utils/api";
|
|
39
|
+
import { CheckoutFieldsType } from ".";
|
|
40
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
28
41
|
|
|
29
42
|
async function createOrder(cart, apiBaseUrl, dev) {
|
|
30
43
|
dev && console.log("Creating order");
|
|
@@ -131,6 +144,7 @@ export default function ReviewAndCalculateTaxes({
|
|
|
131
144
|
CollectExtraInfo = undefined,
|
|
132
145
|
defaultValues = {},
|
|
133
146
|
dev,
|
|
147
|
+
hideFields = [],
|
|
134
148
|
}) {
|
|
135
149
|
dev && console.log({ products, prices });
|
|
136
150
|
const [formDisabled, setFormDisabled] = useState(true);
|
|
@@ -142,6 +156,8 @@ export default function ReviewAndCalculateTaxes({
|
|
|
142
156
|
const [tax, setTax] = taxState;
|
|
143
157
|
const [order, setOrder] = orderState;
|
|
144
158
|
|
|
159
|
+
const [precheckErrors, setPrecheckErrors] = useState([]);
|
|
160
|
+
|
|
145
161
|
async function createOrderAndGetTaxes(values) {
|
|
146
162
|
setFormError(undefined);
|
|
147
163
|
setFormDisabled(true);
|
|
@@ -188,11 +204,15 @@ export default function ReviewAndCalculateTaxes({
|
|
|
188
204
|
"stripe",
|
|
189
205
|
invoiceId
|
|
190
206
|
)
|
|
191
|
-
.then((data) => {
|
|
207
|
+
.then(async (data) => {
|
|
192
208
|
dev && console.log("Checkout submitted");
|
|
193
209
|
if (data instanceof Response) {
|
|
194
210
|
setFormError(true);
|
|
195
|
-
|
|
211
|
+
const { detail: errorData } = await data.json();
|
|
212
|
+
// dev && alert(data.statusText);
|
|
213
|
+
// console.log(errorData);
|
|
214
|
+
// TODO display issues
|
|
215
|
+
if (!errorData.valid) setPrecheckErrors(errorData.errors);
|
|
196
216
|
} else {
|
|
197
217
|
// success
|
|
198
218
|
setSuccessData(data);
|
|
@@ -360,64 +380,74 @@ export default function ReviewAndCalculateTaxes({
|
|
|
360
380
|
}, [formik.errors]);
|
|
361
381
|
|
|
362
382
|
return (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
>
|
|
374
|
-
<CartList
|
|
375
|
-
{...{
|
|
376
|
-
statusState: [status, setStatus],
|
|
377
|
-
cart,
|
|
378
|
-
subtotal,
|
|
379
|
-
tax,
|
|
380
|
-
shipping,
|
|
381
|
-
discount,
|
|
382
|
-
prices,
|
|
383
|
-
products,
|
|
384
|
-
disableMissingImage,
|
|
385
|
-
disableProductLink,
|
|
386
|
-
formik,
|
|
387
|
-
formDisabled,
|
|
388
|
-
formErrorState: [formError, setFormError],
|
|
383
|
+
<>
|
|
384
|
+
<Box
|
|
385
|
+
sx={{
|
|
386
|
+
mt: 2,
|
|
387
|
+
display: "flex",
|
|
388
|
+
flexDirection: { xs: "column", xl: "row" },
|
|
389
|
+
justifyContent: "center",
|
|
390
|
+
alignItems: { xs: undefined, xl: "flex-start" },
|
|
391
|
+
px: { xs: 32, xl: 16 },
|
|
392
|
+
"&>div": { width: { xs: undefined, xl: "50%" } },
|
|
389
393
|
}}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
394
|
+
>
|
|
395
|
+
<CartList
|
|
396
|
+
{...{
|
|
397
|
+
statusState: [status, setStatus],
|
|
398
|
+
cart,
|
|
399
|
+
subtotal,
|
|
400
|
+
tax,
|
|
401
|
+
shipping,
|
|
402
|
+
discount,
|
|
403
|
+
prices,
|
|
404
|
+
products,
|
|
405
|
+
disableMissingImage,
|
|
406
|
+
disableProductLink,
|
|
407
|
+
formik,
|
|
408
|
+
formDisabled,
|
|
409
|
+
formErrorState: [formError, setFormError],
|
|
410
|
+
}}
|
|
411
|
+
/>
|
|
412
|
+
{status === 0 && (
|
|
413
|
+
<Box
|
|
414
|
+
sx={{
|
|
415
|
+
flexGrow: 1,
|
|
416
|
+
display: "flex",
|
|
417
|
+
flexDirection: "column",
|
|
418
|
+
gap: 2,
|
|
411
419
|
}}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
420
|
+
>
|
|
421
|
+
{CollectExtraInfo && <CollectExtraInfo formik={formik} />}
|
|
422
|
+
<CheckoutActionFields
|
|
423
|
+
formik={formik}
|
|
424
|
+
prices={prices}
|
|
425
|
+
products={products}
|
|
426
|
+
hideFields={hideFields}
|
|
427
|
+
/>
|
|
428
|
+
<AddCard
|
|
429
|
+
cardRequired={cardRequired}
|
|
430
|
+
onSubmit={createOrderAndGetTaxes}
|
|
431
|
+
stacked={stacked}
|
|
432
|
+
formData={{
|
|
433
|
+
formik,
|
|
434
|
+
handleInputChange,
|
|
435
|
+
handleInputFocus,
|
|
436
|
+
formDisabled,
|
|
437
|
+
formError,
|
|
438
|
+
}}
|
|
439
|
+
hideFields={hideFields}
|
|
440
|
+
/>
|
|
441
|
+
</Box>
|
|
442
|
+
)}
|
|
443
|
+
</Box>
|
|
444
|
+
<PrecheckModal errors={precheckErrors} setErrors={setPrecheckErrors} />
|
|
445
|
+
</>
|
|
416
446
|
);
|
|
417
447
|
}
|
|
418
448
|
|
|
419
|
-
function CheckoutActionFields({ formik, products, prices }) {
|
|
420
|
-
const checkoutFields = [
|
|
449
|
+
function CheckoutActionFields({ formik, products, prices, hideFields = [] }) {
|
|
450
|
+
const checkoutFields: Record<string, CheckoutFieldsType> = [
|
|
421
451
|
...Object.keys(products).flatMap((productKey) =>
|
|
422
452
|
(products[productKey].actions ?? []).flatMap(
|
|
423
453
|
(action) => action.checkout_fields ?? []
|
|
@@ -447,33 +477,109 @@ function CheckoutActionFields({ formik, products, prices }) {
|
|
|
447
477
|
const handleInputChange = (e) => {
|
|
448
478
|
formik.handleChange(e);
|
|
449
479
|
};
|
|
450
|
-
|
|
480
|
+
// console.log({ checkoutFields });
|
|
451
481
|
return (
|
|
452
482
|
<Box sx={{ display: "flex", flexDirection: "column", mx: 3, gap: 2 }}>
|
|
453
|
-
{Object.keys(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
name
|
|
465
|
-
label
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
483
|
+
{Object.keys((console.log(checkoutFields), checkoutFields))
|
|
484
|
+
.filter(
|
|
485
|
+
(key) =>
|
|
486
|
+
!["email", ...hideFields].includes(key) &&
|
|
487
|
+
!(
|
|
488
|
+
checkoutFields[key].hidden === true ||
|
|
489
|
+
checkoutFields[key].hidden === "true"
|
|
490
|
+
)
|
|
491
|
+
)
|
|
492
|
+
.map((key) => {
|
|
493
|
+
const {
|
|
494
|
+
name,
|
|
495
|
+
label,
|
|
496
|
+
type = "string", // todo
|
|
497
|
+
required = true, // can be a string
|
|
498
|
+
} = checkoutFields[key];
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<TextField
|
|
502
|
+
fullWidth
|
|
503
|
+
name={name}
|
|
504
|
+
label={label}
|
|
505
|
+
required={required === true || required === "true"}
|
|
506
|
+
onBlur={formik.handleBlur}
|
|
507
|
+
onChange={handleInputChange}
|
|
508
|
+
onFocus={handleInputFocus}
|
|
509
|
+
variant="outlined"
|
|
510
|
+
value={formik.values[name]}
|
|
511
|
+
error={Boolean(formik.touched[name] && formik.errors[name])}
|
|
512
|
+
helperText={formik.touched[name] && formik.errors[name]}
|
|
513
|
+
/>
|
|
514
|
+
);
|
|
515
|
+
})}
|
|
477
516
|
</Box>
|
|
478
517
|
);
|
|
479
518
|
}
|
|
519
|
+
|
|
520
|
+
function PrecheckModal({ errors, setErrors }) {
|
|
521
|
+
function onClose() {
|
|
522
|
+
setErrors([]);
|
|
523
|
+
}
|
|
524
|
+
return (
|
|
525
|
+
<Modal
|
|
526
|
+
open={errors.length > 0}
|
|
527
|
+
onClose={onClose} // called when backdrop clicked or escape pressed
|
|
528
|
+
closeAfterTransition
|
|
529
|
+
slots={{ backdrop: Backdrop }}
|
|
530
|
+
slotProps={{
|
|
531
|
+
backdrop: {
|
|
532
|
+
timeout: 300,
|
|
533
|
+
},
|
|
534
|
+
}}
|
|
535
|
+
aria-labelledby="centered-modal-title"
|
|
536
|
+
aria-describedby="centered-modal-description"
|
|
537
|
+
>
|
|
538
|
+
<Fade in={errors.length > 0}>
|
|
539
|
+
<Box
|
|
540
|
+
sx={{
|
|
541
|
+
position: "absolute",
|
|
542
|
+
top: "50%",
|
|
543
|
+
left: "50%",
|
|
544
|
+
transform: "translate(-50%, -50%)",
|
|
545
|
+
minWidth: 300,
|
|
546
|
+
maxWidth: "90vw",
|
|
547
|
+
bgcolor: "background.paper",
|
|
548
|
+
boxShadow: 24,
|
|
549
|
+
borderRadius: 2,
|
|
550
|
+
p: 3,
|
|
551
|
+
outline: "none",
|
|
552
|
+
}}
|
|
553
|
+
>
|
|
554
|
+
<Box
|
|
555
|
+
sx={{
|
|
556
|
+
display: "flex",
|
|
557
|
+
alignItems: "center",
|
|
558
|
+
justifyContent: "space-between",
|
|
559
|
+
mb: 1,
|
|
560
|
+
gap: 4,
|
|
561
|
+
}}
|
|
562
|
+
>
|
|
563
|
+
<Typography id="centered-modal-title" variant="h5">
|
|
564
|
+
Your purchase was unsuccessful.
|
|
565
|
+
</Typography>
|
|
566
|
+
<IconButton aria-label="close" onClick={onClose} size="small">
|
|
567
|
+
<CloseIcon fontSize="small" />
|
|
568
|
+
</IconButton>
|
|
569
|
+
</Box>
|
|
570
|
+
|
|
571
|
+
<Box id="centered-modal-description">
|
|
572
|
+
<Typography variant="h6" component="h2">
|
|
573
|
+
Errors:
|
|
574
|
+
</Typography>
|
|
575
|
+
<ul>
|
|
576
|
+
{errors.map((error) => (
|
|
577
|
+
<Typography component="li">{error}</Typography>
|
|
578
|
+
))}
|
|
579
|
+
</ul>
|
|
580
|
+
</Box>
|
|
581
|
+
</Box>
|
|
582
|
+
</Fade>
|
|
583
|
+
</Modal>
|
|
584
|
+
);
|
|
585
|
+
}
|
|
@@ -68,6 +68,7 @@ export type AddCardProps = {
|
|
|
68
68
|
formDisabled;
|
|
69
69
|
formError;
|
|
70
70
|
};
|
|
71
|
+
hideFields?: string[];
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
export const AddCard = ({
|
|
@@ -84,6 +85,7 @@ export const AddCard = ({
|
|
|
84
85
|
formDisabled,
|
|
85
86
|
formError,
|
|
86
87
|
},
|
|
88
|
+
hideFields = [],
|
|
87
89
|
}: AddCardProps) => {
|
|
88
90
|
return (
|
|
89
91
|
<Container id="paymentMethodForm">
|
|
@@ -203,11 +205,13 @@ export const AddCard = ({
|
|
|
203
205
|
Billing Address
|
|
204
206
|
</Typography>
|
|
205
207
|
<AddressCountryField formik={formik} name="country" />
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
{!hideFields.includes("email") && (
|
|
209
|
+
<AddressEmailField
|
|
210
|
+
formik={formik}
|
|
211
|
+
name="email"
|
|
212
|
+
sx={{ mt: 2 }}
|
|
213
|
+
/>
|
|
214
|
+
)}
|
|
211
215
|
<AddressOrganizationNameField
|
|
212
216
|
sx={{ mt: 2 }}
|
|
213
217
|
formik={formik}
|
|
@@ -177,7 +177,7 @@ export function AddressEmailField({ formik, name, sx }: AddressFieldProps) {
|
|
|
177
177
|
return (
|
|
178
178
|
<>
|
|
179
179
|
<TextField
|
|
180
|
-
label="
|
|
180
|
+
label="Email"
|
|
181
181
|
sx={{ width: 400, display: "block", ...sx }}
|
|
182
182
|
name={name as string}
|
|
183
183
|
id={name as string}
|
|
@@ -138,10 +138,10 @@ export function CartList({
|
|
|
138
138
|
alignItems: "center",
|
|
139
139
|
}}
|
|
140
140
|
>
|
|
141
|
-
<Typography color="red">
|
|
141
|
+
{/* <Typography color="red">
|
|
142
142
|
Could not confirm payment. Your card info may have been entered
|
|
143
143
|
incorrectly.
|
|
144
|
-
</Typography>
|
|
144
|
+
</Typography> */}
|
|
145
145
|
<Button
|
|
146
146
|
onClick={() => {
|
|
147
147
|
setFormError(undefined);
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
.product-card {
|
|
2
|
-
width: 500px;
|
|
3
|
-
/* display: flex;
|
|
4
|
-
flex-direction: row;
|
|
5
|
-
justify-content: space-between; */
|
|
6
|
-
display: grid;
|
|
7
|
-
grid-template-columns: 1fr 40px;
|
|
8
|
-
gap: 0.5rem;
|
|
9
|
-
border-radius: 8px;
|
|
10
|
-
padding: 1rem;
|
|
11
|
-
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0);
|
|
12
|
-
transition: all 0.3s 0.1s;
|
|
13
|
-
cursor: pointer;
|
|
14
|
-
min-height: 48px;
|
|
15
|
-
flex-shrink: 0;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.product-card:hover {
|
|
19
|
-
box-shadow: 0px 2px 5px 2px #dfdfdfff;
|
|
20
|
-
transition: all 0.3s 0s;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.left-section {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: row;
|
|
26
|
-
gap: 1rem;
|
|
27
|
-
flex-grow: 1;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.left-section > img,
|
|
31
|
-
.missing-image {
|
|
32
|
-
min-height: 100%;
|
|
33
|
-
max-height: 100px;
|
|
34
|
-
aspect-ratio: 1;
|
|
35
|
-
border-radius: 6px;
|
|
36
|
-
overflow: hidden;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.missing-image {
|
|
40
|
-
background-color: rgb(222, 222, 222);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.two-row {
|
|
44
|
-
display: flex;
|
|
45
|
-
flex-direction: column;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.two-row :nth-child(1) {
|
|
49
|
-
font-size: 20px;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.two-row :nth-child(2) {
|
|
53
|
-
font-size: 14px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.two-row > * {
|
|
57
|
-
margin: 0;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.remove-button {
|
|
61
|
-
color: #ff000040 !important;
|
|
62
|
-
transition: all 0.2s !important;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.product-card:hover .remove-button {
|
|
66
|
-
color: red !important;
|
|
67
|
-
}
|
|
1
|
+
.product-card {
|
|
2
|
+
width: 500px;
|
|
3
|
+
/* display: flex;
|
|
4
|
+
flex-direction: row;
|
|
5
|
+
justify-content: space-between; */
|
|
6
|
+
display: grid;
|
|
7
|
+
grid-template-columns: 1fr 40px;
|
|
8
|
+
gap: 0.5rem;
|
|
9
|
+
border-radius: 8px;
|
|
10
|
+
padding: 1rem;
|
|
11
|
+
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0);
|
|
12
|
+
transition: all 0.3s 0.1s;
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
min-height: 48px;
|
|
15
|
+
flex-shrink: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.product-card:hover {
|
|
19
|
+
box-shadow: 0px 2px 5px 2px #dfdfdfff;
|
|
20
|
+
transition: all 0.3s 0s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.left-section {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: row;
|
|
26
|
+
gap: 1rem;
|
|
27
|
+
flex-grow: 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.left-section > img,
|
|
31
|
+
.missing-image {
|
|
32
|
+
min-height: 100%;
|
|
33
|
+
max-height: 100px;
|
|
34
|
+
aspect-ratio: 1;
|
|
35
|
+
border-radius: 6px;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.missing-image {
|
|
40
|
+
background-color: rgb(222, 222, 222);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.two-row {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.two-row :nth-child(1) {
|
|
49
|
+
font-size: 20px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.two-row :nth-child(2) {
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.two-row > * {
|
|
57
|
+
margin: 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.remove-button {
|
|
61
|
+
color: #ff000040 !important;
|
|
62
|
+
transition: all 0.2s !important;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.product-card:hover .remove-button {
|
|
66
|
+
color: red !important;
|
|
67
|
+
}
|
|
File without changes
|