@faststore/components 3.4.4 → 3.7.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 (62) hide show
  1. package/dist/cjs/hooks/index.d.ts +1 -0
  2. package/dist/cjs/hooks/index.js +3 -1
  3. package/dist/cjs/hooks/index.js.map +1 -1
  4. package/dist/cjs/hooks/useSKUMatrix.d.ts +1 -0
  5. package/dist/cjs/hooks/useSKUMatrix.js +14 -0
  6. package/dist/cjs/hooks/useSKUMatrix.js.map +1 -0
  7. package/dist/cjs/index.d.ts +2 -0
  8. package/dist/cjs/index.js +5 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/molecules/Breadcrumb/BreadcrumbBase.js +9 -4
  11. package/dist/cjs/molecules/Breadcrumb/BreadcrumbBase.js.map +1 -1
  12. package/dist/cjs/organisms/SKUMatrix/SKUMatrix.d.ts +9 -0
  13. package/dist/cjs/organisms/SKUMatrix/SKUMatrix.js +11 -0
  14. package/dist/cjs/organisms/SKUMatrix/SKUMatrix.js.map +1 -0
  15. package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.d.ts +45 -0
  16. package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js +93 -0
  17. package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -0
  18. package/dist/cjs/organisms/SKUMatrix/SKUMatrixTrigger.d.ts +5 -0
  19. package/dist/cjs/organisms/SKUMatrix/SKUMatrixTrigger.js +15 -0
  20. package/dist/cjs/organisms/SKUMatrix/SKUMatrixTrigger.js.map +1 -0
  21. package/dist/cjs/organisms/SKUMatrix/index.d.ts +6 -0
  22. package/dist/cjs/organisms/SKUMatrix/index.js +13 -0
  23. package/dist/cjs/organisms/SKUMatrix/index.js.map +1 -0
  24. package/dist/cjs/organisms/SKUMatrix/provider/SKUMatrixProvider.d.ts +49 -0
  25. package/dist/cjs/organisms/SKUMatrix/provider/SKUMatrixProvider.js +28 -0
  26. package/dist/cjs/organisms/SKUMatrix/provider/SKUMatrixProvider.js.map +1 -0
  27. package/dist/esm/hooks/index.d.ts +1 -0
  28. package/dist/esm/hooks/index.js +1 -0
  29. package/dist/esm/hooks/index.js.map +1 -1
  30. package/dist/esm/hooks/useSKUMatrix.d.ts +1 -0
  31. package/dist/esm/hooks/useSKUMatrix.js +10 -0
  32. package/dist/esm/hooks/useSKUMatrix.js.map +1 -0
  33. package/dist/esm/index.d.ts +2 -0
  34. package/dist/esm/index.js +1 -0
  35. package/dist/esm/index.js.map +1 -1
  36. package/dist/esm/molecules/Breadcrumb/BreadcrumbBase.js +10 -5
  37. package/dist/esm/molecules/Breadcrumb/BreadcrumbBase.js.map +1 -1
  38. package/dist/esm/organisms/SKUMatrix/SKUMatrix.d.ts +9 -0
  39. package/dist/esm/organisms/SKUMatrix/SKUMatrix.js +8 -0
  40. package/dist/esm/organisms/SKUMatrix/SKUMatrix.js.map +1 -0
  41. package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.d.ts +45 -0
  42. package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js +90 -0
  43. package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -0
  44. package/dist/esm/organisms/SKUMatrix/SKUMatrixTrigger.d.ts +5 -0
  45. package/dist/esm/organisms/SKUMatrix/SKUMatrixTrigger.js +12 -0
  46. package/dist/esm/organisms/SKUMatrix/SKUMatrixTrigger.js.map +1 -0
  47. package/dist/esm/organisms/SKUMatrix/index.d.ts +6 -0
  48. package/dist/esm/organisms/SKUMatrix/index.js +4 -0
  49. package/dist/esm/organisms/SKUMatrix/index.js.map +1 -0
  50. package/dist/esm/organisms/SKUMatrix/provider/SKUMatrixProvider.d.ts +49 -0
  51. package/dist/esm/organisms/SKUMatrix/provider/SKUMatrixProvider.js +24 -0
  52. package/dist/esm/organisms/SKUMatrix/provider/SKUMatrixProvider.js.map +1 -0
  53. package/package.json +4 -4
  54. package/src/hooks/index.ts +1 -2
  55. package/src/hooks/useSKUMatrix.ts +15 -0
  56. package/src/index.ts +11 -0
  57. package/src/molecules/Breadcrumb/BreadcrumbBase.tsx +52 -24
  58. package/src/organisms/SKUMatrix/SKUMatrix.tsx +22 -0
  59. package/src/organisms/SKUMatrix/SKUMatrixSidebar.tsx +297 -0
  60. package/src/organisms/SKUMatrix/SKUMatrixTrigger.tsx +31 -0
  61. package/src/organisms/SKUMatrix/index.ts +8 -0
  62. package/src/organisms/SKUMatrix/provider/SKUMatrixProvider.tsx +104 -0
@@ -0,0 +1,297 @@
1
+ import Image from 'next/image'
2
+ import React, { useMemo } from 'react'
3
+ import { Badge, Button, QuantitySelector, Skeleton } from '../..'
4
+ import Price, { PriceFormatter } from '../../atoms/Price'
5
+ import Icon from '../../atoms/Icon'
6
+ import { useFadeEffect, useSKUMatrix, useUI } from '../../hooks'
7
+ import {
8
+ Table,
9
+ TableBody,
10
+ TableCell,
11
+ TableHead,
12
+ TableRow,
13
+ } from '../../molecules/Table'
14
+ import SlideOver, { SlideOverHeader, SlideOverProps } from '../SlideOver'
15
+
16
+ interface VariationProductColumn {
17
+ name: string
18
+ additionalColumns: Array<{ label: string; value: string }>
19
+ availability: {
20
+ label: string
21
+ stockDisplaySettings: 'showStockQuantity' | 'showAvailability'
22
+ }
23
+ price: number
24
+ quantitySelector: number
25
+ }
26
+
27
+ export interface SKUMatrixSidebarProps
28
+ extends Omit<SlideOverProps, 'isOpen' | 'setIsOpen' | "fade"> {
29
+ /**
30
+ * Title for the SKUMatrixSidebar component.
31
+ */
32
+ title?: string
33
+ /**
34
+ * Represents the variations products to building the table.
35
+ */
36
+ columns: VariationProductColumn
37
+ /**
38
+ * Properties related to the 'add to cart' button
39
+ */
40
+ buyProps: {
41
+ 'data-testid': string
42
+ 'data-sku': string
43
+ 'data-seller': string
44
+ onClick(e: React.MouseEvent<HTMLButtonElement>): void
45
+ }
46
+ /**
47
+ * Formatter function that transforms the raw price value and render the result.
48
+ */
49
+ formatter?: PriceFormatter
50
+ /**
51
+ * Check if some result is still loading before render the result.
52
+ */
53
+ loading?: boolean
54
+ }
55
+
56
+ function SKUMatrixSidebar({
57
+ direction = 'rightSide',
58
+ title,
59
+ overlayProps,
60
+ size = 'partial',
61
+ children,
62
+ columns,
63
+ buyProps: { onClick: buyButtonOnClick, ...buyProps },
64
+ loading,
65
+ formatter,
66
+ ...otherProps
67
+ }: SKUMatrixSidebarProps) {
68
+ const {
69
+ isOpen,
70
+ setIsOpen,
71
+ setAllVariantProducts,
72
+ allVariantProducts,
73
+ onChangeQuantityItem,
74
+ } = useSKUMatrix()
75
+ const { pushToast } = useUI()
76
+ const { fade } = useFadeEffect()
77
+
78
+ const cartDetails = useMemo(() => {
79
+ return allVariantProducts.reduce(
80
+ (acc, product) => ({
81
+ amount: acc.amount + product.selectedCount,
82
+ subtotal: acc.subtotal + product.selectedCount * product.price,
83
+ }),
84
+ { amount: 0, subtotal: 0 }
85
+ )
86
+ }, [allVariantProducts])
87
+
88
+ function resetQuantityItems() {
89
+ setAllVariantProducts((prev) =>
90
+ prev.map((item) => ({ ...item, quantity: 0 }))
91
+ )
92
+ }
93
+
94
+ function onClose() {
95
+ resetQuantityItems()
96
+ setIsOpen(false)
97
+ }
98
+
99
+ function handleAddToCart(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
100
+ buyButtonOnClick(e)
101
+ onClose()
102
+ }
103
+
104
+ const totalColumnsSkeletonLength =
105
+ Object.keys(columns).filter((v) => v !== 'additionalColumns').length +
106
+ (columns.additionalColumns?.length ?? 0)
107
+
108
+ return (
109
+ <SlideOver
110
+ data-fs-sku-matrix-sidebar
111
+ size={size}
112
+ direction={direction}
113
+ overlayProps={overlayProps}
114
+ isOpen={isOpen}
115
+ fade={fade}
116
+ {...otherProps}
117
+ >
118
+ <SlideOverHeader onClose={onClose}>
119
+ <h2 data-fs-sku-matrix-sidebar-title>{title}</h2>
120
+ </SlideOverHeader>
121
+
122
+ {children}
123
+
124
+ <Table variant="bordered">
125
+ <TableHead>
126
+ <TableRow>
127
+ <TableCell align="left" variant="header" scope="col">
128
+ {columns.name}
129
+ </TableCell>
130
+
131
+ {columns.additionalColumns?.map(({ label, value }) => (
132
+ <TableCell key={value} align="left" variant="header" scope="col">
133
+ {label}
134
+ </TableCell>
135
+ ))}
136
+
137
+ <TableCell align="left" variant="header" scope="col">
138
+ {columns.availability.label}
139
+ </TableCell>
140
+
141
+ <TableCell align="right" variant="header" scope="col">
142
+ {columns.price}
143
+ </TableCell>
144
+
145
+ <TableCell align="left" variant="header" scope="col">
146
+ {columns.quantitySelector}
147
+ </TableCell>
148
+ </TableRow>
149
+ </TableHead>
150
+
151
+ <TableBody>
152
+ {loading ? (
153
+ <>
154
+ {Array.from({ length: 5 }).map((_, index) => {
155
+ return (
156
+ <TableRow key={`table-row-${index}`}>
157
+ {Array.from({
158
+ length: totalColumnsSkeletonLength,
159
+ }).map((_, index) => {
160
+ return (
161
+ <TableCell key={`table-cell-${index}`}>
162
+ <span>
163
+ <Skeleton
164
+ key={index}
165
+ size={{ width: '100%', height: '30px' }}
166
+ />
167
+ </span>
168
+ </TableCell>
169
+ )
170
+ })}
171
+ </TableRow>
172
+ )
173
+ })}
174
+ </>
175
+ ) : (
176
+ <>
177
+ {allVariantProducts.map((variantProduct) => (
178
+ <TableRow key={`${variantProduct.name}-${variantProduct.id}`}>
179
+ <TableCell data-fs-sku-matrix-sidebar-cell-image align="left">
180
+ <Image
181
+ src={variantProduct.image.url}
182
+ alt={variantProduct.image.alternateName}
183
+ width={48}
184
+ height={48}
185
+ />
186
+ {variantProduct.name}
187
+ </TableCell>
188
+
189
+ {columns.additionalColumns?.map(({ value }) => (
190
+ <TableCell
191
+ key={`${variantProduct.name}-${variantProduct.id}-${value}`}
192
+ align="left"
193
+ >
194
+ {variantProduct.specifications[value.toLowerCase()]}
195
+ </TableCell>
196
+ ))}
197
+
198
+ <TableCell align="left">
199
+ {columns.availability.stockDisplaySettings ===
200
+ 'showAvailability' && (
201
+ <Badge
202
+ variant={
203
+ variantProduct.availability === 'outOfStock'
204
+ ? 'warning'
205
+ : 'success'
206
+ }
207
+ >
208
+ {variantProduct.availability === 'outOfStock'
209
+ ? 'Out of stock'
210
+ : 'Available'}
211
+ </Badge>
212
+ )}
213
+
214
+ {columns.availability.stockDisplaySettings ===
215
+ 'showStockQuantity' && variantProduct.inventory}
216
+ </TableCell>
217
+
218
+ <TableCell align="right">
219
+ <div data-fs-sku-matrix-sidebar-table-price>
220
+ <Price
221
+ value={variantProduct.price}
222
+ variant="spot"
223
+ formatter={formatter}
224
+ />
225
+ </div>
226
+ </TableCell>
227
+
228
+ <TableCell
229
+ align="right"
230
+ data-fs-sku-matrix-sidebar-table-cell-quantity-selector
231
+ >
232
+ <div data-fs-sku-matrix-sidebar-table-action>
233
+ <QuantitySelector
234
+ min={0}
235
+ max={variantProduct.inventory}
236
+ disabled={
237
+ !variantProduct.inventory ||
238
+ variantProduct.availability === 'outOfStock'
239
+ }
240
+ initial={variantProduct.selectedCount}
241
+ onChange={(value) =>
242
+ onChangeQuantityItem(variantProduct.id, value)
243
+ }
244
+ onValidateBlur={(
245
+ min: number,
246
+ maxValue: number,
247
+ quantity: number
248
+ ) => {
249
+ pushToast({
250
+ title: 'Invalid quantity!',
251
+ message: `The quantity you entered is outside the range of ${min} to ${maxValue}. The quantity was set to ${quantity}.`,
252
+ status: 'INFO',
253
+ icon: (
254
+ <Icon
255
+ name="CircleWavyWarning"
256
+ width={30}
257
+ height={30}
258
+ />
259
+ ),
260
+ })
261
+ }}
262
+ />
263
+ </div>
264
+ </TableCell>
265
+ </TableRow>
266
+ ))}
267
+ </>
268
+ )}
269
+ </TableBody>
270
+ </Table>
271
+
272
+ <footer data-fs-sku-matrix-sidebar-footer>
273
+ <div>
274
+ <p>
275
+ {cartDetails.amount} {cartDetails.amount !== 1 ? 'Items' : 'Item'}
276
+ </p>
277
+ <Price
278
+ value={cartDetails.subtotal}
279
+ variant="spot"
280
+ formatter={formatter}
281
+ />
282
+ </div>
283
+
284
+ <Button
285
+ variant="primary"
286
+ disabled={!cartDetails.amount}
287
+ onClick={handleAddToCart}
288
+ {...buyProps}
289
+ >
290
+ Add to Cart
291
+ </Button>
292
+ </footer>
293
+ </SlideOver>
294
+ )
295
+ }
296
+
297
+ export default SKUMatrixSidebar
@@ -0,0 +1,31 @@
1
+ import React, { forwardRef } from 'react'
2
+ import Button from '../../atoms/Button'
3
+ import type { ButtonProps } from '../../atoms/Button'
4
+ import { useSKUMatrix } from '../../hooks'
5
+
6
+ export type SKUMatrixTriggerProps = ButtonProps
7
+
8
+ const SKUMatrixTrigger = forwardRef<HTMLButtonElement, SKUMatrixTriggerProps>(
9
+ function SKUMatrixTrigger(
10
+ { children, variant = 'secondary', onClick, ...otherProps },
11
+ ref
12
+ ) {
13
+ const { setIsOpen } = useSKUMatrix()
14
+
15
+ return (
16
+ <Button
17
+ ref={ref}
18
+ variant={variant}
19
+ onClick={(event) => {
20
+ setIsOpen(true)
21
+ onClick?.(event)
22
+ }}
23
+ {...otherProps}
24
+ >
25
+ {children}
26
+ </Button>
27
+ )
28
+ }
29
+ )
30
+
31
+ export default SKUMatrixTrigger
@@ -0,0 +1,8 @@
1
+ export { default } from './SKUMatrix'
2
+ export type { SKUMatrixProps } from './SKUMatrix'
3
+
4
+ export { default as SKUMatrixTrigger } from './SKUMatrixTrigger'
5
+ export type { SKUMatrixTriggerProps } from './SKUMatrixTrigger'
6
+
7
+ export { default as SKUMatrixSidebar } from './SKUMatrixSidebar'
8
+ export type { SKUMatrixSidebarProps } from './SKUMatrixSidebar'
@@ -0,0 +1,104 @@
1
+ import React, { createContext, useCallback, useState, SetStateAction } from 'react'
2
+ import type { ReactNode } from 'react'
3
+
4
+ interface IAllVariantProducts {
5
+ id: string
6
+ name: string
7
+ image: {
8
+ url: string
9
+ alternateName: string
10
+ }
11
+ inventory: number
12
+ availability: string
13
+ price: number
14
+ listPrice: number
15
+ priceWithTaxes: number
16
+ listPriceWithTaxes: number
17
+ specifications: Record<string, string>
18
+ selectedCount: number
19
+ offers: {
20
+ highPrice: number
21
+ lowPrice: number
22
+ lowPriceWithTaxes: number
23
+ offerCount: number
24
+ priceCurrency: string
25
+ offers: Array<{
26
+ listPrice: number
27
+ listPriceWithTaxes: number
28
+ sellingPrice: number
29
+ priceCurrency: string
30
+ price: number
31
+ priceWithTaxes: number
32
+ priceValidUntil: string
33
+ itemCondition: string
34
+ availability: string
35
+ quantity: number
36
+ }>
37
+ }
38
+ }
39
+
40
+ export interface SKUMatrixProviderContextValue {
41
+ /*
42
+ A boolean value that indicates if the modal is open.
43
+ */
44
+ isOpen: boolean
45
+ /*
46
+ Array of all variant products.
47
+ */
48
+ allVariantProducts: IAllVariantProducts[]
49
+ /*
50
+ Function to set the array of all variant products.
51
+ */
52
+ setAllVariantProducts(
53
+ items: SetStateAction<IAllVariantProducts[]>
54
+ ): void
55
+ /*
56
+ */
57
+ onChangeQuantityItem(id: string, value: number): IAllVariantProducts[]
58
+ /*
59
+ function to set the modal is open
60
+ */
61
+ setIsOpen(value: boolean): void
62
+ }
63
+
64
+ export const SKUMatrixContext =
65
+ createContext<SKUMatrixProviderContextValue | null>(null)
66
+
67
+ function SKUMatrixProvider({ children }: { children: ReactNode }) {
68
+ const [isOpen, setIsOpen] = useState<boolean>(false)
69
+ const [allVariantProducts, setAllVariantProducts] = useState<
70
+ IAllVariantProducts[]
71
+ >([])
72
+
73
+ const onChangeQuantityItem = useCallback(
74
+ (id: string, value: number) => {
75
+ const data = [...allVariantProducts]
76
+ const matchedSKU = data.find((item) => item.id === id)
77
+
78
+ if(matchedSKU) {
79
+ matchedSKU.selectedCount = value
80
+ }
81
+
82
+ setAllVariantProducts(data)
83
+
84
+ return data
85
+ },
86
+ [allVariantProducts]
87
+ )
88
+
89
+ return (
90
+ <SKUMatrixContext.Provider
91
+ value={{
92
+ isOpen,
93
+ allVariantProducts,
94
+ setAllVariantProducts,
95
+ onChangeQuantityItem,
96
+ setIsOpen,
97
+ }}
98
+ >
99
+ {children}
100
+ </SKUMatrixContext.Provider>
101
+ )
102
+ }
103
+
104
+ export default SKUMatrixProvider