@springmicro/cart 0.3.2 → 0.3.4
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 +531 -527
- package/dist/index.umd.cjs +43 -43
- package/package.json +5 -3
- package/src/AddToCartForm.tsx +16 -16
- package/src/CartButton.tsx +249 -249
- package/src/ProductCard.css +106 -106
- package/src/ProductCard.tsx +165 -165
- package/src/checkout/CheckoutList.css +93 -93
- package/src/checkout/CheckoutList.tsx +272 -264
- package/src/checkout/components/Address.tsx +265 -265
- package/src/checkout/components/Billing.tsx +353 -353
- package/src/checkout/components/CartProductCard.css +67 -67
- package/src/checkout/components/CartProductCard.tsx +80 -80
- package/src/checkout/components/Order.tsx +95 -93
- package/src/checkout/components/ProviderLogos.tsx +93 -93
- package/src/checkout/components/index.tsx +104 -104
- package/src/index.css +5 -5
- package/src/index.ts +35 -35
- package/src/types.d.ts +56 -56
- package/src/utils/api.ts +67 -67
- package/src/utils/cartAuthHandler.ts +50 -50
- package/src/utils/index.ts +28 -28
- package/src/utils/storage.ts +133 -133
- package/tsconfig.json +24 -24
- package/tsconfig.node.json +11 -11
- package/vite.config.ts +25 -25
- package/springmicro-cart-0.2.3.tgz +0 -0
package/src/ProductCard.css
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
.card {
|
|
2
|
-
display: flex;
|
|
3
|
-
gap: 0.5rem;
|
|
4
|
-
flex-direction: column;
|
|
5
|
-
border-radius: 8px;
|
|
6
|
-
padding: 1rem;
|
|
7
|
-
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0);
|
|
8
|
-
transition: all 0.3s 0.1s;
|
|
9
|
-
cursor: pointer;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.card:hover {
|
|
13
|
-
box-shadow: 0px 2px 5px 2px #dfdfdfff;
|
|
14
|
-
transition: all 0.3s 0s;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.card-section {
|
|
18
|
-
display: flex;
|
|
19
|
-
gap: 8px;
|
|
20
|
-
flex-direction: column;
|
|
21
|
-
align-items: center;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.image-container {
|
|
25
|
-
width: 100%;
|
|
26
|
-
background-color: #ccc;
|
|
27
|
-
border-radius: 4px;
|
|
28
|
-
aspect-ratio: 1.5;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.button-section {
|
|
32
|
-
display: flex;
|
|
33
|
-
justify-content: space-around;
|
|
34
|
-
flex-direction: row;
|
|
35
|
-
flex-wrap: wrap;
|
|
36
|
-
margin: 4px 2rem 0px;
|
|
37
|
-
gap: 0.5rem;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.addtocartbutton {
|
|
41
|
-
color: white;
|
|
42
|
-
background-color: rgb(39, 138, 230);
|
|
43
|
-
padding: 4px 16px 6px;
|
|
44
|
-
border-radius: 8px;
|
|
45
|
-
outline: none;
|
|
46
|
-
transition: all 0.3s;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.addtocartbutton.red {
|
|
50
|
-
background-color: rgb(230, 39, 39);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.addtocartbutton.disabled {
|
|
54
|
-
background-color: rgb(170, 170, 170);
|
|
55
|
-
cursor: not-allowed;
|
|
56
|
-
}
|
|
57
|
-
.addtocartbutton.disabled:hover {
|
|
58
|
-
background-color: rgb(170, 170, 170);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.addtocartbutton:hover {
|
|
62
|
-
background-color: rgb(36, 124, 207);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.hover-button > .hover-section {
|
|
66
|
-
display: none;
|
|
67
|
-
position: absolute;
|
|
68
|
-
width: 325px;
|
|
69
|
-
margin-left: calc(-113.75px);
|
|
70
|
-
padding: 1rem;
|
|
71
|
-
color: black;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.hover-button:hover > .hover-section {
|
|
75
|
-
display: flex;
|
|
76
|
-
justify-content: center;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.hover-data {
|
|
80
|
-
border-radius: 8px;
|
|
81
|
-
padding: 1rem;
|
|
82
|
-
box-shadow: 0px 2px 5px 2px rgb(173, 173, 173);
|
|
83
|
-
background-color: white;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.hover-data > div {
|
|
87
|
-
display: flex;
|
|
88
|
-
flex-direction: column;
|
|
89
|
-
background-color: rgb(203, 203, 203);
|
|
90
|
-
gap: 1px;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.tieredpricingbutton {
|
|
94
|
-
display: flex;
|
|
95
|
-
flex-direction: column;
|
|
96
|
-
justify-content: flex-start;
|
|
97
|
-
align-items: flex-start;
|
|
98
|
-
text-align: left;
|
|
99
|
-
padding: 4px 0.5rem 8px;
|
|
100
|
-
background-color: white;
|
|
101
|
-
transition: all 0.3s;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.tieredpricingbutton:hover {
|
|
105
|
-
background-color: rgb(233, 233, 233);
|
|
106
|
-
}
|
|
1
|
+
.card {
|
|
2
|
+
display: flex;
|
|
3
|
+
gap: 0.5rem;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
border-radius: 8px;
|
|
6
|
+
padding: 1rem;
|
|
7
|
+
box-shadow: 0px 0px 0px 0px rgba(0, 0, 0, 0);
|
|
8
|
+
transition: all 0.3s 0.1s;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.card:hover {
|
|
13
|
+
box-shadow: 0px 2px 5px 2px #dfdfdfff;
|
|
14
|
+
transition: all 0.3s 0s;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.card-section {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: 8px;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
align-items: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.image-container {
|
|
25
|
+
width: 100%;
|
|
26
|
+
background-color: #ccc;
|
|
27
|
+
border-radius: 4px;
|
|
28
|
+
aspect-ratio: 1.5;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.button-section {
|
|
32
|
+
display: flex;
|
|
33
|
+
justify-content: space-around;
|
|
34
|
+
flex-direction: row;
|
|
35
|
+
flex-wrap: wrap;
|
|
36
|
+
margin: 4px 2rem 0px;
|
|
37
|
+
gap: 0.5rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.addtocartbutton {
|
|
41
|
+
color: white;
|
|
42
|
+
background-color: rgb(39, 138, 230);
|
|
43
|
+
padding: 4px 16px 6px;
|
|
44
|
+
border-radius: 8px;
|
|
45
|
+
outline: none;
|
|
46
|
+
transition: all 0.3s;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.addtocartbutton.red {
|
|
50
|
+
background-color: rgb(230, 39, 39);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.addtocartbutton.disabled {
|
|
54
|
+
background-color: rgb(170, 170, 170);
|
|
55
|
+
cursor: not-allowed;
|
|
56
|
+
}
|
|
57
|
+
.addtocartbutton.disabled:hover {
|
|
58
|
+
background-color: rgb(170, 170, 170);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.addtocartbutton:hover {
|
|
62
|
+
background-color: rgb(36, 124, 207);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.hover-button > .hover-section {
|
|
66
|
+
display: none;
|
|
67
|
+
position: absolute;
|
|
68
|
+
width: 325px;
|
|
69
|
+
margin-left: calc(-113.75px);
|
|
70
|
+
padding: 1rem;
|
|
71
|
+
color: black;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.hover-button:hover > .hover-section {
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.hover-data {
|
|
80
|
+
border-radius: 8px;
|
|
81
|
+
padding: 1rem;
|
|
82
|
+
box-shadow: 0px 2px 5px 2px rgb(173, 173, 173);
|
|
83
|
+
background-color: white;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.hover-data > div {
|
|
87
|
+
display: flex;
|
|
88
|
+
flex-direction: column;
|
|
89
|
+
background-color: rgb(203, 203, 203);
|
|
90
|
+
gap: 1px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.tieredpricingbutton {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
justify-content: flex-start;
|
|
97
|
+
align-items: flex-start;
|
|
98
|
+
text-align: left;
|
|
99
|
+
padding: 4px 0.5rem 8px;
|
|
100
|
+
background-color: white;
|
|
101
|
+
transition: all 0.3s;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.tieredpricingbutton:hover {
|
|
105
|
+
background-color: rgb(233, 233, 233);
|
|
106
|
+
}
|
package/src/ProductCard.tsx
CHANGED
|
@@ -1,165 +1,165 @@
|
|
|
1
|
-
import "./ProductCard.css";
|
|
2
|
-
import { useStore } from "@nanostores/react";
|
|
3
|
-
import type React from "react";
|
|
4
|
-
import { Product, ProductPricing } from "./types";
|
|
5
|
-
import { addToCart, cartStore, removeFromCart } from "./utils/storage";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A card meant for displaying product data, allowing for purchases with managed functions.
|
|
9
|
-
*
|
|
10
|
-
* By default it displays a card component from the ecommerce-example repo but you can use a different component by providing it in the properties.
|
|
11
|
-
*
|
|
12
|
-
* A new component should be declared using this format: ```function ExampleComponent(props: @type {ProductCardComponentProps} { return <></>; })```
|
|
13
|
-
* Pass this new component as ```component={ExampleComponent}```
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
export type ProductCardComponentProps = {
|
|
17
|
-
product: Product;
|
|
18
|
-
foundInCart: {
|
|
19
|
-
product: boolean;
|
|
20
|
-
price: boolean;
|
|
21
|
-
};
|
|
22
|
-
pricing;
|
|
23
|
-
addToCart: (price_index?: number) => void;
|
|
24
|
-
removeFromCart: (price?: boolean) => void;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default function ProductCard({
|
|
28
|
-
product,
|
|
29
|
-
component,
|
|
30
|
-
priceTierName,
|
|
31
|
-
}: {
|
|
32
|
-
product: Product;
|
|
33
|
-
component?: React.FC<ProductCardComponentProps>;
|
|
34
|
-
priceTierName?: string; // Might have incomplete code for cases where the tier name doesn't match.
|
|
35
|
-
}) {
|
|
36
|
-
const cart = JSON.parse(useStore(cartStore));
|
|
37
|
-
|
|
38
|
-
const productInCartIndex: number = (cart.items as any[]).findIndex(
|
|
39
|
-
(p) => p.product_id === product.id
|
|
40
|
-
);
|
|
41
|
-
const productFoundInCart = !!~productInCartIndex;
|
|
42
|
-
|
|
43
|
-
const pricing: ProductPricing[] = JSON.parse(product.pricing);
|
|
44
|
-
|
|
45
|
-
const pi = pricing.findIndex((price) => price.tier_label === priceTierName); // TODO add fail-case for missing price
|
|
46
|
-
|
|
47
|
-
const priceInCartIndex: number = (cart.items as any[]).findIndex(
|
|
48
|
-
(p) => p.price_id === pricing[pi].id
|
|
49
|
-
);
|
|
50
|
-
const priceFoundInCart = !!~priceInCartIndex;
|
|
51
|
-
|
|
52
|
-
function addToCartSafe(priceIndex: number = pi) {
|
|
53
|
-
// Removes the ability to add improper info from the addToCart
|
|
54
|
-
addToCart({
|
|
55
|
-
product_id: product.id,
|
|
56
|
-
name: product.name,
|
|
57
|
-
price_id: pricing[priceIndex].id,
|
|
58
|
-
image: undefined,
|
|
59
|
-
quantity: undefined,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const props: ProductCardComponentProps = {
|
|
64
|
-
product,
|
|
65
|
-
foundInCart: {
|
|
66
|
-
product: productFoundInCart,
|
|
67
|
-
price: priceFoundInCart,
|
|
68
|
-
},
|
|
69
|
-
pricing,
|
|
70
|
-
addToCart: addToCartSafe,
|
|
71
|
-
removeFromCart: (price?: boolean) => {
|
|
72
|
-
removeFromCart(price ? priceInCartIndex : productInCartIndex);
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
if (component !== undefined) {
|
|
77
|
-
return component!(props);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return <DefaultProductCard {...props} />;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function DefaultProductCard({
|
|
84
|
-
product,
|
|
85
|
-
foundInCart,
|
|
86
|
-
pricing,
|
|
87
|
-
addToCart,
|
|
88
|
-
removeFromCart,
|
|
89
|
-
}: ProductCardComponentProps) {
|
|
90
|
-
return (
|
|
91
|
-
<div
|
|
92
|
-
className="card"
|
|
93
|
-
onClick={(e) =>
|
|
94
|
-
// @ts-expect-error it works
|
|
95
|
-
!e.target.closest("button") &&
|
|
96
|
-
(window.location.href = `/product/${product.id}`)
|
|
97
|
-
}
|
|
98
|
-
>
|
|
99
|
-
<div className="card-section">
|
|
100
|
-
<b>{product.name}</b>
|
|
101
|
-
<div className="image-container"></div>
|
|
102
|
-
</div>
|
|
103
|
-
{product.description && (
|
|
104
|
-
<p style={{ margin: "0px 1rem", flexGrow: 1 }}>{product.description}</p>
|
|
105
|
-
)}
|
|
106
|
-
<div className="button-section">
|
|
107
|
-
{foundInCart.product ? (
|
|
108
|
-
<button
|
|
109
|
-
className="addtocartbutton"
|
|
110
|
-
onClick={() => {
|
|
111
|
-
removeFromCart();
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
Remove from cart
|
|
115
|
-
</button>
|
|
116
|
-
) : pricing.length === 1 ? (
|
|
117
|
-
<button
|
|
118
|
-
className="addtocartbutton"
|
|
119
|
-
onClick={() => {
|
|
120
|
-
addToCart();
|
|
121
|
-
}}
|
|
122
|
-
>
|
|
123
|
-
Add {formatPricing(pricing[0])}
|
|
124
|
-
</button>
|
|
125
|
-
) : pricing.length === 0 ? (
|
|
126
|
-
<button className="addtocartbutton disabled">
|
|
127
|
-
Currently unavailable
|
|
128
|
-
</button>
|
|
129
|
-
) : (
|
|
130
|
-
<button className="addtocartbutton hover-button">
|
|
131
|
-
Add to cart ▼
|
|
132
|
-
<div className="hover-section">
|
|
133
|
-
<div className="hover-data">
|
|
134
|
-
<div>
|
|
135
|
-
{pricing.map((p, i) => (
|
|
136
|
-
<button
|
|
137
|
-
className="tieredpricingbutton"
|
|
138
|
-
onClick={() => {
|
|
139
|
-
addToCart(i);
|
|
140
|
-
}}
|
|
141
|
-
>
|
|
142
|
-
Tier {i + 1}:
|
|
143
|
-
<br />
|
|
144
|
-
{formatPricing(p)}
|
|
145
|
-
</button>
|
|
146
|
-
))}
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
</button>
|
|
151
|
-
)}
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function formatPricing({ unit_amount, recurring }: any) {
|
|
158
|
-
if (recurring) {
|
|
159
|
-
const { interval, interval_count } = recurring;
|
|
160
|
-
return `$${(unit_amount / 100).toFixed(2)}/${
|
|
161
|
-
interval_count === 1 ? interval : `${interval_count} ${interval}s`
|
|
162
|
-
}`;
|
|
163
|
-
}
|
|
164
|
-
return `$${(unit_amount / 100).toFixed(2)}`;
|
|
165
|
-
}
|
|
1
|
+
import "./ProductCard.css";
|
|
2
|
+
import { useStore } from "@nanostores/react";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import { Product, ProductPricing } from "./types";
|
|
5
|
+
import { addToCart, cartStore, removeFromCart } from "./utils/storage";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A card meant for displaying product data, allowing for purchases with managed functions.
|
|
9
|
+
*
|
|
10
|
+
* By default it displays a card component from the ecommerce-example repo but you can use a different component by providing it in the properties.
|
|
11
|
+
*
|
|
12
|
+
* A new component should be declared using this format: ```function ExampleComponent(props: @type {ProductCardComponentProps} { return <></>; })```
|
|
13
|
+
* Pass this new component as ```component={ExampleComponent}```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export type ProductCardComponentProps = {
|
|
17
|
+
product: Product;
|
|
18
|
+
foundInCart: {
|
|
19
|
+
product: boolean;
|
|
20
|
+
price: boolean;
|
|
21
|
+
};
|
|
22
|
+
pricing;
|
|
23
|
+
addToCart: (price_index?: number) => void;
|
|
24
|
+
removeFromCart: (price?: boolean) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default function ProductCard({
|
|
28
|
+
product,
|
|
29
|
+
component,
|
|
30
|
+
priceTierName,
|
|
31
|
+
}: {
|
|
32
|
+
product: Product;
|
|
33
|
+
component?: React.FC<ProductCardComponentProps>;
|
|
34
|
+
priceTierName?: string; // Might have incomplete code for cases where the tier name doesn't match.
|
|
35
|
+
}) {
|
|
36
|
+
const cart = JSON.parse(useStore(cartStore));
|
|
37
|
+
|
|
38
|
+
const productInCartIndex: number = (cart.items as any[]).findIndex(
|
|
39
|
+
(p) => p.product_id === product.id
|
|
40
|
+
);
|
|
41
|
+
const productFoundInCart = !!~productInCartIndex;
|
|
42
|
+
|
|
43
|
+
const pricing: ProductPricing[] = JSON.parse(product.pricing);
|
|
44
|
+
|
|
45
|
+
const pi = pricing.findIndex((price) => price.tier_label === priceTierName); // TODO add fail-case for missing price
|
|
46
|
+
|
|
47
|
+
const priceInCartIndex: number = (cart.items as any[]).findIndex(
|
|
48
|
+
(p) => p.price_id === pricing[pi].id
|
|
49
|
+
);
|
|
50
|
+
const priceFoundInCart = !!~priceInCartIndex;
|
|
51
|
+
|
|
52
|
+
function addToCartSafe(priceIndex: number = pi) {
|
|
53
|
+
// Removes the ability to add improper info from the addToCart
|
|
54
|
+
addToCart({
|
|
55
|
+
product_id: product.id,
|
|
56
|
+
name: product.name,
|
|
57
|
+
price_id: pricing[priceIndex].id,
|
|
58
|
+
image: undefined,
|
|
59
|
+
quantity: undefined,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const props: ProductCardComponentProps = {
|
|
64
|
+
product,
|
|
65
|
+
foundInCart: {
|
|
66
|
+
product: productFoundInCart,
|
|
67
|
+
price: priceFoundInCart,
|
|
68
|
+
},
|
|
69
|
+
pricing,
|
|
70
|
+
addToCart: addToCartSafe,
|
|
71
|
+
removeFromCart: (price?: boolean) => {
|
|
72
|
+
removeFromCart(price ? priceInCartIndex : productInCartIndex);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (component !== undefined) {
|
|
77
|
+
return component!(props);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return <DefaultProductCard {...props} />;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function DefaultProductCard({
|
|
84
|
+
product,
|
|
85
|
+
foundInCart,
|
|
86
|
+
pricing,
|
|
87
|
+
addToCart,
|
|
88
|
+
removeFromCart,
|
|
89
|
+
}: ProductCardComponentProps) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
className="card"
|
|
93
|
+
onClick={(e) =>
|
|
94
|
+
// @ts-expect-error it works
|
|
95
|
+
!e.target.closest("button") &&
|
|
96
|
+
(window.location.href = `/product/${product.id}`)
|
|
97
|
+
}
|
|
98
|
+
>
|
|
99
|
+
<div className="card-section">
|
|
100
|
+
<b>{product.name}</b>
|
|
101
|
+
<div className="image-container"></div>
|
|
102
|
+
</div>
|
|
103
|
+
{product.description && (
|
|
104
|
+
<p style={{ margin: "0px 1rem", flexGrow: 1 }}>{product.description}</p>
|
|
105
|
+
)}
|
|
106
|
+
<div className="button-section">
|
|
107
|
+
{foundInCart.product ? (
|
|
108
|
+
<button
|
|
109
|
+
className="addtocartbutton"
|
|
110
|
+
onClick={() => {
|
|
111
|
+
removeFromCart();
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
Remove from cart
|
|
115
|
+
</button>
|
|
116
|
+
) : pricing.length === 1 ? (
|
|
117
|
+
<button
|
|
118
|
+
className="addtocartbutton"
|
|
119
|
+
onClick={() => {
|
|
120
|
+
addToCart();
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
Add {formatPricing(pricing[0])}
|
|
124
|
+
</button>
|
|
125
|
+
) : pricing.length === 0 ? (
|
|
126
|
+
<button className="addtocartbutton disabled">
|
|
127
|
+
Currently unavailable
|
|
128
|
+
</button>
|
|
129
|
+
) : (
|
|
130
|
+
<button className="addtocartbutton hover-button">
|
|
131
|
+
Add to cart ▼
|
|
132
|
+
<div className="hover-section">
|
|
133
|
+
<div className="hover-data">
|
|
134
|
+
<div>
|
|
135
|
+
{pricing.map((p, i) => (
|
|
136
|
+
<button
|
|
137
|
+
className="tieredpricingbutton"
|
|
138
|
+
onClick={() => {
|
|
139
|
+
addToCart(i);
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
Tier {i + 1}:
|
|
143
|
+
<br />
|
|
144
|
+
{formatPricing(p)}
|
|
145
|
+
</button>
|
|
146
|
+
))}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</button>
|
|
151
|
+
)}
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function formatPricing({ unit_amount, recurring }: any) {
|
|
158
|
+
if (recurring) {
|
|
159
|
+
const { interval, interval_count } = recurring;
|
|
160
|
+
return `$${(unit_amount / 100).toFixed(2)}/${
|
|
161
|
+
interval_count === 1 ? interval : `${interval_count} ${interval}s`
|
|
162
|
+
}`;
|
|
163
|
+
}
|
|
164
|
+
return `$${(unit_amount / 100).toFixed(2)}`;
|
|
165
|
+
}
|