@springmicro/cart 0.7.22 → 0.7.24

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@springmicro/cart",
3
3
  "private": false,
4
- "version": "0.7.22",
4
+ "version": "0.7.24",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "@nanostores/persistent": "^0.10.1",
25
25
  "@nanostores/query": "^0.3.3",
26
26
  "@nanostores/react": "^0.7.2",
27
- "@springmicro/utils": "^0.7.22",
27
+ "@springmicro/utils": "^0.7.24",
28
28
  "dotenv": "^16.4.5",
29
29
  "nanostores": "^0.10.3",
30
30
  "react": "^19.2.4",
@@ -49,5 +49,5 @@
49
49
  "vite-plugin-css-injected-by-js": "^3.5.1",
50
50
  "yup": "^1.4.0"
51
51
  },
52
- "gitHead": "8bd83cea14b624431c069e6bebba77f858483da6"
52
+ "gitHead": "e261e94677f6c7b48082834e98f63b927bc3585f"
53
53
  }
@@ -39,12 +39,18 @@ import { postCheckout } from "../utils/api";
39
39
  import { CheckoutFieldsType } from ".";
40
40
  import CloseIcon from "@mui/icons-material/Close";
41
41
 
42
- async function createOrder(cart, customer_create, apiBaseUrl, dev) {
42
+ async function createOrder(
43
+ cart,
44
+ billing_information,
45
+ apiBaseUrl,
46
+ affiliateCode,
47
+ dev,
48
+ ) {
43
49
  dev && console.log("Creating order");
44
50
  // If an order has already been created and hasn't been changed, get the previous order.
45
51
  if (cart.order && cart.order.id && cart.order.reference) {
46
52
  const res = await fetch(
47
- `${apiBaseUrl}/api/ecommerce/orders/${cart.order.id}/reference/${cart.order.reference}`
53
+ `${apiBaseUrl}/api/ecommerce/orders/${cart.order.id}/reference/${cart.order.reference}`,
48
54
  );
49
55
  const order = await res.json();
50
56
 
@@ -63,17 +69,22 @@ async function createOrder(cart, customer_create, apiBaseUrl, dev) {
63
69
  "Content-Type": "application/json",
64
70
  },
65
71
  body: JSON.stringify({
66
- customer_create,
67
72
  cart_data: {
68
73
  items: cart.items.map((li) => ({
69
74
  ...li,
70
75
  name: undefined,
71
76
  image: undefined,
72
77
  })),
78
+ billing_information,
73
79
  },
80
+ affiliate_code: affiliateCode,
74
81
  }),
75
82
  credentials: "include",
76
83
  });
84
+ if (!res.ok) {
85
+ throw "Something when wrong when creating your order";
86
+ }
87
+
77
88
  const order = await res.json();
78
89
 
79
90
  if (!order) throw "Missing order";
@@ -86,49 +97,61 @@ async function createOrder(cart, customer_create, apiBaseUrl, dev) {
86
97
  return order;
87
98
  }
88
99
 
89
- async function getTax(apiBaseUrl, taxProvider, items, v, products, dev) {
90
- dev && console.log("Getting tax", items);
91
- dev &&
92
- console.log(
93
- "Getting product data",
94
- products,
95
- products[items[0].product_id]
96
- );
97
- const taxable_items = items.filter(
98
- (i) => i.unit_amount > 0 && products[i.product_id].type != "DONATION"
99
- );
100
- dev && console.log("Taxable items", taxable_items);
101
- if (taxable_items.length === 0) return { tax_amount: 0 };
102
-
103
- const res = await fetch(
104
- `${apiBaseUrl}/api/ecommerce/tax?tax_provider=${taxProvider ?? "dummy"}`,
105
- {
106
- method: "POST",
107
- body: JSON.stringify({
108
- cart_data: taxable_items.map((i) => ({
109
- amount: i.unit_amount,
110
- reference: i.reference,
111
- })),
112
- address: {
113
- country: v.country,
114
- city: v.locality,
115
- line1: v.street_address,
116
- postal_code: v.postal_code,
117
- state: v.region,
118
- },
119
- }),
120
- headers: {
121
- "Content-Type": "application/json",
122
- },
123
- }
124
- );
125
- return await res.json();
126
- }
100
+ // async function getTax(apiBaseUrl, taxProvider, items, v, products, dev) {
101
+ // dev && console.log("Getting tax", items);
102
+ // dev &&
103
+ // console.log(
104
+ // "Getting product data",
105
+ // products,
106
+ // products[items[0].product_id],
107
+ // );
108
+ // const taxable_items = items.filter(
109
+ // (i) => i.unit_amount > 0 && products[i.product_id].type != "DONATION",
110
+ // );
111
+ // dev && console.log("Taxable items", taxable_items);
112
+ // if (taxable_items.length === 0) return { tax_amount: 0 };
113
+
114
+ // const res = await fetch(
115
+ // `${apiBaseUrl}/api/ecommerce/tax?tax_provider=${taxProvider ?? "dummy"}`,
116
+ // {
117
+ // method: "POST",
118
+ // body: JSON.stringify({
119
+ // cart_data: taxable_items.map((i) => ({
120
+ // amount: i.unit_amount,
121
+ // reference: i.reference,
122
+ // })),
123
+ // address: {
124
+ // country: v.country,
125
+ // city: v.locality,
126
+ // line1: v.street_address,
127
+ // postal_code: v.postal_code,
128
+ // state: v.region,
129
+ // },
130
+ // }),
131
+ // headers: {
132
+ // "Content-Type": "application/json",
133
+ // },
134
+ // },
135
+ // );
136
+ // return await res.json();
137
+ // }
138
+
139
+ // getTax(
140
+ // apiBaseUrl,
141
+ // taxProvider,
142
+ // cart.items.map((i) => ({
143
+ // unit_amount: prices[i.price_id].unit_amount,
144
+ // reference: i.name,
145
+ // product_id: i.product_id,
146
+ // })),
147
+ // values,
148
+ // products,
149
+ // dev,
150
+ // ),
127
151
 
128
152
  export default function ReviewAndCalculateTaxes({
129
153
  subtotal,
130
154
  discount,
131
- taxState,
132
155
  shipping,
133
156
  statusState,
134
157
  cart,
@@ -145,6 +168,7 @@ export default function ReviewAndCalculateTaxes({
145
168
  CollectExtraInfo = undefined,
146
169
  defaultValues = {},
147
170
  dev,
171
+ affiliateCode,
148
172
  hideFields = [],
149
173
  disableFields = [],
150
174
  }) {
@@ -155,7 +179,6 @@ export default function ReviewAndCalculateTaxes({
155
179
  const stacked = useMediaQuery(theme.breakpoints.down("lg"));
156
180
 
157
181
  const [status, setStatus] = statusState;
158
- const [tax, setTax] = taxState;
159
182
  const [order, setOrder] = orderState;
160
183
 
161
184
  const [precheckErrors, setPrecheckErrors] = useState([]);
@@ -166,31 +189,23 @@ export default function ReviewAndCalculateTaxes({
166
189
  // status === 0 when this is clicked.
167
190
  // Creates an order and calculates tax.
168
191
  dev && console.log("Cart items", cart.items);
169
- Promise.all([
170
- createOrder(
171
- cart,
172
- {
173
- email: values.email,
174
- name: values.name,
175
- },
176
- apiBaseUrl,
177
- dev
178
- ),
179
- getTax(
180
- apiBaseUrl,
181
- taxProvider,
182
- cart.items.map((i) => ({
183
- unit_amount: prices[i.price_id].unit_amount,
184
- reference: i.name,
185
- product_id: i.product_id,
186
- })),
187
- values,
188
- products,
189
- dev
190
- ),
191
- ])
192
- .then(([order, taxData]) => {
193
- setTax(taxData);
192
+
193
+ createOrder(
194
+ cart,
195
+ {
196
+ email: values.email,
197
+ name: values.name,
198
+ country: values.country,
199
+ locality: values.locality,
200
+ street_address: values.street_address,
201
+ postal_code: values.postal_code,
202
+ state: values.region,
203
+ },
204
+ apiBaseUrl,
205
+ affiliateCode,
206
+ dev,
207
+ )
208
+ .then((order) => {
194
209
  setOrder(order);
195
210
  setStatus(1);
196
211
  setFormDisabled(false);
@@ -212,7 +227,7 @@ export default function ReviewAndCalculateTaxes({
212
227
  order.reference,
213
228
  values,
214
229
  "stripe",
215
- invoiceId
230
+ invoiceId,
216
231
  )
217
232
  .then(async (data) => {
218
233
  dev && console.log("Checkout submitted.", data);
@@ -324,7 +339,7 @@ export default function ReviewAndCalculateTaxes({
324
339
  ...validationSchemaAddress,
325
340
  }
326
341
  : validationSchemaBase
327
- : {}
342
+ : {},
328
343
  ),
329
344
  onSubmit: async (v, helpers) => {
330
345
  dev && console.log("Formik submit");
@@ -405,7 +420,7 @@ export default function ReviewAndCalculateTaxes({
405
420
  flexDirection: { xs: "column", xl: "row" },
406
421
  justifyContent: "center",
407
422
  alignItems: { xs: undefined, xl: "flex-start" },
408
- px: { xs: 32, xl: 16 },
423
+ px: { xs: 2, xl: 16 },
409
424
  "&>div": { width: { xs: undefined, xl: "50%" } },
410
425
  }}
411
426
  >
@@ -414,7 +429,7 @@ export default function ReviewAndCalculateTaxes({
414
429
  statusState: [status, setStatus],
415
430
  cart,
416
431
  subtotal,
417
- tax,
432
+ orderState,
418
433
  shipping,
419
434
  discount,
420
435
  prices,
@@ -475,14 +490,14 @@ function CheckoutActionFields({
475
490
  const checkoutFields: Record<string, CheckoutFieldsType> = [
476
491
  ...Object.keys(products).flatMap((productKey) =>
477
492
  (products[productKey].actions ?? []).flatMap(
478
- (action) => action.checkout_fields ?? []
479
- )
493
+ (action) => action.checkout_fields ?? [],
494
+ ),
480
495
  ),
481
496
  // TODO Add this once prices have checkout fields
482
497
  ...Object.keys(prices).flatMap((priceKey) =>
483
498
  (prices[priceKey].actions ?? []).flatMap(
484
- (action) => action.checkout_fields ?? []
485
- )
499
+ (action) => action.checkout_fields ?? [],
500
+ ),
486
501
  ),
487
502
 
488
503
  // Overwrites the checkout field to use the last one provided. This allows prices to overwrite product checkout fields if necessary.
@@ -512,7 +527,7 @@ function CheckoutActionFields({
512
527
  !(
513
528
  checkoutFields[key].hidden === true ||
514
529
  checkoutFields[key].hidden === "true"
515
- )
530
+ ),
516
531
  )
517
532
  .map((key) => {
518
533
  const {
@@ -58,7 +58,7 @@ export type AddCardProps = {
58
58
  cardRequired?: boolean;
59
59
  address?: boolean;
60
60
  onSubmit?: (
61
- values: CreditCardValues & Partial<AddressValues>
61
+ values: CreditCardValues & Partial<AddressValues>,
62
62
  ) => Promise<any>;
63
63
  PriceDetails?: JSX.Element;
64
64
  formData?: {
@@ -195,7 +195,6 @@ export const AddCard = ({
195
195
  display: "flex",
196
196
  flexDirection: "row",
197
197
  gap: 2,
198
- width: "100%",
199
198
  }}
200
199
  >
201
200
  <Box sx={{ flexGrow: 1 }}>
@@ -204,51 +203,75 @@ export const AddCard = ({
204
203
  <Typography variant="h6" sx={{ mt: 2, mb: 3 }}>
205
204
  Billing Address
206
205
  </Typography>
207
- <AddressCountryField formik={formik} name="country" />
208
- {!hideFields.includes("email") && (
209
- <AddressEmailField
206
+ <Box
207
+ sx={{
208
+ display: "flex",
209
+ flexDirection: "column",
210
+ gap: 2,
211
+ width: "100%",
212
+ }}
213
+ >
214
+ {!hideFields.includes("email") && (
215
+ <AddressEmailField
216
+ formik={formik}
217
+ name="email"
218
+ sx={{ width: "100%" }}
219
+ />
220
+ )}
221
+ <AddressCountryField
210
222
  formik={formik}
211
- name="email"
212
- sx={{ mt: 2 }}
223
+ name="country"
224
+ sx={{ width: "100%" }}
213
225
  />
214
- )}
215
- <AddressOrganizationNameField
216
- sx={{ mt: 2 }}
217
- formik={formik}
218
- name="organization"
219
- />
220
- <AddressStreetField
221
- sx={{ mt: 2 }}
222
- formik={formik}
223
- name="line1"
224
- lineNo="1"
225
- />
226
- <AddressStreetField
227
- sx={{ mt: 2 }}
228
- formik={formik}
229
- name="line2"
230
- lineNo="2"
231
- required={false}
232
- />
233
- <AddressCityField
234
- sx={{ mt: 2 }}
235
- formik={formik}
236
- name="city"
237
- />
238
- <AddressRegionField
239
- sx={{ mt: 2 }}
240
- formik={formik}
241
- name="region"
242
- />
243
- <AddressPostalCodeField
244
- sx={{ mt: 2 }}
245
- formik={formik}
246
- name="postal_code"
247
- />
226
+ <AddressOrganizationNameField
227
+ formik={formik}
228
+ name="organization"
229
+ sx={{ width: "100%" }}
230
+ />
231
+ <AddressStreetField
232
+ formik={formik}
233
+ name="line1"
234
+ lineNo="1"
235
+ sx={{ width: "100%" }}
236
+ />
237
+ <AddressStreetField
238
+ formik={formik}
239
+ name="line2"
240
+ lineNo="2"
241
+ required={false}
242
+ sx={{ width: "100%" }}
243
+ />
244
+ <Box
245
+ sx={{
246
+ display: "flex",
247
+ flexDirection: { xs: "column", md: "row" },
248
+ gap: 2,
249
+ width: "100%",
250
+ }}
251
+ >
252
+ <AddressCityField
253
+ formik={formik}
254
+ name="city"
255
+ sx={{ flex: "2 1 0", minWidth: 0 }}
256
+ />
257
+
258
+ <AddressRegionField
259
+ formik={formik}
260
+ name="region"
261
+ sx={{ width: 300, flexShrink: 0 }}
262
+ />
263
+
264
+ <AddressPostalCodeField
265
+ formik={formik}
266
+ name="postal_code"
267
+ sx={{ flex: "1 1 0", minWidth: 0 }}
268
+ />
269
+ </Box>
270
+ </Box>
248
271
  </Box>
249
272
  )}
250
273
  </Box>
251
- <Box
274
+ {/* <Box
252
275
  sx={{
253
276
  mt: "16px",
254
277
  display: "flex",
@@ -258,7 +281,7 @@ export const AddCard = ({
258
281
  }}
259
282
  >
260
283
  {PriceDetails}
261
- </Box>
284
+ </Box> */}
262
285
  </Box>
263
286
  )}
264
287
  {error && (
@@ -105,13 +105,13 @@ export function AddressRegionField({ formik, name, sx }: AddressFieldProps) {
105
105
  useEffect(() => {
106
106
  setAddressRegionFieldOptional(
107
107
  provinces.filter(
108
- (province: Province) => province.country === country2code
109
- ).length === 0
108
+ (province: Province) => province.country === country2code,
109
+ ).length === 0,
110
110
  );
111
111
  }, [country2code]);
112
112
 
113
113
  const baseProps = {
114
- sx: { width: 300, ...sx },
114
+ sx: { width: 300, flexShrink: 0, ...sx },
115
115
  label: getRegionLabel(country2code),
116
116
  name: name as string,
117
117
  id: name as string,
@@ -160,6 +160,7 @@ export function AddressStreetField({
160
160
  return (
161
161
  <>
162
162
  <TextField
163
+ fullWidth
163
164
  label={lineNo ? `Street Address ${lineNo}` : "Street Address"}
164
165
  sx={{ width: 400, display: "block", ...sx }}
165
166
  name={name as string}
@@ -198,6 +199,7 @@ export function AddressOrganizationNameField({
198
199
  }: AddressFieldProps) {
199
200
  return (
200
201
  <TextField
202
+ fullWidth
201
203
  label="Organization Name"
202
204
  sx={{ width: 400, display: "block", ...sx }}
203
205
  name={name as string}
@@ -215,7 +217,7 @@ export function AddressCityField({ formik, name, sx }: AddressFieldProps) {
215
217
  return (
216
218
  <TextField
217
219
  label="City"
218
- sx={{ width: 400, display: "block", ...sx }}
220
+ sx={sx}
219
221
  name={name as string}
220
222
  id={name as string}
221
223
  value={formik.values[name]}
@@ -244,7 +246,7 @@ export function AddressPostalCodeField({
244
246
  return (
245
247
  <TextField
246
248
  label={getPostalCodeLabel(country2code)}
247
- sx={{ width: 400, display: "block", ...sx }}
249
+ sx={{ ...sx }}
248
250
  name={name as string}
249
251
  id={name as string}
250
252
  value={formik.values[name]}
@@ -10,7 +10,7 @@ export function CartList({
10
10
  statusState,
11
11
  cart,
12
12
  subtotal,
13
- tax,
13
+ orderState,
14
14
  shipping,
15
15
  discount,
16
16
  prices,
@@ -23,6 +23,9 @@ export function CartList({
23
23
  }) {
24
24
  const [status, setStatus] = statusState;
25
25
  const [formError, setFormError] = formErrorState;
26
+ const [order] = orderState;
27
+ const { taxes = "Pending", total } = order ?? {};
28
+
26
29
  return (
27
30
  <form
28
31
  style={{ flexGrow: 1 }}
@@ -65,29 +68,9 @@ export function CartList({
65
68
  <Typography sx={{ fontSize: "20px", p: 1 }}>
66
69
  Subtotal: {formatPrice(subtotal)}
67
70
  </Typography>
68
- {tax.error ? (
69
- <Tooltip
70
- disableInteractive
71
- title={`Tax could not be calculated. Error: ${tax.error}`}
72
- >
73
- <Typography
74
- sx={{
75
- fontSize: "20px",
76
- bgcolor: "#ff000040",
77
- borderRadius: 2,
78
- p: 1,
79
- textDecoration: "underline dotted",
80
- cursor: "help",
81
- }}
82
- >
83
- Taxes: {formatPrice(tax.tax_amount)}
84
- </Typography>
85
- </Tooltip>
86
- ) : (
87
- <Typography sx={{ fontSize: "20px", p: 1 }}>
88
- Taxes: {formatPrice(tax.tax_amount)}
89
- </Typography>
90
- )}
71
+ <Typography sx={{ fontSize: "20px", p: 1 }}>
72
+ Taxes: {formatPrice(taxes)}
73
+ </Typography>
91
74
  </Box>
92
75
  {(discount != 0 || shipping != 0) && (
93
76
  <Box
@@ -108,12 +91,12 @@ export function CartList({
108
91
  <Box>
109
92
  <Typography style={{ fontSize: "26px" }}>
110
93
  Total:{" "}
111
- {typeof subtotal === "number"
94
+ {total || typeof subtotal === "number"
112
95
  ? formatPrice(
113
96
  subtotal +
114
- (tax.tax_amount === "TBD" ? 0 : tax.tax_amount) +
97
+ (typeof taxes === "string" ? 0 : taxes) +
115
98
  shipping -
116
- discount
99
+ discount,
117
100
  )
118
101
  : subtotal}
119
102
  </Typography>
@@ -156,7 +139,7 @@ export function CartList({
156
139
  <Box className="checkout-list">
157
140
  {cart.items.map((p, i) => (
158
141
  <CartProductCard
159
- product={products[p.product_id] ?? p}
142
+ product={{ ...p, ...(products[p.product_id] ?? {}) }}
160
143
  i={i}
161
144
  price={prices[p.price_id]}
162
145
  disableProductLink={disableProductLink}
@@ -38,7 +38,9 @@ export function CartProductCard({
38
38
  !disableMissingImage && <div className="missing-image" />
39
39
  )}
40
40
  <div className="two-row">
41
- <Typography>{product.name}</Typography>
41
+ <Typography>
42
+ {product.name.replace("%s", product.hidden_id)}
43
+ </Typography>
42
44
  <Typography>
43
45
  {price
44
46
  ? `$${(price.unit_amount / 100).toFixed(2)}${
@@ -17,17 +17,23 @@ export function StatusBar({ status, backlink = "" }) {
17
17
  </IconButton>
18
18
  </Tooltip>
19
19
  </Box>
20
- <div id="status-bar">
20
+ <Box id="status-bar">
21
21
  <Typography className="status-text active">PAYMENT DETAILS</Typography>
22
- <div className={"status-bar" + (status > 0 ? " active" : "")}></div>
22
+ <Box
23
+ className={"status-bar" + (status > 0 ? " active" : "")}
24
+ sx={{ display: { xs: "none", md: "block" } }}
25
+ ></Box>
23
26
  <Typography className={"status-text" + (status > 0 ? " active" : "")}>
24
27
  CONFIRMATION
25
28
  </Typography>
26
- <div className={"status-bar" + (status > 1 ? " active" : "")}></div>
29
+ <Box
30
+ className={"status-bar" + (status > 1 ? " active" : "")}
31
+ sx={{ display: { xs: "none", md: "block" } }}
32
+ ></Box>
27
33
  <Typography className={"status-text" + (status > 1 ? " active" : "")}>
28
34
  ORDER PLACED
29
35
  </Typography>
30
- </div>
36
+ </Box>
31
37
  <Box sx={{ flex: "1 1" }} />
32
38
  </Box>
33
39
  );