@thorprovider/blocks 0.1.3 → 2.0.0

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 (178) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/README.md +228 -68
  3. package/docs/standards/data-contracts.md +13 -2
  4. package/package.json +26 -10
  5. package/scripts/fix-esm-extensions.mjs +40 -0
  6. package/src/blocks/application/login-forms/login-page.test.tsx +190 -0
  7. package/src/blocks/application/login-forms/login-page.tsx +240 -0
  8. package/src/blocks/application/password-recovery/forgot-password-page-1.tsx +6 -8
  9. package/src/blocks/application/signup-forms/signup-page-1.tsx +127 -129
  10. package/src/blocks/application/verification/verify-1.tsx +2 -2
  11. package/src/blocks/application/viewport-ownership.test.tsx +41 -0
  12. package/src/blocks/e-commerce/category-filters/category-listing-filter-fields.tsx +218 -0
  13. package/src/blocks/e-commerce/category-filters/{category-filter-2.test.tsx → category-listing.test.tsx} +287 -199
  14. package/src/blocks/e-commerce/category-filters/category-listing.tsx +934 -0
  15. package/src/blocks/e-commerce/checkout-forms/checkout-contact-step.tsx +149 -0
  16. package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-country-field.tsx → checkout-country-field.tsx} +10 -8
  17. package/src/blocks/e-commerce/checkout-forms/checkout-order-summary.tsx +230 -0
  18. package/src/blocks/e-commerce/checkout-forms/checkout-payment-step.tsx +100 -0
  19. package/src/blocks/e-commerce/checkout-forms/checkout-progress.tsx +62 -0
  20. package/src/blocks/e-commerce/checkout-forms/checkout-review-step.tsx +59 -0
  21. package/src/blocks/e-commerce/checkout-forms/{checkout-form-1-shipping-step.tsx → checkout-shipping-step.tsx} +65 -41
  22. package/src/blocks/e-commerce/checkout-forms/checkout.test.tsx +478 -0
  23. package/src/blocks/e-commerce/checkout-forms/checkout.tsx +550 -0
  24. package/src/blocks/e-commerce/navigation/storefront-navbar-account-menu.test.tsx +56 -0
  25. package/src/blocks/{marketing/navbars/navbar-4-account-menu.tsx → e-commerce/navigation/storefront-navbar-account-menu.tsx} +3 -3
  26. package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.test.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.test.tsx} +22 -22
  27. package/src/blocks/{marketing/navbars/navbar-4-cart-sheet.tsx → e-commerce/navigation/storefront-navbar-cart-sheet.tsx} +3 -3
  28. package/src/blocks/{marketing/navbars/navbar-4-mobile-nav.tsx → e-commerce/navigation/storefront-navbar-mobile-nav.tsx} +4 -12
  29. package/src/blocks/{marketing/navbars/navbar-4-search-bar.tsx → e-commerce/navigation/storefront-navbar-search-bar.tsx} +3 -3
  30. package/src/blocks/{marketing/navbars/navbar-4.test.tsx → e-commerce/navigation/storefront-navbar.test.tsx} +67 -36
  31. package/src/blocks/{marketing/navbars/navbar-4.tsx → e-commerce/navigation/storefront-navbar.tsx} +43 -25
  32. package/src/blocks/e-commerce/product-categories/category-card-grid.test.tsx +122 -0
  33. package/src/blocks/e-commerce/product-categories/category-card.test.tsx +68 -0
  34. package/src/blocks/e-commerce/product-categories/category-card.tsx +172 -0
  35. package/src/blocks/e-commerce/product-categories/category-grid.test.tsx +67 -0
  36. package/src/blocks/e-commerce/product-categories/category-shared.tsx +109 -0
  37. package/src/blocks/e-commerce/product-categories/product-category-grid.tsx +170 -0
  38. package/src/blocks/e-commerce/product-categories/product-category.test.tsx +266 -0
  39. package/src/blocks/e-commerce/product-categories/product-category.tsx +462 -0
  40. package/src/blocks/e-commerce/product-list/product-card.test.tsx +263 -0
  41. package/src/blocks/e-commerce/product-list/product-card.tsx +447 -0
  42. package/src/blocks/e-commerce/product-list/product-grid.test.tsx +162 -0
  43. package/src/blocks/e-commerce/product-list/product-grid.tsx +114 -0
  44. package/src/blocks/e-commerce/product-overview/product-overview-gallery.tsx +71 -0
  45. package/src/blocks/e-commerce/product-overview/{product-overview-5-lightbox-tab.tsx → product-overview-lightbox-tab.tsx} +35 -23
  46. package/src/blocks/e-commerce/product-overview/{product-overview-5-reviews-tab.tsx → product-overview-reviews-tab.tsx} +40 -17
  47. package/src/blocks/e-commerce/product-overview/{product-overview-5-tabs.tsx → product-overview-tabs.tsx} +8 -7
  48. package/src/blocks/e-commerce/product-overview/product-overview.test.tsx +283 -0
  49. package/src/blocks/e-commerce/product-overview/product-overview.tsx +1186 -0
  50. package/src/blocks/e-commerce/reviews/review-rating-2.tsx +5 -6
  51. package/src/blocks/e-commerce/shopping-carts/shopping-cart.test.tsx +399 -0
  52. package/src/blocks/e-commerce/shopping-carts/{shopping-cart-4.tsx → shopping-cart.tsx} +119 -85
  53. package/src/blocks/e-commerce/storefront-hero/storefront-hero.test.tsx +412 -0
  54. package/src/blocks/e-commerce/storefront-hero/storefront-hero.tsx +1283 -0
  55. package/src/blocks/marketing/features/feature.test.tsx +153 -0
  56. package/src/blocks/marketing/features/feature.tsx +195 -0
  57. package/src/blocks/marketing/footers/footer-section-accessibility.test.tsx +118 -0
  58. package/src/blocks/marketing/footers/footer-section-actions.test.tsx +131 -0
  59. package/src/blocks/marketing/footers/footer-section-data.test.tsx +127 -0
  60. package/src/blocks/marketing/footers/footer-section-native-links.test.tsx +100 -0
  61. package/src/blocks/marketing/footers/footer-section-public-api.test.tsx +11 -0
  62. package/src/blocks/marketing/footers/footer-section.test.tsx +46 -0
  63. package/src/blocks/marketing/footers/footer-section.tsx +532 -0
  64. package/src/blocks/marketing/navbars/navbar-public-api.test.tsx +57 -0
  65. package/src/blocks/marketing/navbars/navbar.mega.test.tsx +149 -0
  66. package/src/blocks/marketing/navbars/navbar.test.tsx +155 -0
  67. package/src/blocks/marketing/navbars/navbar.tsx +735 -0
  68. package/src/blocks/marketing/testimonials/testimonial-section.test.tsx +171 -0
  69. package/src/blocks/marketing/testimonials/testimonial-section.tsx +237 -0
  70. package/src/index.ts +156 -128
  71. package/src/lib/contracts-curated.test.ts +47 -29
  72. package/src/lib/contracts.test.ts +198 -2
  73. package/src/lib/contracts.ts +410 -16
  74. package/src/ui/button-group.tsx +1 -1
  75. package/src/ui/carousel.tsx +1 -1
  76. package/src/ui/dialog.tsx +1 -1
  77. package/src/ui/field.tsx +2 -2
  78. package/src/ui/input-group.tsx +3 -3
  79. package/src/ui/pagination.tsx +1 -1
  80. package/src/ui/sidebar.tsx +7 -7
  81. package/src/ui/toggle-group.tsx +1 -1
  82. package/tsconfig.build.json +12 -0
  83. package/tsup.config.ts +11 -7
  84. package/.turbo/turbo-build.log +0 -24
  85. package/.turbo/turbo-test.log +0 -47
  86. package/.turbo/turbo-type-check.log +0 -0
  87. package/dist/.tsbuildinfo +0 -1
  88. package/dist/contracts.d.mts +0 -1732
  89. package/dist/contracts.d.ts +0 -1732
  90. package/dist/contracts.js +0 -423
  91. package/dist/contracts.js.map +0 -1
  92. package/dist/contracts.mjs +0 -365
  93. package/dist/contracts.mjs.map +0 -1
  94. package/dist/index.d.mts +0 -3068
  95. package/dist/index.d.ts +0 -3068
  96. package/dist/index.js +0 -17834
  97. package/dist/index.js.map +0 -1
  98. package/dist/index.mjs +0 -17740
  99. package/dist/index.mjs.map +0 -1
  100. package/src/blocks/application/login-forms/login-page-1.tsx +0 -246
  101. package/src/blocks/application/login-forms/login-page-2.tsx +0 -207
  102. package/src/blocks/e-commerce/category-filters/category-filter-1.tsx +0 -260
  103. package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +0 -222
  104. package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +0 -921
  105. package/src/blocks/e-commerce/category-filters/category-filter-4-chip-rail.tsx +0 -57
  106. package/src/blocks/e-commerce/category-filters/category-filter-4-drawer.tsx +0 -124
  107. package/src/blocks/e-commerce/category-filters/category-filter-4-fields.tsx +0 -170
  108. package/src/blocks/e-commerce/category-filters/category-filter-4-sidebar.tsx +0 -52
  109. package/src/blocks/e-commerce/category-filters/category-filter-4-sort-sheet.tsx +0 -57
  110. package/src/blocks/e-commerce/category-filters/category-filter-4-state.ts +0 -68
  111. package/src/blocks/e-commerce/category-filters/category-filter-4.tsx +0 -298
  112. package/src/blocks/e-commerce/checkout-forms/card-formatting.test.ts +0 -47
  113. package/src/blocks/e-commerce/checkout-forms/card-formatting.ts +0 -9
  114. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-contact-step.tsx +0 -96
  115. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +0 -252
  116. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +0 -188
  117. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-progress.tsx +0 -36
  118. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +0 -216
  119. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +0 -338
  120. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-order-summary.tsx +0 -130
  121. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-payment-card.tsx +0 -175
  122. package/src/blocks/e-commerce/checkout-forms/checkout-form-2-shipping-card.tsx +0 -190
  123. package/src/blocks/e-commerce/checkout-forms/checkout-form-2.tsx +0 -312
  124. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-information-step.tsx +0 -91
  125. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-order-summary.tsx +0 -110
  126. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-payment-step.tsx +0 -137
  127. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-progress.tsx +0 -68
  128. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-review-step.tsx +0 -79
  129. package/src/blocks/e-commerce/checkout-forms/checkout-form-3-shipping-step.tsx +0 -172
  130. package/src/blocks/e-commerce/checkout-forms/checkout-form-3.tsx +0 -392
  131. package/src/blocks/e-commerce/product-categories/avatar-group.tsx +0 -86
  132. package/src/blocks/e-commerce/product-categories/product-category-1.tsx +0 -126
  133. package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +0 -51
  134. package/src/blocks/e-commerce/product-categories/product-category-2.tsx +0 -120
  135. package/src/blocks/e-commerce/product-categories/product-category-4.tsx +0 -129
  136. package/src/blocks/e-commerce/product-categories/product-category-5.tsx +0 -218
  137. package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +0 -88
  138. package/src/blocks/e-commerce/product-list/product-card-1.tsx +0 -192
  139. package/src/blocks/e-commerce/product-list/product-card-2.tsx +0 -71
  140. package/src/blocks/e-commerce/product-list/product-card-3-reaction-toggle.tsx +0 -166
  141. package/src/blocks/e-commerce/product-list/product-card-3.tsx +0 -215
  142. package/src/blocks/e-commerce/product-list/product-card-5-checkbox-check.tsx +0 -98
  143. package/src/blocks/e-commerce/product-list/product-card-5-reaction-toggle.tsx +0 -171
  144. package/src/blocks/e-commerce/product-list/product-card-5.tsx +0 -367
  145. package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +0 -182
  146. package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +0 -370
  147. package/src/blocks/e-commerce/product-overview/product-overview-2.tsx +0 -272
  148. package/src/blocks/e-commerce/product-overview/product-overview-5-gallery.tsx +0 -59
  149. package/src/blocks/e-commerce/product-overview/product-overview-5.tsx +0 -274
  150. package/src/blocks/e-commerce/shopping-carts/shopping-cart-1-spinning-counter.tsx +0 -142
  151. package/src/blocks/e-commerce/shopping-carts/shopping-cart-1.tsx +0 -291
  152. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-item-row.tsx +0 -110
  153. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-recommendations.tsx +0 -51
  154. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2-spinning-counter.tsx +0 -146
  155. package/src/blocks/e-commerce/shopping-carts/shopping-cart-2.tsx +0 -295
  156. package/src/blocks/e-commerce/shopping-carts/shopping-cart-3-spinning-counter.tsx +0 -142
  157. package/src/blocks/e-commerce/shopping-carts/shopping-cart-3.tsx +0 -342
  158. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4-spinning-counter.tsx +0 -146
  159. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +0 -229
  160. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +0 -72
  161. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +0 -263
  162. package/src/blocks/e-commerce/storefront-hero/storefront-hero-2.tsx +0 -283
  163. package/src/blocks/e-commerce/storefront-hero/storefront-hero-5.tsx +0 -318
  164. package/src/blocks/e-commerce/storefront-hero/storefront-hero-6.tsx +0 -205
  165. package/src/blocks/marketing/features/feature-1.tsx +0 -97
  166. package/src/blocks/marketing/features/feature-2.tsx +0 -82
  167. package/src/blocks/marketing/footers/footer-section-1.test.tsx +0 -117
  168. package/src/blocks/marketing/footers/footer-section-1.tsx +0 -178
  169. package/src/blocks/marketing/footers/footer-section-3.tsx +0 -192
  170. package/src/blocks/marketing/footers/footer-section-4.tsx +0 -355
  171. package/src/blocks/marketing/navbars/navbar-1.tsx +0 -267
  172. package/src/blocks/marketing/navbars/navbar-2.tsx +0 -351
  173. package/src/blocks/marketing/navbars/navbar-3.tsx +0 -303
  174. package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +0 -38
  175. package/src/blocks/marketing/navbars/navbar-4-like-button.tsx +0 -177
  176. package/src/blocks/marketing/navbars/navbar-4-product-grid.tsx +0 -219
  177. package/src/blocks/marketing/testimonials/testimonial-1.tsx +0 -141
  178. package/src/blocks/marketing/testimonials/testimonial-2.tsx +0 -108
@@ -1,137 +0,0 @@
1
- 'use client'
2
-
3
- import { CreditCard, Shield } from 'lucide-react'
4
-
5
- import { Field, FieldGroup, FieldLabel, FieldLegend, FieldSet } from '../../../ui/field'
6
- import { Input } from '../../../ui/input'
7
- import { RadioGroup, RadioGroupItem } from '../../../ui/radio-group'
8
-
9
- import type { PaymentMethod } from '@thorprovider/types'
10
- import type { CheckoutForm3ChangeHandler, CheckoutForm3FormData } from './checkout-form-3'
11
-
12
- interface CheckoutForm3PaymentStepProps {
13
- formData: CheckoutForm3FormData
14
- onChange: CheckoutForm3ChangeHandler
15
- paymentMethods: PaymentMethod[]
16
- paymentLabel: string
17
- noMethodsLabel: string
18
- cardNumberLabel: string
19
- expiryLabel: string
20
- cvvLabel: string
21
- cardNameLabel: string
22
- securePaymentLabel: string
23
- }
24
-
25
- export function CheckoutForm3PaymentStep({
26
- formData,
27
- onChange,
28
- paymentMethods,
29
- paymentLabel,
30
- noMethodsLabel,
31
- cardNumberLabel,
32
- expiryLabel,
33
- cvvLabel,
34
- cardNameLabel,
35
- securePaymentLabel,
36
- }: CheckoutForm3PaymentStepProps) {
37
- const selectedMethod = paymentMethods.find(method => method.id === formData.paymentMethod)
38
- const isCard = selectedMethod?.type === 'card'
39
-
40
- return (
41
- <div className='flex flex-col gap-6'>
42
- <FieldSet className='gap-4'>
43
- <FieldLegend className='flex items-center gap-2 text-base font-medium'>
44
- <CreditCard className='size-4' aria-hidden='true' />
45
- {paymentLabel}
46
- </FieldLegend>
47
-
48
- {paymentMethods.length === 0 ? (
49
- <p className='text-muted-foreground text-sm'>{noMethodsLabel}</p>
50
- ) : (
51
- <RadioGroup value={formData.paymentMethod} onValueChange={value => value && onChange('paymentMethod', value)}>
52
- {paymentMethods.map(method => (
53
- <Field key={method.id} orientation='horizontal' className='rounded-lg border p-4'>
54
- <RadioGroupItem value={method.id} id={method.id} />
55
- <FieldLabel htmlFor={method.id} className='flex flex-1 flex-col gap-0.5 font-normal'>
56
- <span className='flex items-center gap-2'>
57
- {method.logo ? (
58
- // eslint-disable-next-line @next/next/no-img-element
59
- <img src={method.logo} alt='' className='size-4 object-contain' />
60
- ) : (
61
- <CreditCard className='size-4' aria-hidden='true' />
62
- )}
63
- {method.name}
64
- </span>
65
- {method.description ? (
66
- <span className='text-muted-foreground text-xs'>{method.description}</span>
67
- ) : null}
68
- </FieldLabel>
69
- </Field>
70
- ))}
71
- </RadioGroup>
72
- )}
73
- </FieldSet>
74
-
75
- {selectedMethod && !isCard ? (
76
- <div className='bg-muted/50 rounded-lg p-4 text-sm'>
77
- <p className='font-medium'>{selectedMethod.name}</p>
78
- {selectedMethod.description ? <p className='text-muted-foreground mt-1'>{selectedMethod.description}</p> : null}
79
- </div>
80
- ) : null}
81
-
82
- {isCard ? (
83
- <div className='rounded-lg border p-4'>
84
- <FieldGroup>
85
- <Field>
86
- <FieldLabel htmlFor='cardNumber'>{cardNumberLabel} *</FieldLabel>
87
- <Input
88
- id='cardNumber'
89
- placeholder='1234 5678 9012 3456'
90
- className='h-9 font-mono'
91
- value={formData.cardNumber}
92
- onChange={event => onChange('cardNumber', event.target.value)}
93
- />
94
- </Field>
95
- <div className='grid gap-4 sm:grid-cols-3'>
96
- <Field className='sm:col-span-2'>
97
- <FieldLabel htmlFor='expiryDate'>{expiryLabel} *</FieldLabel>
98
- <Input
99
- id='expiryDate'
100
- placeholder='MM/AA'
101
- className='h-9 font-mono'
102
- value={formData.expiryDate}
103
- onChange={event => onChange('expiryDate', event.target.value)}
104
- />
105
- </Field>
106
- <Field>
107
- <FieldLabel htmlFor='cvv'>{cvvLabel} *</FieldLabel>
108
- <Input
109
- id='cvv'
110
- placeholder='123'
111
- className='h-9 font-mono'
112
- value={formData.cvv}
113
- onChange={event => onChange('cvv', event.target.value)}
114
- />
115
- </Field>
116
- </div>
117
- <Field>
118
- <FieldLabel htmlFor='cardName'>{cardNameLabel} *</FieldLabel>
119
- <Input
120
- id='cardName'
121
- placeholder='Juan Pérez'
122
- value={formData.cardName}
123
- onChange={event => onChange('cardName', event.target.value)}
124
- className='h-9'
125
- />
126
- </Field>
127
- </FieldGroup>
128
- </div>
129
- ) : null}
130
-
131
- <div className='bg-muted/50 flex items-center gap-2 rounded-lg p-3 text-sm'>
132
- <Shield className='size-4 text-success' aria-hidden='true' />
133
- <span>{securePaymentLabel}</span>
134
- </div>
135
- </div>
136
- )
137
- }
@@ -1,68 +0,0 @@
1
- 'use client'
2
-
3
- import { Check, CreditCard, Package, Truck, User } from 'lucide-react'
4
- import type { LucideIcon } from 'lucide-react'
5
-
6
- import { cn } from '../../../lib/utils'
7
-
8
- import type { CheckoutForm3Step } from './checkout-form-3'
9
-
10
- export const CHECKOUT_FORM_3_STEP_ICONS: LucideIcon[] = [User, Truck, CreditCard, Package]
11
-
12
- interface CheckoutForm3ProgressProps {
13
- steps: CheckoutForm3Step[]
14
- currentStep: number
15
- isStepComplete: (stepNumber: number) => boolean
16
- }
17
-
18
- export function CheckoutForm3Progress({ steps, currentStep, isStepComplete }: CheckoutForm3ProgressProps) {
19
- return (
20
- <div className='mb-8'>
21
- <div className='flex items-center justify-between'>
22
- {steps.map((step, index) => {
23
- const Icon = CHECKOUT_FORM_3_STEP_ICONS[index]
24
- const isActive = step.id === currentStep
25
- const isCompleted = isStepComplete(step.id)
26
-
27
- return (
28
- <div key={step.id} className='flex flex-1 items-center'>
29
- <div className='flex flex-col items-center'>
30
- <div
31
- aria-current={isActive ? 'step' : undefined}
32
- className={cn(
33
- 'flex size-10 items-center justify-center rounded-full border-2 transition-colors',
34
- isCompleted
35
- ? 'border-primary bg-primary text-primary-foreground'
36
- : isActive
37
- ? 'border-primary bg-background text-primary'
38
- : 'border-muted bg-background text-muted-foreground',
39
- )}
40
- >
41
- {isCompleted ? (
42
- <Check className='size-5' aria-hidden='true' />
43
- ) : Icon ? (
44
- <Icon className='size-5' aria-hidden='true' />
45
- ) : null}
46
- </div>
47
- <span
48
- className={cn(
49
- 'mt-2 text-center text-xs font-medium',
50
- isActive ? 'text-primary' : 'text-muted-foreground',
51
- )}
52
- >
53
- {step.name}
54
- </span>
55
- </div>
56
- {index < steps.length - 1 ? (
57
- <div
58
- aria-hidden='true'
59
- className={cn('mx-4 h-px flex-1 transition-colors', isCompleted ? 'bg-primary' : 'bg-muted')}
60
- />
61
- ) : null}
62
- </div>
63
- )
64
- })}
65
- </div>
66
- </div>
67
- )
68
- }
@@ -1,79 +0,0 @@
1
- 'use client'
2
-
3
- import { CheckboxCheck } from './checkbox-check'
4
- import { Field, FieldLabel } from '../../../ui/field'
5
-
6
- import type { PaymentMethod } from '@thorprovider/types'
7
- import type {
8
- CheckoutForm3ChangeHandler,
9
- CheckoutForm3FormData,
10
- CheckoutForm3ShippingMethod,
11
- } from './checkout-form-3'
12
-
13
- interface CheckoutForm3ReviewStepProps {
14
- formData: CheckoutForm3FormData
15
- onChange: CheckoutForm3ChangeHandler
16
- shippingMethods: CheckoutForm3ShippingMethod[]
17
- paymentMethods: PaymentMethod[]
18
- orderReviewLabel: string
19
- contactReviewLabel: string
20
- shipToReviewLabel: string
21
- paymentReviewLabel: string
22
- shippingReviewLabel: string
23
- saveInfoLabel: string
24
- }
25
-
26
- export function CheckoutForm3ReviewStep({
27
- formData,
28
- onChange,
29
- shippingMethods,
30
- paymentMethods,
31
- orderReviewLabel,
32
- contactReviewLabel,
33
- shipToReviewLabel,
34
- paymentReviewLabel,
35
- shippingReviewLabel,
36
- saveInfoLabel,
37
- }: CheckoutForm3ReviewStepProps) {
38
- const shippingName = shippingMethods.find(method => method.id === formData.shippingMethod)?.name
39
- const paymentMethodName = paymentMethods.find(method => method.id === formData.paymentMethod)?.name
40
-
41
- return (
42
- <div className='flex flex-col gap-6'>
43
- <div className='bg-muted/50 rounded-lg p-6'>
44
- <h3 className='mb-4 font-medium'>{orderReviewLabel}</h3>
45
- <dl className='flex flex-col gap-4 text-sm'>
46
- <div>
47
- <dt className='inline font-medium'>{contactReviewLabel}: </dt>
48
- <dd className='inline'>{formData.email}</dd>
49
- </div>
50
- <div>
51
- <dt className='inline font-medium'>{shipToReviewLabel}: </dt>
52
- <dd className='inline'>
53
- {formData.firstName} {formData.lastName}, {formData.address}, {formData.city} {formData.zipCode}
54
- </dd>
55
- </div>
56
- <div>
57
- <dt className='inline font-medium'>{paymentReviewLabel}: </dt>
58
- <dd className='inline'>{paymentMethodName}</dd>
59
- </div>
60
- <div>
61
- <dt className='inline font-medium'>{shippingReviewLabel}: </dt>
62
- <dd className='inline'>{shippingName}</dd>
63
- </div>
64
- </dl>
65
- </div>
66
-
67
- <Field orientation='horizontal'>
68
- <CheckboxCheck
69
- id='saveInfo'
70
- checked={formData.saveInfo}
71
- onCheckedChange={checked => onChange('saveInfo', checked as boolean)}
72
- />
73
- <FieldLabel htmlFor='saveInfo' className='text-sm font-normal'>
74
- {saveInfoLabel}
75
- </FieldLabel>
76
- </Field>
77
- </div>
78
- )
79
- }
@@ -1,172 +0,0 @@
1
- 'use client'
2
-
3
- import { MapPin, Truck } from 'lucide-react'
4
-
5
- import { Field, FieldGroup, FieldLabel, FieldLegend, FieldSet } from '../../../ui/field'
6
- import { Input } from '../../../ui/input'
7
- import { RadioGroup, RadioGroupItem } from '../../../ui/radio-group'
8
- import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '../../../ui/select'
9
- import { Separator } from '../../../ui/separator'
10
-
11
- import type {
12
- CheckoutForm3ChangeHandler,
13
- CheckoutForm3CountryOption,
14
- CheckoutForm3FormData,
15
- CheckoutForm3ShippingMethod,
16
- } from './checkout-form-3'
17
-
18
- interface CheckoutForm3ShippingStepProps {
19
- formData: CheckoutForm3FormData
20
- onChange: CheckoutForm3ChangeHandler
21
- countryOptions: CheckoutForm3CountryOption[]
22
- shippingMethods: CheckoutForm3ShippingMethod[]
23
- shippingAddressLabel: string
24
- addressLabel: string
25
- apartmentLabel: string
26
- cityLabel: string
27
- stateLabel: string
28
- zipCodeLabel: string
29
- countryLabel: string
30
- shippingMethodLabel: string
31
- freeLabel: string
32
- currencySymbol: string
33
- }
34
-
35
- const countryLabelFor = (value: string, options: CheckoutForm3CountryOption[]) =>
36
- options.find(option => option.value === value)?.label ?? value
37
-
38
- export function CheckoutForm3ShippingStep({
39
- formData,
40
- onChange,
41
- countryOptions,
42
- shippingMethods,
43
- shippingAddressLabel,
44
- addressLabel,
45
- apartmentLabel,
46
- cityLabel,
47
- stateLabel,
48
- zipCodeLabel,
49
- countryLabel,
50
- shippingMethodLabel,
51
- freeLabel,
52
- currencySymbol,
53
- }: CheckoutForm3ShippingStepProps) {
54
- return (
55
- <div className='flex flex-col gap-6'>
56
- <div className='flex flex-col gap-4'>
57
- <h3 className='flex items-center gap-2 font-medium'>
58
- <MapPin className='size-4' aria-hidden='true' />
59
- {shippingAddressLabel}
60
- </h3>
61
-
62
- <FieldGroup>
63
- <Field>
64
- <FieldLabel htmlFor='address'>{addressLabel} *</FieldLabel>
65
- <Input
66
- id='address'
67
- placeholder='Calle Principal 123'
68
- value={formData.address}
69
- onChange={event => onChange('address', event.target.value)}
70
- required
71
- className='h-9'
72
- />
73
- </Field>
74
-
75
- <Field>
76
- <FieldLabel htmlFor='apartment'>{apartmentLabel}</FieldLabel>
77
- <Input
78
- id='apartment'
79
- placeholder='Piso 4B'
80
- value={formData.apartment}
81
- onChange={event => onChange('apartment', event.target.value)}
82
- className='h-9'
83
- />
84
- </Field>
85
-
86
- <div className='grid gap-4 sm:grid-cols-3'>
87
- <Field>
88
- <FieldLabel htmlFor='city'>{cityLabel} *</FieldLabel>
89
- <Input
90
- id='city'
91
- placeholder='Madrid'
92
- value={formData.city}
93
- onChange={event => onChange('city', event.target.value)}
94
- required
95
- className='h-9'
96
- />
97
- </Field>
98
- <Field>
99
- <FieldLabel htmlFor='state'>{stateLabel}</FieldLabel>
100
- <Input
101
- id='state'
102
- placeholder='Madrid'
103
- value={formData.state}
104
- onChange={event => onChange('state', event.target.value)}
105
- className='h-9'
106
- />
107
- </Field>
108
- <Field>
109
- <FieldLabel htmlFor='zipCode'>{zipCodeLabel} *</FieldLabel>
110
- <Input
111
- id='zipCode'
112
- placeholder='28001'
113
- value={formData.zipCode}
114
- onChange={event => onChange('zipCode', event.target.value)}
115
- required
116
- className='h-9'
117
- />
118
- </Field>
119
- </div>
120
-
121
- <Field>
122
- <FieldLabel htmlFor='country'>{countryLabel}</FieldLabel>
123
- <Select value={formData.country} onValueChange={value => value && onChange('country', value)}>
124
- <SelectTrigger id='country' className='!h-9 w-full'>
125
- <SelectValue>{countryLabelFor(formData.country, countryOptions)}</SelectValue>
126
- </SelectTrigger>
127
- <SelectContent>
128
- <SelectGroup>
129
- {countryOptions.map(country => (
130
- <SelectItem key={country.value} value={country.value}>
131
- {country.label}
132
- </SelectItem>
133
- ))}
134
- </SelectGroup>
135
- </SelectContent>
136
- </Select>
137
- </Field>
138
- </FieldGroup>
139
- </div>
140
-
141
- <Separator />
142
-
143
- <FieldSet className='gap-4'>
144
- <FieldLegend className='flex items-center gap-2 text-base font-medium'>
145
- <Truck className='size-4' aria-hidden='true' />
146
- {shippingMethodLabel}
147
- </FieldLegend>
148
- <RadioGroup
149
- value={formData.shippingMethod}
150
- onValueChange={value => value && onChange('shippingMethod', value)}
151
- >
152
- {shippingMethods.map(method => (
153
- <div key={method.id} className='flex items-center justify-between rounded-lg border p-4'>
154
- <Field orientation='horizontal' className='w-auto'>
155
- <RadioGroupItem value={method.id} id={method.id} />
156
- <FieldLabel htmlFor={method.id} className='font-normal'>
157
- <div>
158
- <div className='font-medium'>{method.name}</div>
159
- <div className='text-muted-foreground text-sm'>{method.description}</div>
160
- </div>
161
- </FieldLabel>
162
- </Field>
163
- <div className='font-medium'>
164
- {method.cost === 0 ? freeLabel : `${currencySymbol}${method.cost.toFixed(2)}`}
165
- </div>
166
- </div>
167
- ))}
168
- </RadioGroup>
169
- </FieldSet>
170
- </div>
171
- )
172
- }