@libreapps/commerce 7.5.1
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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE.md +21 -0
- package/components/Icons.tsx +35 -0
- package/components/add-to-cart-widget.tsx +183 -0
- package/components/buy/buy-card.tsx +259 -0
- package/components/buy/carousel-buy-card.tsx +242 -0
- package/components/buy/multi-family/all-variants-carousel.tsx +261 -0
- package/components/buy/multi-family/family-carousel/index.tsx +77 -0
- package/components/buy/multi-family/family-carousel/slide.tsx +83 -0
- package/components/buy/multi-family/family-carousel/state.ts +87 -0
- package/components/buy/multi-family/index.ts +2 -0
- package/components/buy/single-family-selector.tsx +90 -0
- package/components/buy/title-and-byline.tsx +25 -0
- package/components/cart/cart-panel/cart-line-item.tsx +76 -0
- package/components/cart/cart-panel/index.tsx +154 -0
- package/components/cart/cart-panel/promo-code.tsx +109 -0
- package/components/cart/cart-panel/total-area.tsx +60 -0
- package/components/checkout/payment-step-form/card-icon-row.tsx +26 -0
- package/components/checkout/payment-step-form/card-icons/amex.tsx +32 -0
- package/components/checkout/payment-step-form/card-icons/diners-club.tsx +13 -0
- package/components/checkout/payment-step-form/card-icons/discover.tsx +25 -0
- package/components/checkout/payment-step-form/card-icons/jcb.tsx +26 -0
- package/components/checkout/payment-step-form/card-icons/mastercard.tsx +27 -0
- package/components/checkout/payment-step-form/card-icons/visa.tsx +25 -0
- package/components/checkout/payment-step-form/cc-button.tsx +17 -0
- package/components/checkout/payment-step-form/contact-form.tsx +50 -0
- package/components/checkout/payment-step-form/crypto-icons/btc.tsx +11 -0
- package/components/checkout/payment-step-form/crypto-icons/eth.tsx +20 -0
- package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +13 -0
- package/components/checkout/payment-step-form/index.tsx +122 -0
- package/components/checkout/payment-step-form/methods/bank-transfer.tsx +79 -0
- package/components/checkout/payment-step-form/methods/card.tsx +232 -0
- package/components/checkout/payment-step-form/methods/crypto.tsx +227 -0
- package/components/checkout/payment-step-form/methods/index.ts +23 -0
- package/components/checkout/shipping-step-form.tsx +175 -0
- package/components/index.ts +11 -0
- package/components/item/product-card.tsx +48 -0
- package/components/item-selector/button.tsx +188 -0
- package/components/item-selector/carousel/index.tsx +197 -0
- package/components/item-selector/carousel/slider.tsx +40 -0
- package/components/item-selector/index.ts +5 -0
- package/components/item-selector/quantity-indicator.tsx +48 -0
- package/components/node-tabs/index.tsx +91 -0
- package/components/node-tabs/node-image.tsx +31 -0
- package/dist/components/Icons.d.ts +18 -0
- package/dist/components/Icons.js +19 -0
- package/dist/components/Icons.js.map +1 -0
- package/dist/components/add-to-cart-widget.d.ts +11 -0
- package/dist/components/add-to-cart-widget.js +85 -0
- package/dist/components/add-to-cart-widget.js.map +1 -0
- package/dist/components/buy/buy-card.d.ts +30 -0
- package/dist/components/buy/buy-card.js +109 -0
- package/dist/components/buy/buy-card.js.map +1 -0
- package/dist/components/buy/carousel-buy-card.d.ts +12 -0
- package/dist/components/buy/carousel-buy-card.js +94 -0
- package/dist/components/buy/carousel-buy-card.js.map +1 -0
- package/dist/components/buy/multi-family/all-variants-carousel.d.ts +4 -0
- package/dist/components/buy/multi-family/all-variants-carousel.js +115 -0
- package/dist/components/buy/multi-family/all-variants-carousel.js.map +1 -0
- package/dist/components/buy/multi-family/family-carousel/index.d.ts +4 -0
- package/dist/components/buy/multi-family/family-carousel/index.js +27 -0
- package/dist/components/buy/multi-family/family-carousel/index.js.map +1 -0
- package/dist/components/buy/multi-family/family-carousel/slide.d.ts +11 -0
- package/dist/components/buy/multi-family/family-carousel/slide.js +35 -0
- package/dist/components/buy/multi-family/family-carousel/slide.js.map +1 -0
- package/dist/components/buy/multi-family/family-carousel/state.d.ts +20 -0
- package/dist/components/buy/multi-family/family-carousel/state.js +59 -0
- package/dist/components/buy/multi-family/family-carousel/state.js.map +1 -0
- package/dist/components/buy/multi-family/index.d.ts +2 -0
- package/dist/components/buy/multi-family/index.js +3 -0
- package/dist/components/buy/multi-family/index.js.map +1 -0
- package/dist/components/buy/single-family-selector.d.ts +15 -0
- package/dist/components/buy/single-family-selector.js +28 -0
- package/dist/components/buy/single-family-selector.js.map +1 -0
- package/dist/components/buy/title-and-byline.d.ts +8 -0
- package/dist/components/buy/title-and-byline.js +7 -0
- package/dist/components/buy/title-and-byline.js.map +1 -0
- package/dist/components/cart/cart-panel/cart-line-item.d.ts +11 -0
- package/dist/components/cart/cart-panel/cart-line-item.js +25 -0
- package/dist/components/cart/cart-panel/cart-line-item.js.map +1 -0
- package/dist/components/cart/cart-panel/index.d.ts +19 -0
- package/dist/components/cart/cart-panel/index.js +65 -0
- package/dist/components/cart/cart-panel/index.js.map +1 -0
- package/dist/components/cart/cart-panel/promo-code.d.ts +4 -0
- package/dist/components/cart/cart-panel/promo-code.js +62 -0
- package/dist/components/cart/cart-panel/promo-code.js.map +1 -0
- package/dist/components/cart/cart-panel/total-area.d.ts +7 -0
- package/dist/components/cart/cart-panel/total-area.js +14 -0
- package/dist/components/cart/cart-panel/total-area.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icon-row.d.ts +2 -0
- package/dist/components/checkout/payment-step-form/card-icon-row.js +14 -0
- package/dist/components/checkout/payment-step-form/card-icon-row.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/amex.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/amex.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/amex.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/diners-club.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/diners-club.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/diners-club.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/discover.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/discover.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/discover.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/jcb.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/jcb.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/jcb.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/mastercard.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/mastercard.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/mastercard.js.map +1 -0
- package/dist/components/checkout/payment-step-form/card-icons/visa.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/card-icons/visa.js +6 -0
- package/dist/components/checkout/payment-step-form/card-icons/visa.js.map +1 -0
- package/dist/components/checkout/payment-step-form/cc-button.d.ts +3 -0
- package/dist/components/checkout/payment-step-form/cc-button.js +6 -0
- package/dist/components/checkout/payment-step-form/cc-button.js.map +1 -0
- package/dist/components/checkout/payment-step-form/contact-form.d.ts +5 -0
- package/dist/components/checkout/payment-step-form/contact-form.js +6 -0
- package/dist/components/checkout/payment-step-form/contact-form.js.map +1 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/btc.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/btc.js +6 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/btc.js.map +1 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/eth.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/eth.js +6 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/eth.js.map +1 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/usdt.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js +6 -0
- package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js.map +1 -0
- package/dist/components/checkout/payment-step-form/index.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/index.js +77 -0
- package/dist/components/checkout/payment-step-form/index.js.map +1 -0
- package/dist/components/checkout/payment-step-form/methods/bank-transfer.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/methods/bank-transfer.js +24 -0
- package/dist/components/checkout/payment-step-form/methods/bank-transfer.js.map +1 -0
- package/dist/components/checkout/payment-step-form/methods/card.d.ts +4 -0
- package/dist/components/checkout/payment-step-form/methods/card.js +160 -0
- package/dist/components/checkout/payment-step-form/methods/card.js.map +1 -0
- package/dist/components/checkout/payment-step-form/methods/crypto.d.ts +9 -0
- package/dist/components/checkout/payment-step-form/methods/crypto.js +137 -0
- package/dist/components/checkout/payment-step-form/methods/crypto.js.map +1 -0
- package/dist/components/checkout/payment-step-form/methods/index.d.ts +6 -0
- package/dist/components/checkout/payment-step-form/methods/index.js +21 -0
- package/dist/components/checkout/payment-step-form/methods/index.js.map +1 -0
- package/dist/components/checkout/shipping-step-form.d.ts +3 -0
- package/dist/components/checkout/shipping-step-form.js +53 -0
- package/dist/components/checkout/shipping-step-form.js.map +1 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.js +9 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/item/product-card.d.ts +7 -0
- package/dist/components/item/product-card.js +9 -0
- package/dist/components/item/product-card.js.map +1 -0
- package/dist/components/item-selector/button.d.ts +4 -0
- package/dist/components/item-selector/button.js +47 -0
- package/dist/components/item-selector/button.js.map +1 -0
- package/dist/components/item-selector/carousel/index.d.ts +12 -0
- package/dist/components/item-selector/carousel/index.js +74 -0
- package/dist/components/item-selector/carousel/index.js.map +1 -0
- package/dist/components/item-selector/carousel/slider.d.ts +8 -0
- package/dist/components/item-selector/carousel/slider.js +12 -0
- package/dist/components/item-selector/carousel/slider.js.map +1 -0
- package/dist/components/item-selector/index.d.ts +2 -0
- package/dist/components/item-selector/index.js +3 -0
- package/dist/components/item-selector/index.js.map +1 -0
- package/dist/components/item-selector/quantity-indicator.d.ts +9 -0
- package/dist/components/item-selector/quantity-indicator.js +16 -0
- package/dist/components/item-selector/quantity-indicator.js.map +1 -0
- package/dist/components/node-tabs/index.d.ts +14 -0
- package/dist/components/node-tabs/index.js +42 -0
- package/dist/components/node-tabs/index.js.map +1 -0
- package/dist/components/node-tabs/node-image.d.ts +6 -0
- package/dist/components/node-tabs/node-image.js +13 -0
- package/dist/components/node-tabs/node-image.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/service/context.d.ts +8 -0
- package/dist/service/context.js +19 -0
- package/dist/service/context.js.map +1 -0
- package/dist/service/debug.d.ts +10 -0
- package/dist/service/debug.js +30 -0
- package/dist/service/debug.js.map +1 -0
- package/dist/service/impls/standalone/actual-line-item.d.ts +40 -0
- package/dist/service/impls/standalone/actual-line-item.js +84 -0
- package/dist/service/impls/standalone/actual-line-item.js.map +1 -0
- package/dist/service/impls/standalone/get-instance.d.ts +2 -0
- package/dist/service/impls/standalone/get-instance.js +39 -0
- package/dist/service/impls/standalone/get-instance.js.map +1 -0
- package/dist/service/impls/standalone/index.d.ts +67 -0
- package/dist/service/impls/standalone/index.js +416 -0
- package/dist/service/impls/standalone/index.js.map +1 -0
- package/dist/service/impls/standalone/order/firebase.d.ts +2 -0
- package/dist/service/impls/standalone/order/firebase.js +13 -0
- package/dist/service/impls/standalone/order/firebase.js.map +1 -0
- package/dist/service/impls/standalone/order/index.d.ts +24 -0
- package/dist/service/impls/standalone/order/index.js +61 -0
- package/dist/service/impls/standalone/order/index.js.map +1 -0
- package/dist/service/impls/standalone/persistence.d.ts +4 -0
- package/dist/service/impls/standalone/persistence.js +22 -0
- package/dist/service/impls/standalone/persistence.js.map +1 -0
- package/dist/service/path-utils.d.ts +7 -0
- package/dist/service/path-utils.js +16 -0
- package/dist/service/path-utils.js.map +1 -0
- package/dist/service/sep.d.ts +6 -0
- package/dist/service/sep.js +6 -0
- package/dist/service/sep.js.map +1 -0
- package/dist/types/category-node.d.ts +36 -0
- package/dist/types/category-node.js +2 -0
- package/dist/types/category-node.js.map +1 -0
- package/dist/types/checkout.d.ts +33 -0
- package/dist/types/checkout.js +2 -0
- package/dist/types/checkout.js.map +1 -0
- package/dist/types/commerce-config.d.ts +11 -0
- package/dist/types/commerce-config.js +2 -0
- package/dist/types/commerce-config.js.map +1 -0
- package/dist/types/commerce-service.d.ts +109 -0
- package/dist/types/commerce-service.js +2 -0
- package/dist/types/commerce-service.js.map +1 -0
- package/dist/types/family.d.ts +16 -0
- package/dist/types/family.js +2 -0
- package/dist/types/family.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/item-selector.d.ts +72 -0
- package/dist/types/item-selector.js +2 -0
- package/dist/types/item-selector.js.map +1 -0
- package/dist/types/line-item.d.ts +14 -0
- package/dist/types/line-item.js +2 -0
- package/dist/types/line-item.js.map +1 -0
- package/dist/types/multi-family-selector-props.d.ts +16 -0
- package/dist/types/multi-family-selector-props.js +2 -0
- package/dist/types/multi-family-selector-props.js.map +1 -0
- package/dist/types/product.d.ts +15 -0
- package/dist/types/product.js +2 -0
- package/dist/types/product.js.map +1 -0
- package/dist/types/promo.d.ts +7 -0
- package/dist/types/promo.js +2 -0
- package/dist/types/promo.js.map +1 -0
- package/dist/types/selection-ui-specifier.d.ts +40 -0
- package/dist/types/selection-ui-specifier.js +2 -0
- package/dist/types/selection-ui-specifier.js.map +1 -0
- package/dist/types/string-mutator.d.ts +9 -0
- package/dist/types/string-mutator.js +2 -0
- package/dist/types/string-mutator.js.map +1 -0
- package/dist/types/token-separators.d.ts +6 -0
- package/dist/types/token-separators.js +2 -0
- package/dist/types/token-separators.js.map +1 -0
- package/dist/util/analytics.d.ts +9 -0
- package/dist/util/analytics.js +10 -0
- package/dist/util/analytics.js.map +1 -0
- package/dist/util/countries.d.ts +7 -0
- package/dist/util/countries.js +197 -0
- package/dist/util/countries.js.map +1 -0
- package/dist/util/error.d.ts +1 -0
- package/dist/util/error.js +22 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/index.d.ts +15 -0
- package/dist/util/index.js +54 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/item-selector-options-accessor.d.ts +3 -0
- package/dist/util/item-selector-options-accessor.js +27 -0
- package/dist/util/item-selector-options-accessor.js.map +1 -0
- package/dist/util/line-item-ref.d.ts +8 -0
- package/dist/util/line-item-ref.js +15 -0
- package/dist/util/line-item-ref.js.map +1 -0
- package/dist/util/multi-family-selector-options-accessor.d.ts +3 -0
- package/dist/util/multi-family-selector-options-accessor.js +11 -0
- package/dist/util/multi-family-selector-options-accessor.js.map +1 -0
- package/dist/util/obs-string-mutator.d.ts +8 -0
- package/dist/util/obs-string-mutator.js +15 -0
- package/dist/util/obs-string-mutator.js.map +1 -0
- package/dist/util/product-media-accessor.d.ts +29 -0
- package/dist/util/product-media-accessor.js +22 -0
- package/dist/util/product-media-accessor.js.map +1 -0
- package/dist/util/promo-codes.d.ts +3 -0
- package/dist/util/promo-codes.js +100 -0
- package/dist/util/promo-codes.js.map +1 -0
- package/dist/util/selection-ui-specifiers.d.ts +3 -0
- package/dist/util/selection-ui-specifiers.js +24 -0
- package/dist/util/selection-ui-specifiers.js.map +1 -0
- package/dist/util/square-payment.d.ts +7 -0
- package/dist/util/square-payment.js +37 -0
- package/dist/util/square-payment.js.map +1 -0
- package/dist/util/use-sync-sku-param-w-current-item.d.ts +2 -0
- package/dist/util/use-sync-sku-param-w-current-item.js +61 -0
- package/dist/util/use-sync-sku-param-w-current-item.js.map +1 -0
- package/index.ts +13 -0
- package/libreapps-ui.d.ts +108 -0
- package/package.json +67 -0
- package/service/context.tsx +45 -0
- package/service/debug.ts +41 -0
- package/service/impls/standalone/actual-line-item.ts +136 -0
- package/service/impls/standalone/get-instance.ts +64 -0
- package/service/impls/standalone/index.ts +579 -0
- package/service/impls/standalone/order/firebase.ts +14 -0
- package/service/impls/standalone/order/index.ts +129 -0
- package/service/impls/standalone/persistence.ts +33 -0
- package/service/path-utils.ts +26 -0
- package/service/sep.ts +7 -0
- package/tsconfig.json +17 -0
- package/types/README.md +2 -0
- package/types/category-node.ts +50 -0
- package/types/checkout.ts +47 -0
- package/types/commerce-config.ts +13 -0
- package/types/commerce-service.ts +128 -0
- package/types/family.ts +26 -0
- package/types/index.ts +15 -0
- package/types/item-selector.ts +97 -0
- package/types/line-item.ts +29 -0
- package/types/multi-family-selector-props.ts +20 -0
- package/types/product.ts +21 -0
- package/types/promo.ts +10 -0
- package/types/selection-ui-specifier.ts +52 -0
- package/types/string-mutator.ts +14 -0
- package/types/token-separators.ts +7 -0
- package/util/analytics.ts +21 -0
- package/util/countries.ts +196 -0
- package/util/error.ts +34 -0
- package/util/index.ts +71 -0
- package/util/item-selector-options-accessor.ts +35 -0
- package/util/line-item-ref.ts +23 -0
- package/util/multi-family-selector-options-accessor.ts +15 -0
- package/util/obs-string-mutator.ts +22 -0
- package/util/product-media-accessor.ts +58 -0
- package/util/promo-codes.ts +106 -0
- package/util/selection-ui-specifiers.ts +30 -0
- package/util/square-payment.ts +50 -0
- package/util/use-sync-sku-param-w-current-item.ts +88 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Family, LineItem, ObsLineItemRef, Product } from '../../../../types'
|
|
2
|
+
import { observable, action, computed, makeObservable } from 'mobx'
|
|
3
|
+
|
|
4
|
+
class SlideState implements ObsLineItemRef {
|
|
5
|
+
|
|
6
|
+
_fam: Family
|
|
7
|
+
_item: Product
|
|
8
|
+
_syncSku: (sku: string) => void
|
|
9
|
+
_selected: boolean
|
|
10
|
+
|
|
11
|
+
constructor(fam: Family, initiallySelected: boolean, sync: (sku: string) => void) {
|
|
12
|
+
this._fam = fam
|
|
13
|
+
this._item = fam.products[0]
|
|
14
|
+
this._selected = initiallySelected
|
|
15
|
+
this._syncSku = sync
|
|
16
|
+
|
|
17
|
+
makeObservable(this, {
|
|
18
|
+
_item: observable,
|
|
19
|
+
item: computed,
|
|
20
|
+
selectSku: action
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
selectSku = (sku: string) => {
|
|
25
|
+
if (this._item.sku === sku) return;
|
|
26
|
+
const found = this._fam.products.find((i) => (i.sku === sku))
|
|
27
|
+
if (found) {
|
|
28
|
+
this._item = found
|
|
29
|
+
if (this._selected) {
|
|
30
|
+
this._syncSku(sku)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw new Error('SlideState.selectSku(): no item found!')
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setSelected = (b: boolean) => {this._selected = b}
|
|
39
|
+
|
|
40
|
+
get id(): string {return (this._fam.id)}
|
|
41
|
+
|
|
42
|
+
get item(): LineItem | undefined {
|
|
43
|
+
return this._item as LineItem
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class FamilyCarouselState {
|
|
48
|
+
|
|
49
|
+
_map = new Map<string, SlideState>()
|
|
50
|
+
_syncSku: (sku: string) => void
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
fams: Family[],
|
|
54
|
+
// initialFamilyId: string,
|
|
55
|
+
syncSkuToCurrentSlide: (sku: string) => void
|
|
56
|
+
) {
|
|
57
|
+
|
|
58
|
+
fams.forEach((f, index) => {this._map.set(f.id, new SlideState(
|
|
59
|
+
f,
|
|
60
|
+
(index === 0),
|
|
61
|
+
syncSkuToCurrentSlide
|
|
62
|
+
))})
|
|
63
|
+
this._syncSku = syncSkuToCurrentSlide
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
setCurrentFamily = (id: string) => {
|
|
67
|
+
|
|
68
|
+
this._map.forEach((s) => {
|
|
69
|
+
s.setSelected(s.id === id)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const slideState = this._map.get(id)
|
|
73
|
+
if (slideState) {
|
|
74
|
+
this._syncSku(slideState.item!.sku)
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
throw new Error(`FamilyCarouselState.setCurrentFamily: no state object for id '${id}'!`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getSlideState = (familyId: string): SlideState | undefined => (this._map.get(familyId))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
SlideState,
|
|
86
|
+
FamilyCarouselState
|
|
87
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { observer } from 'mobx-react-lite'
|
|
3
|
+
|
|
4
|
+
import { MediaStack, Skeleton } from '@libreapps/ui/primitives'
|
|
5
|
+
import type { Dimensions } from '@libreapps/ui/types'
|
|
6
|
+
|
|
7
|
+
import { useCommerce } from '../..'
|
|
8
|
+
|
|
9
|
+
import type { ItemSelectorOptions, ItemSelectorProps, LineItem } from '../../types'
|
|
10
|
+
import TitleAndByline from './title-and-byline'
|
|
11
|
+
import { accessItemOptions } from '../../util'
|
|
12
|
+
import { cn } from '@libreapps/ui/util'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const DEF_MEDIA_CONSTRAINT = {w: 200, h: 200}
|
|
16
|
+
|
|
17
|
+
const SingleFamilySelector: React.FC<{
|
|
18
|
+
items: LineItem[] // these may be sorted, so are we can't just use currentFamily.products
|
|
19
|
+
Selector: React.ComponentType<ItemSelectorProps>
|
|
20
|
+
selOptions: ItemSelectorOptions | undefined
|
|
21
|
+
scrollable?: boolean
|
|
22
|
+
showItemMedia?: boolean
|
|
23
|
+
mediaConstraint?: Dimensions
|
|
24
|
+
mobile?: boolean
|
|
25
|
+
clx?: string
|
|
26
|
+
titleAreaClx?: string
|
|
27
|
+
}> = ({
|
|
28
|
+
items,
|
|
29
|
+
Selector,
|
|
30
|
+
selOptions,
|
|
31
|
+
scrollable=false,
|
|
32
|
+
showItemMedia=true,
|
|
33
|
+
mediaConstraint=DEF_MEDIA_CONSTRAINT,
|
|
34
|
+
mobile=false,
|
|
35
|
+
clx='',
|
|
36
|
+
titleAreaClx=''
|
|
37
|
+
}) => {
|
|
38
|
+
|
|
39
|
+
const cmmc = useCommerce()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const MyTitleAndByline: React.FC<{clx?: string}> = observer(({
|
|
43
|
+
clx=''
|
|
44
|
+
}) => {
|
|
45
|
+
const { familyTitle, showFamilyByline } = accessItemOptions(selOptions)
|
|
46
|
+
const title = (familyTitle === 'none' ?
|
|
47
|
+
undefined
|
|
48
|
+
:
|
|
49
|
+
(familyTitle === 'long' ?
|
|
50
|
+
cmmc.currentFamily?.title
|
|
51
|
+
:
|
|
52
|
+
(cmmc.currentFamily?.titleShort ?? cmmc.currentFamily?.title)
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
const byline = (familyTitle !== 'none') && showFamilyByline ? cmmc.currentFamily?.byline : undefined
|
|
56
|
+
return ( <TitleAndByline clx={clx} title={title} byline={byline}/> )
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const ItemMedia: React.FC = observer(() => (
|
|
60
|
+
cmmc.currentItem ? (
|
|
61
|
+
<MediaStack
|
|
62
|
+
media={cmmc.currentItem!}
|
|
63
|
+
constrainTo={mediaConstraint}
|
|
64
|
+
clx={'mb-2 ' + (scrollable ? 'shrink-0' : '')}
|
|
65
|
+
/>
|
|
66
|
+
) : (
|
|
67
|
+
<Skeleton className={'w-[200px] h-[200px] my-2 ' + (scrollable ? 'shrink-0' : '')}/>
|
|
68
|
+
)
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className={cn(clx, 'flex flex-col items-center', (scrollable ? 'shrink' : ''))}>
|
|
73
|
+
<MyTitleAndByline clx={cn(titleAreaClx, (scrollable ? 'shrink-0' : ''))} />
|
|
74
|
+
{showItemMedia && (<ItemMedia />)}
|
|
75
|
+
{items && (
|
|
76
|
+
<Selector
|
|
77
|
+
items={items}
|
|
78
|
+
selectedItemRef={cmmc}
|
|
79
|
+
selectSku={cmmc.setCurrentItem.bind(cmmc)}
|
|
80
|
+
scrollable={scrollable}
|
|
81
|
+
mobile={mobile}
|
|
82
|
+
options={selOptions}
|
|
83
|
+
clx={(scrollable ? 'shrink' : '')}
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default SingleFamilySelector
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { ApplyTypography } from '@libreapps/ui/primitives'
|
|
4
|
+
import { cn } from '@libreapps/ui/util'
|
|
5
|
+
|
|
6
|
+
const TitleAndByline: React.FC<{
|
|
7
|
+
title: string | undefined
|
|
8
|
+
byline?: string | undefined
|
|
9
|
+
clx?: string
|
|
10
|
+
bylineClx?: string
|
|
11
|
+
}> = ({
|
|
12
|
+
title,
|
|
13
|
+
byline,
|
|
14
|
+
clx='',
|
|
15
|
+
bylineClx=''
|
|
16
|
+
}) => ( (title || byline) ? (
|
|
17
|
+
<ApplyTypography className={cn('flex flex-col items-center !gap-0 [&>*]:!m-0 ', clx)} >
|
|
18
|
+
<h4>{title}</h4>
|
|
19
|
+
{byline && (<h6 className={bylineClx}>{byline}</h6>)}
|
|
20
|
+
</ApplyTypography>
|
|
21
|
+
) : (null)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default TitleAndByline
|
|
25
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { observer } from 'mobx-react-lite'
|
|
5
|
+
|
|
6
|
+
import { cn } from '@libreapps/ui/util'
|
|
7
|
+
import { Image } from '@libreapps/ui/primitives'
|
|
8
|
+
|
|
9
|
+
import type { LineItem } from '../../../types'
|
|
10
|
+
import { formatCurrencyValue } from '../../../util'
|
|
11
|
+
import AddToCartWidget from '../../add-to-cart-widget'
|
|
12
|
+
import { useCommerce } from '../../../service/context'
|
|
13
|
+
|
|
14
|
+
const DEF_IMG_SIZE=40
|
|
15
|
+
|
|
16
|
+
const renderTitle = (t: string): React.ReactNode => {
|
|
17
|
+
const toks = t.split(', ')
|
|
18
|
+
if (toks.length === 2) {
|
|
19
|
+
return <><p>{toks[0]},</p><p className=''>{toks[1]}</p></>
|
|
20
|
+
}
|
|
21
|
+
return <p>{t}</p>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const CartLineItem: React.FC<{
|
|
25
|
+
item: LineItem
|
|
26
|
+
className?: string
|
|
27
|
+
imgSizePx?: number
|
|
28
|
+
showPromoCode?: boolean
|
|
29
|
+
itemClicked?: (item: LineItem) => void
|
|
30
|
+
selected?: boolean
|
|
31
|
+
}> = observer(({
|
|
32
|
+
item,
|
|
33
|
+
className='',
|
|
34
|
+
imgSizePx=DEF_IMG_SIZE,
|
|
35
|
+
showPromoCode=false,
|
|
36
|
+
itemClicked,
|
|
37
|
+
selected=false
|
|
38
|
+
}) => {
|
|
39
|
+
|
|
40
|
+
const cmmc = useCommerce()
|
|
41
|
+
const promoPrice = showPromoCode ? cmmc.itemPromoPrice(item) : undefined
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div
|
|
45
|
+
className={cn(
|
|
46
|
+
'flex flex-col justify-start items-start text-sm font-sans',
|
|
47
|
+
'border border-background rounded-sm p-1',
|
|
48
|
+
selected ? 'border-foreground' : '',
|
|
49
|
+
(itemClicked && !selected ? 'cursor-pointer hover:!border-muted-4' : 'cursor-default '),
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
onClick={() => {itemClicked && itemClicked(item)}}
|
|
53
|
+
>
|
|
54
|
+
<div className='flex flex-row justify-between items-center gap-1' >
|
|
55
|
+
{item.img ? (
|
|
56
|
+
<Image def={item.img} constrainTo={{w: imgSizePx, h: imgSizePx}} />
|
|
57
|
+
) : ( // placeholder so things align
|
|
58
|
+
<div style={{height: imgSizePx, width: imgSizePx}} className='bg-level-3'/>
|
|
59
|
+
)}
|
|
60
|
+
<div className='grow leading-tight ml-1'>{renderTitle(item.title)}</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div className='flex flex-row items-center justify-between w-full'>
|
|
63
|
+
<div className='flex flex-row items-center'>
|
|
64
|
+
<AddToCartWidget variant='minimal' item={item} />
|
|
65
|
+
{item.quantity > 1 && (<span className='pl-2.5'>{'@' + formatCurrencyValue(item.price)}</span>)}
|
|
66
|
+
</div>
|
|
67
|
+
<div className='flex flex-row gap-1 items-center justify-end'>
|
|
68
|
+
<span className={promoPrice ? 'line-through text-muted-2' : ''}>{formatCurrencyValue(item.price * item.quantity)}</span>
|
|
69
|
+
{promoPrice && <span>{formatCurrencyValue(promoPrice * item.quantity)}</span>}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
export default CartLineItem
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React, { useLayoutEffect, type PropsWithChildren } from 'react'
|
|
3
|
+
import { reaction } from 'mobx'
|
|
4
|
+
import { observer } from 'mobx-react-lite'
|
|
5
|
+
|
|
6
|
+
import { Button, ScrollArea } from '@libreapps/ui/primitives'
|
|
7
|
+
import { cn } from '@libreapps/ui/util'
|
|
8
|
+
|
|
9
|
+
import type { LineItem } from '../../../types'
|
|
10
|
+
import { useCommerce } from '../../../service/context'
|
|
11
|
+
import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
|
|
12
|
+
|
|
13
|
+
import CartLineItem from './cart-line-item'
|
|
14
|
+
import TotalArea from './total-area'
|
|
15
|
+
|
|
16
|
+
const CartPanel: React.FC<PropsWithChildren & {
|
|
17
|
+
/** fix size and scroll after 'scrollAfter items in teh cart. */
|
|
18
|
+
scrollAfter?: number
|
|
19
|
+
scrollHeightClx?: string
|
|
20
|
+
imgSizePx?: number
|
|
21
|
+
className?: string
|
|
22
|
+
itemClx?: string
|
|
23
|
+
listClx?: string
|
|
24
|
+
noItemsClx?: string
|
|
25
|
+
totalClx?: string
|
|
26
|
+
buttonClx?: string
|
|
27
|
+
showPromoCode?: boolean
|
|
28
|
+
showShipping?: boolean
|
|
29
|
+
selectItems?: boolean
|
|
30
|
+
/** if not provided, 'checkout' button will be rendered */
|
|
31
|
+
handleCheckout?: () => void
|
|
32
|
+
}> = observer(({
|
|
33
|
+
/** If provided, 'children' is rendered above the items. eg, a heading. */
|
|
34
|
+
children,
|
|
35
|
+
scrollAfter=5,
|
|
36
|
+
scrollHeightClx='h-[70vh]',
|
|
37
|
+
imgSizePx=40,
|
|
38
|
+
className='',
|
|
39
|
+
itemClx='',
|
|
40
|
+
listClx='',
|
|
41
|
+
noItemsClx='',
|
|
42
|
+
totalClx='',
|
|
43
|
+
buttonClx='',
|
|
44
|
+
showPromoCode=false,
|
|
45
|
+
showShipping=false,
|
|
46
|
+
selectItems=false,
|
|
47
|
+
handleCheckout,
|
|
48
|
+
}) => {
|
|
49
|
+
|
|
50
|
+
const cmmc = useCommerce()
|
|
51
|
+
|
|
52
|
+
useLayoutEffect(() => {
|
|
53
|
+
if (!cmmc) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
if (!cmmc.cartEmpty && !cmmc.currentItem) {
|
|
57
|
+
cmmc.setCurrentItem(cmmc.cartItems[0].sku)
|
|
58
|
+
}
|
|
59
|
+
// return mobx disposer
|
|
60
|
+
return reaction(() => (
|
|
61
|
+
cmmc.cartItems.length
|
|
62
|
+
),
|
|
63
|
+
(itemCount) => {
|
|
64
|
+
if (itemCount > 0) {
|
|
65
|
+
cmmc.setCurrentItem(cmmc.cartItems[0].sku)
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}, [])
|
|
69
|
+
|
|
70
|
+
if (!cmmc) {
|
|
71
|
+
return <div />
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const _handleCheckout = () => {
|
|
75
|
+
sendGAEvent('begin_checkout', {
|
|
76
|
+
currency: 'USD',
|
|
77
|
+
value: cmmc.cartTotal,
|
|
78
|
+
items: cmmc.cartItems.map((item) => ({
|
|
79
|
+
item_id: item.sku,
|
|
80
|
+
item_name: item.title,
|
|
81
|
+
item_category: item.familyId,
|
|
82
|
+
price: item.price,
|
|
83
|
+
quantity: item.quantity
|
|
84
|
+
})),
|
|
85
|
+
})
|
|
86
|
+
sendFBEvent('InitiateCheckout', {
|
|
87
|
+
content_ids: cmmc.cartItems.map((item) => item.sku),
|
|
88
|
+
contents: cmmc.cartItems.map(item => ({
|
|
89
|
+
id: item.sku,
|
|
90
|
+
quantity: item.quantity
|
|
91
|
+
})),
|
|
92
|
+
num_items: cmmc.cartItems.length,
|
|
93
|
+
value: cmmc.cartTotal,
|
|
94
|
+
currency: 'USD',
|
|
95
|
+
})
|
|
96
|
+
handleCheckout && handleCheckout()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const itemClicked = (item: LineItem) => {
|
|
100
|
+
cmmc.setCurrentItem(item.sku)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const MainStuff: React.FC = observer(() => (<>
|
|
104
|
+
{cmmc.cartEmpty ? (
|
|
105
|
+
<p className={cn('text-center my-3', noItemsClx)}>No items</p>
|
|
106
|
+
) : (<>
|
|
107
|
+
{cmmc.cartItems.map((item) => (
|
|
108
|
+
<CartLineItem
|
|
109
|
+
key={`mobile-${item.sku}`}
|
|
110
|
+
imgSizePx={imgSizePx}
|
|
111
|
+
item={item}
|
|
112
|
+
className={cn('mb-2', itemClx)}
|
|
113
|
+
showPromoCode={showPromoCode}
|
|
114
|
+
itemClicked={selectItems ? itemClicked : undefined}
|
|
115
|
+
selected={selectItems ? cmmc.currentItem?.sku === item.sku : false}
|
|
116
|
+
/>
|
|
117
|
+
))}
|
|
118
|
+
</>)}
|
|
119
|
+
<TotalArea clx={totalClx} showPromoCode={showPromoCode} showShipping={showShipping}/>
|
|
120
|
+
</>))
|
|
121
|
+
|
|
122
|
+
const scrolling = (cmmc.cartItems.length > scrollAfter)
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div className={cn(
|
|
126
|
+
'border p-4 rounded-lg flex flex-col',
|
|
127
|
+
className,
|
|
128
|
+
scrolling ? scrollHeightClx : 'h-auto'
|
|
129
|
+
)}>
|
|
130
|
+
{children}
|
|
131
|
+
{scrolling ? (
|
|
132
|
+
<ScrollArea className={cn('mt-2 w-full shrink py-0', listClx)}>
|
|
133
|
+
<MainStuff />
|
|
134
|
+
</ScrollArea>
|
|
135
|
+
) : (
|
|
136
|
+
<div className={cn('mt-2 w-full', listClx)}>
|
|
137
|
+
<MainStuff />
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
{handleCheckout && !cmmc.cartEmpty && (
|
|
141
|
+
<Button
|
|
142
|
+
onClick={_handleCheckout}
|
|
143
|
+
variant='primary'
|
|
144
|
+
rounded='lg'
|
|
145
|
+
className={cn('mt-12 mx-auto w-full sm:max-w-[220px]', buttonClx)}
|
|
146
|
+
>
|
|
147
|
+
Checkout
|
|
148
|
+
</Button>
|
|
149
|
+
)}
|
|
150
|
+
</div>
|
|
151
|
+
)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
export default CartPanel
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react'
|
|
4
|
+
import { useSearchParams } from 'next/navigation'
|
|
5
|
+
import { observer } from 'mobx-react-lite'
|
|
6
|
+
|
|
7
|
+
import { useForm } from 'react-hook-form'
|
|
8
|
+
import * as z from 'zod'
|
|
9
|
+
import { zodResolver } from '@hookform/resolvers/zod'
|
|
10
|
+
import { Check } from 'lucide-react'
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
Button,
|
|
14
|
+
Input
|
|
15
|
+
} from '@libreapps/ui/primitives'
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
Form,
|
|
19
|
+
FormControl,
|
|
20
|
+
FormField,
|
|
21
|
+
FormItem,
|
|
22
|
+
} from '@libreapps/ui/form'
|
|
23
|
+
|
|
24
|
+
import { useCommerce } from '../../../service/context'
|
|
25
|
+
import type { Promo } from '../../../types'
|
|
26
|
+
import getPromoFromApi from '../../../util/promo-codes'
|
|
27
|
+
|
|
28
|
+
const formSchema = z.object({
|
|
29
|
+
code: z.string().min(1, 'Invalid code'),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const PromoCode = observer(() => {
|
|
33
|
+
const cmmc = useCommerce()
|
|
34
|
+
const searchParams = useSearchParams()
|
|
35
|
+
|
|
36
|
+
const [codeAccepted, setCodeAccepted] = useState<boolean>(false)
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const code = searchParams.get('code')
|
|
40
|
+
if (code) {
|
|
41
|
+
getPromoFromApi(code).then((promo?: Promo) => {
|
|
42
|
+
if (promo) {
|
|
43
|
+
form.setValue('code', code)
|
|
44
|
+
setCodeAccepted(true)
|
|
45
|
+
cmmc.setAppliedPromo(promo)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}, [searchParams])
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (cmmc.appliedPromo) {
|
|
53
|
+
form.setValue('code', cmmc.appliedPromo.code)
|
|
54
|
+
setCodeAccepted(true)
|
|
55
|
+
}
|
|
56
|
+
}, [cmmc.appliedPromo])
|
|
57
|
+
|
|
58
|
+
const form = useForm<z.infer<typeof formSchema>>({
|
|
59
|
+
resolver: zodResolver(formSchema),
|
|
60
|
+
defaultValues: {
|
|
61
|
+
code: '',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const applyPromoCode = async (values: z.infer<typeof formSchema>) => {
|
|
66
|
+
const { code } = values
|
|
67
|
+
const promo = await getPromoFromApi(code)
|
|
68
|
+
if (!promo) {
|
|
69
|
+
form.setError('code', { message: 'Invalid code' })
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
setCodeAccepted(true)
|
|
73
|
+
cmmc.setAppliedPromo(promo)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const removePromoCode = () => {
|
|
77
|
+
cmmc.setAppliedPromo(null)
|
|
78
|
+
setCodeAccepted(false)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className='flex flex-col gap-2 border-t py-1'>
|
|
83
|
+
<Form {...form}>
|
|
84
|
+
<form onSubmit={form.handleSubmit(applyPromoCode)}>
|
|
85
|
+
<div className='flex gap-2 items-center'>
|
|
86
|
+
<FormField
|
|
87
|
+
control={form.control}
|
|
88
|
+
name='code'
|
|
89
|
+
render={({ field }) => (
|
|
90
|
+
<FormItem className='w-full'>
|
|
91
|
+
<FormControl>
|
|
92
|
+
<Input {...field} className='h-9' placeholder='Discount or invite code' onInput={removePromoCode}/>
|
|
93
|
+
</FormControl>
|
|
94
|
+
</FormItem>
|
|
95
|
+
)}
|
|
96
|
+
/>
|
|
97
|
+
{codeAccepted ? (
|
|
98
|
+
<Check/>
|
|
99
|
+
) : (
|
|
100
|
+
<Button variant='outline' className='!w-fit !min-w-0 font-inter text-muted text-sm'>Apply</Button>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
</form>
|
|
104
|
+
</Form>
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
export default PromoCode
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import React, { Suspense } from 'react'
|
|
3
|
+
import { observer } from 'mobx-react-lite'
|
|
4
|
+
|
|
5
|
+
import { cn } from '@libreapps/ui/util'
|
|
6
|
+
|
|
7
|
+
import { formatCurrencyValue } from '../../../util'
|
|
8
|
+
import PromoCode from './promo-code'
|
|
9
|
+
import { useCommerce } from '../../../service/context'
|
|
10
|
+
|
|
11
|
+
const TotalArea: React.FC<{
|
|
12
|
+
showPromoCode?: boolean
|
|
13
|
+
showShipping?: boolean
|
|
14
|
+
clx?: string
|
|
15
|
+
}> = observer(({
|
|
16
|
+
showPromoCode=false,
|
|
17
|
+
showShipping=false,
|
|
18
|
+
clx
|
|
19
|
+
}) => {
|
|
20
|
+
|
|
21
|
+
const cmmc = useCommerce()
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className={clx}>
|
|
25
|
+
{showPromoCode && (
|
|
26
|
+
<Suspense>
|
|
27
|
+
<PromoCode/>
|
|
28
|
+
</Suspense>
|
|
29
|
+
)}
|
|
30
|
+
{(showShipping || showPromoCode) && (
|
|
31
|
+
<div className={'flex flex-col gap-0.5 pb-1.5 text-sm ' + (!showPromoCode ? 'border-t pt-1.5' : '')} >
|
|
32
|
+
<p className='flex justify-between'>
|
|
33
|
+
<span className='text-muted-1'>Subtotal</span>
|
|
34
|
+
<span className='font-semibold'>{cmmc.cartTotal === 0 ? '0' : formatCurrencyValue(cmmc.cartTotal)}</span>
|
|
35
|
+
</p>
|
|
36
|
+
{cmmc.promoAppliedCartTotal !== cmmc.cartTotal && (
|
|
37
|
+
<p className='flex justify-between'>
|
|
38
|
+
<span className='text-muted-1'>Promo Discount</span>
|
|
39
|
+
<span className='font-semibold'>-{formatCurrencyValue(cmmc.cartTotal - cmmc.promoAppliedCartTotal)}</span>
|
|
40
|
+
</p>
|
|
41
|
+
)}
|
|
42
|
+
{showShipping && (
|
|
43
|
+
<p className='flex justify-between'>
|
|
44
|
+
<span className='text-muted-1'>Shipping</span>
|
|
45
|
+
<span className='font-semibold'>Free Global Shipping</span>
|
|
46
|
+
</p>
|
|
47
|
+
)}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
<p className={cn('border-t py-2 flex justify-between')}>
|
|
51
|
+
TOTAL
|
|
52
|
+
<span className='font-semibold'>
|
|
53
|
+
{formatCurrencyValue(showPromoCode ? cmmc.promoAppliedCartTotal : cmmc.cartTotal)}
|
|
54
|
+
</span>
|
|
55
|
+
</p>
|
|
56
|
+
</div>
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
export default TotalArea
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LockKeyhole } from 'lucide-react'
|
|
2
|
+
import Amex from './card-icons/amex'
|
|
3
|
+
import Discover from './card-icons/discover'
|
|
4
|
+
import Mastercard from './card-icons/mastercard'
|
|
5
|
+
import Visa from './card-icons/visa'
|
|
6
|
+
import DinersClub from './card-icons/diners-club'
|
|
7
|
+
import Jcb from './card-icons/jcb'
|
|
8
|
+
|
|
9
|
+
// <span className='hidden sm:flex text-sm'>Secure payments with</span>
|
|
10
|
+
|
|
11
|
+
const PaymentMethods: React.FC = () => {
|
|
12
|
+
return (
|
|
13
|
+
<div className='flex gap-1 items-center text-muted-1 pb-3'>
|
|
14
|
+
<LockKeyhole className='w-4 h-4'/>
|
|
15
|
+
<span className='hidden sm:flex text-sm'>Secure payments with</span>
|
|
16
|
+
<Amex className='w-9 h-5'/>
|
|
17
|
+
<Discover className='w-9 h-5'/>
|
|
18
|
+
<Mastercard className='w-9 h-5'/>
|
|
19
|
+
<Visa className='w-9 h-5'/>
|
|
20
|
+
<DinersClub className='w-9 h-5'/>
|
|
21
|
+
<Jcb className='w-9 h-5'/>
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default PaymentMethods
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { type LucideProps } from 'lucide-react'
|
|
3
|
+
|
|
4
|
+
const Amex: React.FC<LucideProps> = (props: LucideProps) => (
|
|
5
|
+
<svg
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
role="img"
|
|
8
|
+
viewBox="0 0 38 24"
|
|
9
|
+
aria-labelledby="pi-american_express"
|
|
10
|
+
{...props}
|
|
11
|
+
>
|
|
12
|
+
<title id="pi-american_express">American Express</title>
|
|
13
|
+
<g fill="none">
|
|
14
|
+
<path
|
|
15
|
+
fill="#000"
|
|
16
|
+
d="M35,0 L3,0 C1.3,0 0,1.3 0,3 L0,21 C0,22.7 1.4,24 3,24 L35,24 C36.7,24 38,22.7 38,21 L38,3 C38,1.3 36.6,0 35,0 Z"
|
|
17
|
+
opacity=".07"
|
|
18
|
+
/>
|
|
19
|
+
<path
|
|
20
|
+
fill="#006FCF"
|
|
21
|
+
d="M35,1 C36.1,1 37,1.9 37,3 L37,21 C37,22.1 36.1,23 35,23 L3,23 C1.9,23 1,22.1 1,21 L1,3 C1,1.9 1.9,1 3,1 L35,1"
|
|
22
|
+
/>
|
|
23
|
+
<path
|
|
24
|
+
fill="#FFF"
|
|
25
|
+
d="M8.971,10.268 L9.745,12.144 L8.203,12.144 L8.971,10.268 Z M25.046,10.346 L22.069,10.346 L22.069,11.173 L24.998,11.173 L24.998,12.412 L22.075,12.412 L22.075,13.334 L25.052,13.334 L25.052,14.073 L27.129,11.828 L25.052,9.488 L25.046,10.346 L25.046,10.346 Z M10.983,8.006 L14.978,8.006 L15.865,9.941 L16.687,8 L27.057,8 L28.135,9.19 L29.25,8 L34.013,8 L30.494,11.852 L33.977,15.68 L29.143,15.68 L28.065,14.49 L26.94,15.68 L10.03,15.68 L9.536,14.49 L8.406,14.49 L7.911,15.68 L4,15.68 L7.286,8 L10.716,8 L10.983,8.006 Z M19.646,9.084 L17.407,9.084 L15.907,12.62 L14.282,9.084 L12.06,9.084 L12.06,13.894 L10,9.084 L8.007,9.084 L5.625,14.596 L7.18,14.596 L7.674,13.406 L10.27,13.406 L10.764,14.596 L13.484,14.596 L13.484,10.661 L15.235,14.602 L16.425,14.602 L18.165,10.673 L18.165,14.603 L19.623,14.603 L19.647,9.083 L19.646,9.084 Z M28.986,11.852 L31.517,9.084 L29.695,9.084 L28.094,10.81 L26.546,9.084 L20.652,9.084 L20.652,14.602 L26.462,14.602 L28.076,12.864 L29.624,14.602 L31.499,14.602 L28.987,11.852 L28.986,11.852 Z"
|
|
26
|
+
/>
|
|
27
|
+
</g>
|
|
28
|
+
</svg>
|
|
29
|
+
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
export default Amex
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { type LucideProps } from 'lucide-react'
|
|
3
|
+
|
|
4
|
+
const DinersClub: React.FC<LucideProps> = (props: LucideProps) => (
|
|
5
|
+
<svg enableBackground="new 0 0 780 500" viewBox="0 0 780 500" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
6
|
+
<path d="m40 0h700c22.092 0 40 17.909 40 40v420c0 22.092-17.908 40-40 40h-700c-22.091 0-40-17.908-40-40v-420c0-22.091 17.909-40 40-40z" fill="#0079be"/>
|
|
7
|
+
<path d="m599.93 251.45c0-99.415-82.98-168.13-173.9-168.1h-78.242c-92.003-.033-167.73 68.705-167.73 168.1 0 90.93 75.727 165.64 167.73 165.2h78.242c90.914.436 173.9-74.294 173.9-165.2z" fill="#fff"/>
|
|
8
|
+
<path d="m348.28 97.43c-84.07.027-152.19 68.308-152.21 152.58.02 84.258 68.144 152.53 152.21 152.56 84.09-.027 152.23-68.303 152.24-152.56-.011-84.272-68.149-152.55-152.24-152.58z" fill="#0079be"/>
|
|
9
|
+
<path d="m252.07 249.6c.08-41.181 25.746-76.297 61.94-90.25v180.48c-36.194-13.948-61.861-49.045-61.94-90.23zm131 90.274v-180.53c36.207 13.92 61.914 49.057 61.979 90.257-.065 41.212-25.772 76.322-61.979 90.269z" fill="#fff"/>
|
|
10
|
+
</svg>
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export default DinersClub
|