@hanzo/commerce 7.7.1 → 7.7.3

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.
Files changed (91) hide show
  1. package/dist/components/cart/cart-panel/promo-code.d.ts +2 -2
  2. package/dist/service/impls/standalone/index.js +4 -4
  3. package/dist/service/impls/standalone/index.js.map +1 -1
  4. package/package.json +46 -17
  5. package/billing.ts +0 -2
  6. package/client.ts +0 -783
  7. package/components/Icons.tsx +0 -35
  8. package/components/add-to-cart-widget.tsx +0 -195
  9. package/components/buy/buy-card.tsx +0 -269
  10. package/components/buy/carousel-buy-card.tsx +0 -243
  11. package/components/buy/multi-family/all-variants-carousel.tsx +0 -259
  12. package/components/buy/multi-family/family-carousel/index.tsx +0 -75
  13. package/components/buy/multi-family/family-carousel/slide.tsx +0 -82
  14. package/components/buy/multi-family/family-carousel/state.ts +0 -87
  15. package/components/buy/multi-family/index.ts +0 -2
  16. package/components/buy/single-family-selector.tsx +0 -91
  17. package/components/buy/title-and-byline.tsx +0 -26
  18. package/components/cart/cart-panel/cart-line-item.tsx +0 -77
  19. package/components/cart/cart-panel/index.tsx +0 -157
  20. package/components/cart/cart-panel/promo-code.tsx +0 -105
  21. package/components/cart/cart-panel/total-area.tsx +0 -61
  22. package/components/checkout/payment-step-form/card-icon-row.tsx +0 -26
  23. package/components/checkout/payment-step-form/card-icons/amex.tsx +0 -32
  24. package/components/checkout/payment-step-form/card-icons/diners-club.tsx +0 -13
  25. package/components/checkout/payment-step-form/card-icons/discover.tsx +0 -25
  26. package/components/checkout/payment-step-form/card-icons/jcb.tsx +0 -26
  27. package/components/checkout/payment-step-form/card-icons/mastercard.tsx +0 -27
  28. package/components/checkout/payment-step-form/card-icons/visa.tsx +0 -25
  29. package/components/checkout/payment-step-form/cc-button.tsx +0 -18
  30. package/components/checkout/payment-step-form/contact-form.tsx +0 -48
  31. package/components/checkout/payment-step-form/crypto-icons/btc.tsx +0 -11
  32. package/components/checkout/payment-step-form/crypto-icons/eth.tsx +0 -20
  33. package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +0 -13
  34. package/components/checkout/payment-step-form/index.tsx +0 -113
  35. package/components/checkout/payment-step-form/methods/bank-transfer.tsx +0 -81
  36. package/components/checkout/payment-step-form/methods/card.tsx +0 -253
  37. package/components/checkout/payment-step-form/methods/crypto.tsx +0 -226
  38. package/components/checkout/payment-step-form/methods/index.ts +0 -23
  39. package/components/checkout/shipping-step-form.tsx +0 -171
  40. package/components/index.ts +0 -11
  41. package/components/item/product-card.tsx +0 -66
  42. package/components/item-selector/button.tsx +0 -213
  43. package/components/item-selector/carousel/index.tsx +0 -196
  44. package/components/item-selector/carousel/slider.tsx +0 -37
  45. package/components/item-selector/index.ts +0 -5
  46. package/components/item-selector/quantity-indicator.tsx +0 -50
  47. package/components/node-tabs/index.tsx +0 -90
  48. package/components/node-tabs/node-image.tsx +0 -31
  49. package/index.ts +0 -55
  50. package/metering.test.ts +0 -199
  51. package/metering.ts +0 -289
  52. package/product-card.test.tsx +0 -104
  53. package/service/context.tsx +0 -45
  54. package/service/debug.ts +0 -41
  55. package/service/impls/standalone/actual-line-item.ts +0 -136
  56. package/service/impls/standalone/get-instance.ts +0 -64
  57. package/service/impls/standalone/index.ts +0 -579
  58. package/service/impls/standalone/order/firebase.ts +0 -5
  59. package/service/impls/standalone/order/index.ts +0 -58
  60. package/service/impls/standalone/persistence.ts +0 -33
  61. package/service/path-utils.ts +0 -26
  62. package/service/sep.ts +0 -7
  63. package/tsconfig.json +0 -17
  64. package/types/README.md +0 -2
  65. package/types/category-node.ts +0 -50
  66. package/types/checkout.ts +0 -47
  67. package/types/commerce-config.ts +0 -13
  68. package/types/commerce-service.ts +0 -128
  69. package/types/family.ts +0 -26
  70. package/types/index.ts +0 -15
  71. package/types/item-selector.ts +0 -97
  72. package/types/line-item.ts +0 -29
  73. package/types/multi-family-selector-props.ts +0 -20
  74. package/types/product.ts +0 -21
  75. package/types/promo.ts +0 -10
  76. package/types/selection-ui-specifier.ts +0 -52
  77. package/types/string-mutator.ts +0 -14
  78. package/types/token-separators.ts +0 -7
  79. package/util/analytics.ts +0 -21
  80. package/util/countries.ts +0 -196
  81. package/util/error.ts +0 -34
  82. package/util/index.ts +0 -71
  83. package/util/item-selector-options-accessor.ts +0 -35
  84. package/util/line-item-ref.ts +0 -23
  85. package/util/multi-family-selector-options-accessor.ts +0 -15
  86. package/util/obs-string-mutator.ts +0 -22
  87. package/util/product-media-accessor.ts +0 -58
  88. package/util/promo-codes.ts +0 -106
  89. package/util/selection-ui-specifiers.ts +0 -30
  90. package/util/square-payment.ts +0 -50
  91. package/util/use-sync-sku-param-w-current-item.ts +0 -88
@@ -1,87 +0,0 @@
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
- }
@@ -1,2 +0,0 @@
1
- export { default as FamilyCarousel } from './family-carousel'
2
- export { default as AllVariantsCarousel } from './all-variants-carousel'
@@ -1,91 +0,0 @@
1
- import React from 'react'
2
- import { observer } from 'mobx-react-lite'
3
-
4
- import {
5
- MediaStack,
6
- Skeleton,
7
- cn,
8
- } from '@hanzo/ui'
9
- import type { Dimensions } from '@hanzo/ui/types'
10
-
11
- import { useCommerce } from '../..'
12
-
13
- import type { ItemSelectorOptions, ItemSelectorProps, LineItem } from '../../types'
14
- import TitleAndByline from './title-and-byline'
15
- import { accessItemOptions } from '../../util'
16
- const DEF_MEDIA_CONSTRAINT = {w: 200, h: 200}
17
-
18
- const SingleFamilySelector: React.FC<{
19
- items: LineItem[] // these may be sorted, so are we can't just use currentFamily.products
20
- Selector: React.ComponentType<ItemSelectorProps>
21
- selOptions: ItemSelectorOptions | undefined
22
- scrollable?: boolean
23
- showItemMedia?: boolean
24
- mediaConstraint?: Dimensions
25
- mobile?: boolean
26
- clx?: string
27
- titleAreaClx?: string
28
- }> = ({
29
- items,
30
- Selector,
31
- selOptions,
32
- scrollable=false,
33
- showItemMedia=true,
34
- mediaConstraint=DEF_MEDIA_CONSTRAINT,
35
- mobile=false,
36
- clx='',
37
- titleAreaClx=''
38
- }) => {
39
-
40
- const cmmc = useCommerce()
41
-
42
-
43
- const MyTitleAndByline: React.FC<{clx?: string}> = observer(({
44
- clx=''
45
- }) => {
46
- const { familyTitle, showFamilyByline } = accessItemOptions(selOptions)
47
- const title = (familyTitle === 'none' ?
48
- undefined
49
- :
50
- (familyTitle === 'long' ?
51
- cmmc.currentFamily?.title
52
- :
53
- (cmmc.currentFamily?.titleShort ?? cmmc.currentFamily?.title)
54
- )
55
- )
56
- const byline = (familyTitle !== 'none') && showFamilyByline ? cmmc.currentFamily?.byline : undefined
57
- return ( <TitleAndByline clx={clx} title={title} byline={byline}/> )
58
- })
59
-
60
- const ItemMedia: React.FC = observer(() => (
61
- cmmc.currentItem ? (
62
- <MediaStack
63
- media={cmmc.currentItem!}
64
- constrainTo={mediaConstraint}
65
- className={'mb-2 ' + (scrollable ? 'shrink-0' : '')}
66
- />
67
- ) : (
68
- <Skeleton className={'w-[200px] h-[200px] my-2 ' + (scrollable ? 'shrink-0' : '')}/>
69
- )
70
- ))
71
-
72
- return (
73
- <div className={cn(clx, 'flex flex-col items-center', (scrollable ? 'shrink' : ''))}>
74
- <MyTitleAndByline clx={cn(titleAreaClx, (scrollable ? 'shrink-0' : ''))} />
75
- {showItemMedia && (<ItemMedia />)}
76
- {items && (
77
- <Selector
78
- items={items}
79
- selectedItemRef={cmmc}
80
- selectSku={cmmc.setCurrentItem.bind(cmmc)}
81
- scrollable={scrollable}
82
- mobile={mobile}
83
- options={selOptions}
84
- clx={(scrollable ? 'shrink' : '')}
85
- />
86
- )}
87
- </div>
88
- )
89
- }
90
-
91
- export default SingleFamilySelector
@@ -1,26 +0,0 @@
1
- import React from 'react'
2
-
3
- import {
4
- ApplyTypography,
5
- cn,
6
- } from '@hanzo/ui'
7
- const TitleAndByline: React.FC<{
8
- title: string | undefined
9
- byline?: string | undefined
10
- clx?: string
11
- bylineClx?: string
12
- }> = ({
13
- title,
14
- byline,
15
- clx='',
16
- bylineClx=''
17
- }) => ( (title || byline) ? (
18
- <ApplyTypography className={cn('flex flex-col items-center !gap-0 [&>*]:!m-0 ', clx)} >
19
- <h4>{title}</h4>
20
- {byline && (<h6 className={bylineClx}>{byline}</h6>)}
21
- </ApplyTypography>
22
- ) : (null)
23
- )
24
-
25
- export default TitleAndByline
26
-
@@ -1,77 +0,0 @@
1
- 'use client'
2
-
3
- import React from 'react'
4
- import { observer } from 'mobx-react-lite'
5
-
6
- import {
7
- cn,
8
- MediaStack,
9
- } from '@hanzo/ui'
10
- import type { LineItem } from '../../../types'
11
- import { formatCurrencyValue } from '../../../util'
12
- import AddToCartWidget from '../../add-to-cart-widget'
13
- import { useCommerce } from '../../../service/context'
14
-
15
- const DEF_IMG_SIZE=40
16
-
17
- const renderTitle = (t: string): React.ReactNode => {
18
- const toks = t.split(', ')
19
- if (toks.length === 2) {
20
- return <><p>{toks[0]},</p><p className=''>{toks[1]}</p></>
21
- }
22
- return <p>{t}</p>
23
- }
24
-
25
- const CartLineItem: React.FC<{
26
- item: LineItem
27
- className?: string
28
- imgSizePx?: number
29
- showPromoCode?: boolean
30
- itemClicked?: (item: LineItem) => void
31
- selected?: boolean
32
- }> = observer(({
33
- item,
34
- className='',
35
- imgSizePx=DEF_IMG_SIZE,
36
- showPromoCode=false,
37
- itemClicked,
38
- selected=false
39
- }) => {
40
-
41
- const cmmc = useCommerce()
42
- const promoPrice = showPromoCode ? cmmc.itemPromoPrice(item) : undefined
43
-
44
- return (
45
- <div
46
- className={cn(
47
- 'flex flex-col justify-start items-start text-sm font-sans',
48
- 'border border-background rounded-sm p-1',
49
- selected ? 'border-foreground' : '',
50
- (itemClicked && !selected ? 'cursor-pointer hover:!border-muted-4' : 'cursor-default '),
51
- className
52
- )}
53
- onClick={() => {itemClicked && itemClicked(item)}}
54
- >
55
- <div className='flex flex-row justify-between items-center gap-1' >
56
- {item.img ? (
57
- <MediaStack media={item} constrainTo={{w: imgSizePx, h: imgSizePx}} />
58
- ) : ( // placeholder so things align
59
- <div style={{height: imgSizePx, width: imgSizePx}} className='bg-level-3'/>
60
- )}
61
- <div className='grow leading-tight ml-1'>{renderTitle(item.title)}</div>
62
- </div>
63
- <div className='flex flex-row items-center justify-between w-full'>
64
- <div className='flex flex-row items-center'>
65
- <AddToCartWidget variant='minimal' item={item} />
66
- {item.quantity > 1 && (<span className='pl-2.5'>{'@' + formatCurrencyValue(item.price)}</span>)}
67
- </div>
68
- <div className='flex flex-row gap-1 items-center justify-end'>
69
- <span className={promoPrice ? 'line-through text-muted-2' : ''}>{formatCurrencyValue(item.price * item.quantity)}</span>
70
- {promoPrice && <span>{formatCurrencyValue(promoPrice * item.quantity)}</span>}
71
- </div>
72
- </div>
73
- </div>
74
- )
75
- })
76
-
77
- export default CartLineItem
@@ -1,157 +0,0 @@
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 {
7
- Button,
8
- ScrollArea,
9
- cn,
10
- sx,
11
- } from '@hanzo/ui'
12
- import type { LineItem } from '../../../types'
13
- import { useCommerce } from '../../../service/context'
14
- import { sendFBEvent, sendGAEvent } from '../../../util/analytics'
15
-
16
- import CartLineItem from './cart-line-item'
17
- import TotalArea from './total-area'
18
-
19
- const CartPanel: React.FC<PropsWithChildren & {
20
- /** fix size and scroll after 'scrollAfter items in teh cart. */
21
- scrollAfter?: number
22
- scrollHeightClx?: string
23
- imgSizePx?: number
24
- className?: string
25
- itemClx?: string
26
- listClx?: string
27
- noItemsClx?: string
28
- totalClx?: string
29
- buttonClx?: string
30
- showPromoCode?: boolean
31
- showShipping?: boolean
32
- selectItems?: boolean
33
- /** if not provided, 'checkout' button will be rendered */
34
- handleCheckout?: () => void
35
- }> = observer(({
36
- /** If provided, 'children' is rendered above the items. eg, a heading. */
37
- children,
38
- scrollAfter=5,
39
- scrollHeightClx='h-[70vh]',
40
- imgSizePx=40,
41
- className='',
42
- itemClx='',
43
- listClx='',
44
- noItemsClx='',
45
- totalClx='',
46
- buttonClx='',
47
- showPromoCode=false,
48
- showShipping=false,
49
- selectItems=false,
50
- handleCheckout,
51
- }) => {
52
-
53
- const cmmc = useCommerce()
54
-
55
- useLayoutEffect(() => {
56
- if (!cmmc) {
57
- return
58
- }
59
- if (!cmmc.cartEmpty && !cmmc.currentItem) {
60
- cmmc.setCurrentItem(cmmc.cartItems[0].sku)
61
- }
62
- // return mobx disposer
63
- return reaction(() => (
64
- cmmc.cartItems.length
65
- ),
66
- (itemCount) => {
67
- if (itemCount > 0) {
68
- cmmc.setCurrentItem(cmmc.cartItems[0].sku)
69
- }
70
- })
71
- }, [])
72
-
73
- if (!cmmc) {
74
- return <div />
75
- }
76
-
77
- const _handleCheckout = () => {
78
- sendGAEvent('begin_checkout', {
79
- currency: 'USD',
80
- value: cmmc.cartTotal,
81
- items: cmmc.cartItems.map((item) => ({
82
- item_id: item.sku,
83
- item_name: item.title,
84
- item_category: item.familyId,
85
- price: item.price,
86
- quantity: item.quantity
87
- })),
88
- })
89
- sendFBEvent('InitiateCheckout', {
90
- content_ids: cmmc.cartItems.map((item) => item.sku),
91
- contents: cmmc.cartItems.map(item => ({
92
- id: item.sku,
93
- quantity: item.quantity
94
- })),
95
- num_items: cmmc.cartItems.length,
96
- value: cmmc.cartTotal,
97
- currency: 'USD',
98
- })
99
- handleCheckout && handleCheckout()
100
- }
101
-
102
- const itemClicked = (item: LineItem) => {
103
- cmmc.setCurrentItem(item.sku)
104
- }
105
-
106
- const MainStuff: React.FC = observer(() => (<>
107
- {cmmc.cartEmpty ? (
108
- <p className={cn('text-center my-3', noItemsClx)}>No items</p>
109
- ) : (<>
110
- {cmmc.cartItems.map((item) => (
111
- <CartLineItem
112
- key={`mobile-${item.sku}`}
113
- imgSizePx={imgSizePx}
114
- item={item}
115
- className={cn('mb-2', itemClx)}
116
- showPromoCode={showPromoCode}
117
- itemClicked={selectItems ? itemClicked : undefined}
118
- selected={selectItems ? cmmc.currentItem?.sku === item.sku : false}
119
- />
120
- ))}
121
- </>)}
122
- <TotalArea clx={totalClx} showPromoCode={showPromoCode} showShipping={showShipping}/>
123
- </>))
124
-
125
- const scrolling = (cmmc.cartItems.length > scrollAfter)
126
-
127
- return (
128
- <div className={cn(
129
- 'border p-4 rounded-lg flex flex-col',
130
- className,
131
- scrolling ? scrollHeightClx : 'h-auto'
132
- )}>
133
- {children}
134
- {scrolling ? (
135
- <ScrollArea className={cn('mt-2 w-full shrink py-0', listClx)}>
136
- <MainStuff />
137
- </ScrollArea>
138
- ) : (
139
- <div className={cn('mt-2 w-full', listClx)}>
140
- <MainStuff />
141
- </div>
142
- )}
143
- {handleCheckout && !cmmc.cartEmpty && (
144
- <Button
145
- onClick={_handleCheckout}
146
- variant='primary'
147
- {...sx('rounded-lg')}
148
- className={cn('mt-12 mx-auto w-full sm:max-w-[220px]', buttonClx)}
149
- >
150
- Checkout
151
- </Button>
152
- )}
153
- </div>
154
- )
155
- })
156
-
157
- export default CartPanel
@@ -1,105 +0,0 @@
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
- Form,
16
- FormControl,
17
- FormField,
18
- FormItem,
19
- } from '@hanzo/ui'
20
- import { useCommerce } from '../../../service/context'
21
- import type { Promo } from '../../../types'
22
- import getPromoFromApi from '../../../util/promo-codes'
23
-
24
- const formSchema = z.object({
25
- code: z.string().min(1, 'Invalid code'),
26
- })
27
-
28
- const PromoCode = observer(() => {
29
- const cmmc = useCommerce()
30
- const searchParams = useSearchParams()
31
-
32
- const [codeAccepted, setCodeAccepted] = useState<boolean>(false)
33
-
34
- useEffect(() => {
35
- const code = searchParams.get('code')
36
- if (code) {
37
- getPromoFromApi(code).then((promo?: Promo) => {
38
- if (promo) {
39
- form.setValue('code', code)
40
- setCodeAccepted(true)
41
- cmmc.setAppliedPromo(promo)
42
- }
43
- })
44
- }
45
- }, [searchParams])
46
-
47
- useEffect(() => {
48
- if (cmmc.appliedPromo) {
49
- form.setValue('code', cmmc.appliedPromo.code)
50
- setCodeAccepted(true)
51
- }
52
- }, [cmmc.appliedPromo])
53
-
54
- const form = useForm<z.infer<typeof formSchema>>({
55
- resolver: zodResolver(formSchema as any),
56
- defaultValues: {
57
- code: '',
58
- },
59
- })
60
-
61
- const applyPromoCode = async (values: z.infer<typeof formSchema>) => {
62
- const { code } = values
63
- const promo = await getPromoFromApi(code)
64
- if (!promo) {
65
- form.setError('code', { message: 'Invalid code' })
66
- return
67
- }
68
- setCodeAccepted(true)
69
- cmmc.setAppliedPromo(promo)
70
- }
71
-
72
- const removePromoCode = () => {
73
- cmmc.setAppliedPromo(null)
74
- setCodeAccepted(false)
75
- }
76
-
77
- return (
78
- <div className='flex flex-col gap-2 border-t py-1'>
79
- <Form {...form}>
80
- <form onSubmit={form.handleSubmit(applyPromoCode)}>
81
- <div className='flex gap-2 items-center'>
82
- <FormField
83
- control={form.control}
84
- name='code'
85
- render={({ field }) => (
86
- <FormItem className='w-full'>
87
- <FormControl>
88
- <Input {...field} className='h-9' placeholder='Discount or invite code' onInput={removePromoCode}/>
89
- </FormControl>
90
- </FormItem>
91
- )}
92
- />
93
- {codeAccepted ? (
94
- <Check/>
95
- ) : (
96
- <Button variant='outline' className='!w-fit !min-w-0 font-inter text-muted text-sm'>Apply</Button>
97
- )}
98
- </div>
99
- </form>
100
- </Form>
101
- </div>
102
- )
103
- })
104
-
105
- export default PromoCode
@@ -1,61 +0,0 @@
1
- 'use client'
2
- import React, { Suspense } from 'react'
3
- import { observer } from 'mobx-react-lite'
4
-
5
- import {
6
- cn,
7
- } from '@hanzo/ui'
8
- import { formatCurrencyValue } from '../../../util'
9
- import PromoCode from './promo-code'
10
- import { useCommerce } from '../../../service/context'
11
-
12
- const TotalArea: React.FC<{
13
- showPromoCode?: boolean
14
- showShipping?: boolean
15
- clx?: string
16
- }> = observer(({
17
- showPromoCode=false,
18
- showShipping=false,
19
- clx
20
- }) => {
21
-
22
- const cmmc = useCommerce()
23
-
24
- return (
25
- <div className={clx}>
26
- {showPromoCode && (
27
- <Suspense>
28
- <PromoCode/>
29
- </Suspense>
30
- )}
31
- {(showShipping || showPromoCode) && (
32
- <div className={'flex flex-col gap-0.5 pb-1.5 text-sm ' + (!showPromoCode ? 'border-t pt-1.5' : '')} >
33
- <p className='flex justify-between'>
34
- <span className='text-muted-1'>Subtotal</span>
35
- <span className='font-semibold'>{cmmc.cartTotal === 0 ? '0' : formatCurrencyValue(cmmc.cartTotal)}</span>
36
- </p>
37
- {cmmc.promoAppliedCartTotal !== cmmc.cartTotal && (
38
- <p className='flex justify-between'>
39
- <span className='text-muted-1'>Promo Discount</span>
40
- <span className='font-semibold'>-{formatCurrencyValue(cmmc.cartTotal - cmmc.promoAppliedCartTotal)}</span>
41
- </p>
42
- )}
43
- {showShipping && (
44
- <p className='flex justify-between'>
45
- <span className='text-muted-1'>Shipping</span>
46
- <span className='font-semibold'>Free Global Shipping</span>
47
- </p>
48
- )}
49
- </div>
50
- )}
51
- <p className={cn('border-t py-2 flex justify-between')}>
52
- TOTAL
53
- <span className='font-semibold'>
54
- {formatCurrencyValue(showPromoCode ? cmmc.promoAppliedCartTotal : cmmc.cartTotal)}
55
- </span>
56
- </p>
57
- </div>
58
- )
59
- })
60
-
61
- export default TotalArea
@@ -1,26 +0,0 @@
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
@@ -1,32 +0,0 @@
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
@@ -1,13 +0,0 @@
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