@faststore/components 3.98.0-dev.3 → 3.98.0-dev.8

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 (171) hide show
  1. package/dist/cjs/atoms/Link/Link.d.ts +1 -1
  2. package/dist/cjs/atoms/Link/Link.d.ts.map +1 -1
  3. package/dist/cjs/atoms/Link/Link.js.map +1 -1
  4. package/dist/cjs/atoms/List/List.d.ts.map +1 -1
  5. package/dist/cjs/atoms/List/List.js.map +1 -1
  6. package/dist/cjs/hooks/index.d.ts +7 -3
  7. package/dist/cjs/hooks/index.d.ts.map +1 -1
  8. package/dist/cjs/hooks/index.js +12 -6
  9. package/dist/cjs/hooks/index.js.map +1 -1
  10. package/dist/cjs/hooks/useCSVParser.d.ts +43 -0
  11. package/dist/cjs/hooks/useCSVParser.d.ts.map +1 -0
  12. package/dist/cjs/hooks/useCSVParser.js +264 -0
  13. package/dist/cjs/hooks/useCSVParser.js.map +1 -0
  14. package/dist/cjs/hooks/useFileUpload.d.ts +26 -0
  15. package/dist/cjs/hooks/useFileUpload.d.ts.map +1 -0
  16. package/dist/cjs/hooks/useFileUpload.js +68 -0
  17. package/dist/cjs/hooks/useFileUpload.js.map +1 -0
  18. package/dist/cjs/index.d.ts +58 -50
  19. package/dist/cjs/index.d.ts.map +1 -1
  20. package/dist/cjs/index.js +47 -32
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/molecules/Accordion/AccordionItem.d.ts.map +1 -1
  23. package/dist/cjs/molecules/Accordion/AccordionItem.js.map +1 -1
  24. package/dist/cjs/molecules/Dropzone/Dropzone.d.ts +87 -0
  25. package/dist/cjs/molecules/Dropzone/Dropzone.d.ts.map +1 -0
  26. package/dist/cjs/molecules/Dropzone/Dropzone.js +85 -0
  27. package/dist/cjs/molecules/Dropzone/Dropzone.js.map +1 -0
  28. package/dist/cjs/molecules/Dropzone/index.d.ts +3 -0
  29. package/dist/cjs/molecules/Dropzone/index.d.ts.map +1 -0
  30. package/dist/cjs/molecules/Dropzone/index.js +9 -0
  31. package/dist/cjs/molecules/Dropzone/index.js.map +1 -0
  32. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.d.ts +113 -0
  33. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.d.ts.map +1 -0
  34. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.js +169 -0
  35. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.js.map +1 -0
  36. package/dist/cjs/molecules/FileUploadCard/index.d.ts +3 -0
  37. package/dist/cjs/molecules/FileUploadCard/index.d.ts.map +1 -0
  38. package/dist/cjs/molecules/FileUploadCard/index.js +9 -0
  39. package/dist/cjs/molecules/FileUploadCard/index.js.map +1 -0
  40. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.d.ts +93 -0
  41. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.d.ts.map +1 -0
  42. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.js +77 -0
  43. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.js.map +1 -0
  44. package/dist/cjs/molecules/FileUploadStatus/index.d.ts +3 -0
  45. package/dist/cjs/molecules/FileUploadStatus/index.d.ts.map +1 -0
  46. package/dist/cjs/molecules/FileUploadStatus/index.js +11 -0
  47. package/dist/cjs/molecules/FileUploadStatus/index.js.map +1 -0
  48. package/dist/cjs/molecules/SearchInputField/SearchInputField.d.ts +23 -1
  49. package/dist/cjs/molecules/SearchInputField/SearchInputField.d.ts.map +1 -1
  50. package/dist/cjs/molecules/SearchInputField/SearchInputField.js +9 -4
  51. package/dist/cjs/molecules/SearchInputField/SearchInputField.js.map +1 -1
  52. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts +24 -0
  53. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts.map +1 -0
  54. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.js +14 -0
  55. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.js.map +1 -0
  56. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts +16 -0
  57. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts.map +1 -0
  58. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js +37 -0
  59. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js.map +1 -0
  60. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts +9 -0
  61. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts.map +1 -0
  62. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js +24 -0
  63. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js.map +1 -0
  64. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts +35 -0
  65. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts.map +1 -0
  66. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js +91 -0
  67. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js.map +1 -0
  68. package/dist/cjs/organisms/QuickOrderDrawer/index.d.ts +11 -0
  69. package/dist/cjs/organisms/QuickOrderDrawer/index.d.ts.map +1 -0
  70. package/dist/cjs/organisms/QuickOrderDrawer/index.js +18 -0
  71. package/dist/cjs/organisms/QuickOrderDrawer/index.js.map +1 -0
  72. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts +61 -0
  73. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts.map +1 -0
  74. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js +86 -0
  75. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js.map +1 -0
  76. package/dist/esm/atoms/Link/Link.d.ts +1 -1
  77. package/dist/esm/atoms/Link/Link.d.ts.map +1 -1
  78. package/dist/esm/atoms/Link/Link.js.map +1 -1
  79. package/dist/esm/atoms/List/List.d.ts.map +1 -1
  80. package/dist/esm/atoms/List/List.js.map +1 -1
  81. package/dist/esm/hooks/index.d.ts +7 -3
  82. package/dist/esm/hooks/index.d.ts.map +1 -1
  83. package/dist/esm/hooks/index.js +6 -3
  84. package/dist/esm/hooks/index.js.map +1 -1
  85. package/dist/esm/hooks/useCSVParser.d.ts +43 -0
  86. package/dist/esm/hooks/useCSVParser.d.ts.map +1 -0
  87. package/dist/esm/hooks/useCSVParser.js +259 -0
  88. package/dist/esm/hooks/useCSVParser.js.map +1 -0
  89. package/dist/esm/hooks/useFileUpload.d.ts +26 -0
  90. package/dist/esm/hooks/useFileUpload.d.ts.map +1 -0
  91. package/dist/esm/hooks/useFileUpload.js +64 -0
  92. package/dist/esm/hooks/useFileUpload.js.map +1 -0
  93. package/dist/esm/index.d.ts +58 -50
  94. package/dist/esm/index.d.ts.map +1 -1
  95. package/dist/esm/index.js +24 -20
  96. package/dist/esm/index.js.map +1 -1
  97. package/dist/esm/molecules/Accordion/AccordionItem.d.ts.map +1 -1
  98. package/dist/esm/molecules/Accordion/AccordionItem.js.map +1 -1
  99. package/dist/esm/molecules/Dropzone/Dropzone.d.ts +87 -0
  100. package/dist/esm/molecules/Dropzone/Dropzone.d.ts.map +1 -0
  101. package/dist/esm/molecules/Dropzone/Dropzone.js +82 -0
  102. package/dist/esm/molecules/Dropzone/Dropzone.js.map +1 -0
  103. package/dist/esm/molecules/Dropzone/index.d.ts +3 -0
  104. package/dist/esm/molecules/Dropzone/index.d.ts.map +1 -0
  105. package/dist/esm/molecules/Dropzone/index.js +2 -0
  106. package/dist/esm/molecules/Dropzone/index.js.map +1 -0
  107. package/dist/esm/molecules/FileUploadCard/FileUploadCard.d.ts +113 -0
  108. package/dist/esm/molecules/FileUploadCard/FileUploadCard.d.ts.map +1 -0
  109. package/dist/esm/molecules/FileUploadCard/FileUploadCard.js +166 -0
  110. package/dist/esm/molecules/FileUploadCard/FileUploadCard.js.map +1 -0
  111. package/dist/esm/molecules/FileUploadCard/index.d.ts +3 -0
  112. package/dist/esm/molecules/FileUploadCard/index.d.ts.map +1 -0
  113. package/dist/esm/molecules/FileUploadCard/index.js +2 -0
  114. package/dist/esm/molecules/FileUploadCard/index.js.map +1 -0
  115. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.d.ts +93 -0
  116. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.d.ts.map +1 -0
  117. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.js +73 -0
  118. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.js.map +1 -0
  119. package/dist/esm/molecules/FileUploadStatus/index.d.ts +3 -0
  120. package/dist/esm/molecules/FileUploadStatus/index.d.ts.map +1 -0
  121. package/dist/esm/molecules/FileUploadStatus/index.js +2 -0
  122. package/dist/esm/molecules/FileUploadStatus/index.js.map +1 -0
  123. package/dist/esm/molecules/SearchInputField/SearchInputField.d.ts +23 -1
  124. package/dist/esm/molecules/SearchInputField/SearchInputField.d.ts.map +1 -1
  125. package/dist/esm/molecules/SearchInputField/SearchInputField.js +9 -4
  126. package/dist/esm/molecules/SearchInputField/SearchInputField.js.map +1 -1
  127. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts +24 -0
  128. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts.map +1 -0
  129. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.js +11 -0
  130. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.js.map +1 -0
  131. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts +16 -0
  132. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts.map +1 -0
  133. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js +34 -0
  134. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js.map +1 -0
  135. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts +9 -0
  136. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts.map +1 -0
  137. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js +21 -0
  138. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js.map +1 -0
  139. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts +35 -0
  140. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts.map +1 -0
  141. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js +88 -0
  142. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js.map +1 -0
  143. package/dist/esm/organisms/QuickOrderDrawer/index.d.ts +11 -0
  144. package/dist/esm/organisms/QuickOrderDrawer/index.d.ts.map +1 -0
  145. package/dist/esm/organisms/QuickOrderDrawer/index.js +6 -0
  146. package/dist/esm/organisms/QuickOrderDrawer/index.js.map +1 -0
  147. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts +61 -0
  148. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts.map +1 -0
  149. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js +80 -0
  150. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js.map +1 -0
  151. package/package.json +5 -2
  152. package/src/atoms/Link/Link.tsx +4 -1
  153. package/src/atoms/List/List.tsx +18 -16
  154. package/src/hooks/index.ts +11 -3
  155. package/src/hooks/useCSVParser.ts +367 -0
  156. package/src/hooks/useFileUpload.ts +88 -0
  157. package/src/index.ts +97 -66
  158. package/src/molecules/Accordion/AccordionItem.tsx +4 -3
  159. package/src/molecules/Dropzone/Dropzone.tsx +248 -0
  160. package/src/molecules/Dropzone/index.ts +2 -0
  161. package/src/molecules/FileUploadCard/FileUploadCard.tsx +406 -0
  162. package/src/molecules/FileUploadCard/index.tsx +2 -0
  163. package/src/molecules/FileUploadStatus/FileUploadStatus.tsx +258 -0
  164. package/src/molecules/FileUploadStatus/index.tsx +6 -0
  165. package/src/molecules/SearchInputField/SearchInputField.tsx +72 -23
  166. package/src/organisms/QuickOrderDrawer/QuickOrderDrawer.tsx +58 -0
  167. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.tsx +72 -0
  168. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.tsx +43 -0
  169. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.tsx +323 -0
  170. package/src/organisms/QuickOrderDrawer/index.ts +19 -0
  171. package/src/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.tsx +205 -0
@@ -14,6 +14,7 @@ type ButtonProps = {
14
14
  onClick?: () => void
15
15
  testId?: string
16
16
  }
17
+
17
18
  export interface SearchInputFieldProps extends InputProps {
18
19
  /**
19
20
  * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
@@ -29,7 +30,29 @@ export interface SearchInputFieldProps extends InputProps {
29
30
  */
30
31
  buttonIcon?: ReactNode
31
32
  /**
32
- * Custom aria-label for input and button.
33
+ * Whether to show the attachment button.
34
+ * @default false
35
+ */
36
+ showAttachmentButton?: boolean
37
+ /**
38
+ * Props for the paperclip button inside the input.
39
+ */
40
+ attachmentButtonProps?: ButtonProps
41
+ /**
42
+ * Aria-label for the attachment button (e.g. from CMS).
43
+ */
44
+ attachmentButtonAriaLabel?: string
45
+ /**
46
+ * Aria-label for the submit button (e.g. from CMS).
47
+ */
48
+ submitButtonAriaLabel?: string
49
+ /**
50
+ * A React component that will be rendered as an icon (attachment button).
51
+ * @default <Icon name="Paperclip" />
52
+ */
53
+ attachmentButtonIcon?: ReactNode
54
+ /**
55
+ * Aria-label for the search input (e.g. from CMS).
33
56
  */
34
57
  'aria-label'?: AriaAttributes['aria-label']
35
58
  /**
@@ -50,7 +73,12 @@ const SearchInputField = forwardRef<
50
73
  {
51
74
  onSubmit,
52
75
  buttonIcon,
53
- 'aria-label': ariaLabel = 'search',
76
+ showAttachmentButton = false,
77
+ attachmentButtonAriaLabel,
78
+ attachmentButtonIcon,
79
+ attachmentButtonProps,
80
+ submitButtonAriaLabel,
81
+ 'aria-label': ariaLabel,
54
82
  testId = 'fs-search-input',
55
83
  buttonProps,
56
84
  ...otherProps
@@ -74,27 +102,48 @@ const SearchInputField = forwardRef<
74
102
  }))
75
103
 
76
104
  return (
77
- <form
78
- ref={formRef}
79
- data-fs-search-input-field
80
- data-testid={testId}
81
- onSubmit={handleSubmit}
82
- role="search"
83
- >
84
- <Input
85
- ref={inputRef}
86
- aria-label={ariaLabel}
87
- data-fs-search-input-field-input
88
- {...otherProps}
89
- />
90
- <IconButton
91
- type="submit"
92
- aria-label="Submit Search"
93
- icon={buttonIcon ?? <Icon name="MagnifyingGlass" />}
94
- size="small"
95
- {...buttonProps}
96
- />
97
- </form>
105
+ <div data-fs-search-input-field-wrapper>
106
+ <form
107
+ ref={formRef}
108
+ data-fs-search-input-field
109
+ data-testid={testId}
110
+ onSubmit={handleSubmit}
111
+ role="search"
112
+ >
113
+ <Input
114
+ ref={inputRef}
115
+ aria-label={ariaLabel}
116
+ data-fs-search-input-field-input
117
+ {...otherProps}
118
+ />
119
+
120
+ <div data-fs-search-input-field-actions>
121
+ {showAttachmentButton && (
122
+ <>
123
+ <IconButton
124
+ type="button"
125
+ aria-label={attachmentButtonAriaLabel}
126
+ icon={attachmentButtonIcon ?? <Icon name="Paperclip" />}
127
+ size="small"
128
+ data-fs-search-input-field-attachment-button
129
+ {...attachmentButtonProps}
130
+ />
131
+
132
+ <span data-fs-search-input-field-separator />
133
+ </>
134
+ )}
135
+
136
+ <IconButton
137
+ type="submit"
138
+ aria-label={submitButtonAriaLabel}
139
+ icon={buttonIcon ?? <Icon name="MagnifyingGlass" />}
140
+ size="small"
141
+ data-fs-search-input-field-submit-button
142
+ {...buttonProps}
143
+ />
144
+ </div>
145
+ </form>
146
+ </div>
98
147
  )
99
148
  })
100
149
 
@@ -0,0 +1,58 @@
1
+ import React, { type PropsWithChildren } from 'react'
2
+ import type { OverlayProps } from '../../atoms/Overlay'
3
+ import { useFadeEffect } from '../../hooks'
4
+ import SlideOver from '../SlideOver/SlideOver'
5
+
6
+ import {
7
+ QuickOrderDrawerProvider,
8
+ type QuickOrderDrawerProviderProps,
9
+ } from './provider/QuickOrderDrawerProvider'
10
+
11
+ export type QuickOrderDrawerProps = {
12
+ /**
13
+ * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
14
+ */
15
+ testId?: string
16
+
17
+ /**
18
+ * Controls the state
19
+ */
20
+ isOpen: boolean
21
+
22
+ /**
23
+ * Props forwarded to the `Overlay` component.
24
+ */
25
+ overlayProps?: OverlayProps
26
+
27
+ /**
28
+ * Props forwarded to the `QuickOrderDrawerProvider` component.
29
+ */
30
+ providerProps?: Omit<QuickOrderDrawerProviderProps, 'children'>
31
+ }
32
+
33
+ const QuickOrderDrawer = ({
34
+ testId = 'fs-quick-order-drawer',
35
+ isOpen,
36
+ overlayProps,
37
+ providerProps,
38
+ children,
39
+ }: PropsWithChildren<QuickOrderDrawerProps>) => {
40
+ const { fade } = useFadeEffect()
41
+ return (
42
+ <QuickOrderDrawerProvider {...providerProps}>
43
+ <SlideOver
44
+ testId={testId}
45
+ fade={fade}
46
+ isOpen={isOpen}
47
+ size="partial"
48
+ direction="rightSide"
49
+ overlayProps={overlayProps}
50
+ data-fs-quick-order-drawer
51
+ >
52
+ {children}
53
+ </SlideOver>
54
+ </QuickOrderDrawerProvider>
55
+ )
56
+ }
57
+
58
+ export default QuickOrderDrawer
@@ -0,0 +1,72 @@
1
+ import React, { useState } from 'react'
2
+ import Button from '../../atoms/Button'
3
+ import Icon from '../../atoms/Icon'
4
+ import Price, { type PriceFormatter } from '../../atoms/Price'
5
+ import { useQuickOrderDrawer } from './provider/QuickOrderDrawerProvider'
6
+
7
+ export type QuickOrderDrawerFooterProps = {
8
+ formatter?: PriceFormatter
9
+ /**
10
+ * Text labels for CMS configuration
11
+ */
12
+ labels?: {
13
+ itemsLabel?: string
14
+ addToCartLabel?: string
15
+ addToCartAriaLabel?: string
16
+ }
17
+ }
18
+
19
+ const QuickOrderDrawerFooter = ({
20
+ formatter,
21
+ labels,
22
+ }: QuickOrderDrawerFooterProps) => {
23
+ const [loading, setLoading] = useState(false)
24
+ const {
25
+ itemsCount,
26
+ totalPrice,
27
+ onAddToCart,
28
+ formatter: contextFormatter,
29
+ } = useQuickOrderDrawer()
30
+ const priceFormatter = formatter || contextFormatter
31
+ const { itemsLabel, addToCartLabel, addToCartAriaLabel } = labels || {}
32
+
33
+ const handleAddToCart = async () => {
34
+ if (itemsCount === 0) return
35
+ setLoading(true)
36
+ try {
37
+ onAddToCart()
38
+ } finally {
39
+ setLoading(false)
40
+ }
41
+ }
42
+
43
+ return (
44
+ <div data-fs-quick-order-drawer-footer>
45
+ <div data-fs-quick-order-drawer-footer-items>
46
+ <Icon name="Inventory" width={24} height={24} />
47
+ <span>
48
+ {itemsCount} {itemsLabel || ''}
49
+ </span>
50
+ </div>
51
+ <div data-fs-quick-order-drawer-footer-actions>
52
+ <Price
53
+ value={totalPrice}
54
+ variant="selling"
55
+ formatter={priceFormatter}
56
+ />
57
+ <Button
58
+ data-fs-quick-order-drawer-add-to-cart-btn
59
+ variant="primary"
60
+ disabled={itemsCount === 0}
61
+ loading={loading}
62
+ onClick={handleAddToCart}
63
+ aria-label={addToCartAriaLabel}
64
+ >
65
+ {addToCartLabel}
66
+ </Button>
67
+ </div>
68
+ </div>
69
+ )
70
+ }
71
+
72
+ export default QuickOrderDrawerFooter
@@ -0,0 +1,43 @@
1
+ import React from 'react'
2
+ import Icon from '../../atoms/Icon'
3
+ import { SlideOverHeader } from '../SlideOver'
4
+
5
+ export type QuickOrderDrawerHeaderProps = {
6
+ title: string
7
+ titleCharLimit?: number
8
+ onCloseDrawer?: () => void
9
+ }
10
+
11
+ const QuickOrderDrawerHeader = ({
12
+ onCloseDrawer,
13
+ title,
14
+ titleCharLimit = 30,
15
+ }: QuickOrderDrawerHeaderProps) => {
16
+ const leftOffset = Math.floor(titleCharLimit / 2) - 3
17
+ const rightOffset = Math.floor(titleCharLimit / 2)
18
+ const titleFormatted =
19
+ title.length > titleCharLimit
20
+ ? `${title.slice(0, leftOffset)}...${title.slice(-rightOffset)}`
21
+ : title
22
+
23
+ return (
24
+ <SlideOverHeader
25
+ data-fs-quick-order-drawer-header
26
+ closeBtnProps={{
27
+ variant: 'tertiary',
28
+ color: 'black',
29
+ 'aria-label': 'Close quick order drawer',
30
+ }}
31
+ onClose={() => onCloseDrawer?.()}
32
+ >
33
+ <div data-fs-quick-order-drawer-title-container>
34
+ <div data-fs-quick-order-drawer-icon>
35
+ <Icon name="Table" weight="bold" width={32} height={32} />
36
+ </div>
37
+ <div data-fs-quick-order-drawer-title>{titleFormatted}</div>
38
+ </div>
39
+ </SlideOverHeader>
40
+ )
41
+ }
42
+
43
+ export default QuickOrderDrawerHeader
@@ -0,0 +1,323 @@
1
+ import React, { type FunctionComponent } from 'react'
2
+ import Icon from '../../atoms/Icon'
3
+ import IconButton from '../../molecules/IconButton'
4
+ import QuantitySelector from '../../molecules/QuantitySelector'
5
+ import {
6
+ Table,
7
+ TableBody,
8
+ TableCell,
9
+ TableHead,
10
+ TableRow,
11
+ } from '../../molecules/Table'
12
+
13
+ import Badge from '../../atoms/Badge'
14
+ import type { PriceFormatter } from '../../atoms/Price'
15
+ import Price from '../../atoms/Price'
16
+ import Skeleton from '../../atoms/Skeleton'
17
+ import { useUI } from '../../hooks'
18
+ import Alert from '../../molecules/Alert'
19
+ import Tooltip from '../../molecules/Tooltip'
20
+ import {
21
+ useQuickOrderDrawer,
22
+ type VariationProductColumn,
23
+ } from './provider/QuickOrderDrawerProvider'
24
+
25
+ type ImageComponentType = FunctionComponent<{
26
+ src: string
27
+ alt: string
28
+ width?: number
29
+ height?: number
30
+ loading?: 'eager' | 'lazy'
31
+ }>
32
+
33
+ // TODO: Replace with faststore Image component in final implementation
34
+ // This is a temporary reference component for storybook preview
35
+ const DefaultImageComponent: ImageComponentType = ({
36
+ src,
37
+ alt,
38
+ width,
39
+ height,
40
+ ...otherProps
41
+ }) => <img src={src} alt={alt} width={width} height={height} {...otherProps} />
42
+
43
+ export type QuickOrderDrawerProductsProps = {
44
+ columns: VariationProductColumn
45
+ formatter?: PriceFormatter
46
+ ImageComponent?: ImageComponentType
47
+ /**
48
+ * Messages for CMS configuration
49
+ */
50
+ messages?: {
51
+ alertAriaLabel?: string
52
+ tableAriaLabel?: string
53
+ quantityUpdatedTooltip?: string
54
+ quantityUpdatedAriaLabel?: string
55
+ outOfStockLabel?: string
56
+ availableLabel?: string
57
+ selectQuantityAriaLabel?: string
58
+ removeProductAriaLabel?: string
59
+ invalidQuantityTitle?: string
60
+ invalidQuantityMessage?: (
61
+ min: number,
62
+ max: number,
63
+ quantity: number
64
+ ) => string
65
+ emptyStateTitle?: string
66
+ emptyStateMessage?: string
67
+ }
68
+ }
69
+
70
+ const QuickOrderDrawerProducts = ({
71
+ columns,
72
+ formatter,
73
+ ImageComponent = DefaultImageComponent,
74
+ messages,
75
+ }: QuickOrderDrawerProductsProps) => {
76
+ const { pushToast } = useUI()
77
+ const {
78
+ products,
79
+ onChangeQuantityItem,
80
+ onDelete,
81
+ isLoading,
82
+ alertMessage,
83
+ setAlertMessage,
84
+ formatter: contextFormatter,
85
+ } = useQuickOrderDrawer()
86
+ const priceFormatter = formatter || contextFormatter
87
+
88
+ const showSkeleton = isLoading
89
+ return (
90
+ <div data-fs-quick-order-drawer-content>
91
+ <>
92
+ {!isLoading && alertMessage && (
93
+ <Alert
94
+ icon={<Icon name="AlertFilled" weight="bold" />}
95
+ dismissible
96
+ onClick={() => setAlertMessage('')}
97
+ aria-label={messages?.alertAriaLabel}
98
+ >
99
+ {alertMessage}
100
+ </Alert>
101
+ )}
102
+ <Table
103
+ data-fs-quick-order-drawer-table
104
+ variant="bordered"
105
+ aria-label={messages?.tableAriaLabel}
106
+ >
107
+ <TableHead>
108
+ <TableRow>
109
+ <TableCell
110
+ data-fs-quick-order-drawer-product-header
111
+ align="left"
112
+ variant="header"
113
+ scope="col"
114
+ >
115
+ {columns.name}
116
+ </TableCell>
117
+
118
+ <TableCell align="left" variant="header" scope="col">
119
+ {columns.availability.label}
120
+ </TableCell>
121
+
122
+ <TableCell align="center" variant="header" scope="col">
123
+ {columns.price}
124
+ </TableCell>
125
+
126
+ <TableCell align="left" variant="header" scope="col">
127
+ {columns.quantity}
128
+ </TableCell>
129
+ <TableCell align="right" variant="header" scope="col"></TableCell>
130
+ </TableRow>
131
+ </TableHead>
132
+
133
+ <TableBody>
134
+ {showSkeleton ? (
135
+ <>
136
+ {Array.from({ length: 5 }).map((_, index) => {
137
+ return (
138
+ <TableRow key={`table-row-skeleton-${index}`}>
139
+ {Array.from({
140
+ length: 5,
141
+ }).map((_, cellIndex) => {
142
+ return (
143
+ <TableCell key={`table-cell-skeleton-${cellIndex}`}>
144
+ <Skeleton size={{ width: '96%', height: '30px' }} />
145
+ </TableCell>
146
+ )
147
+ })}
148
+ </TableRow>
149
+ )
150
+ })}
151
+ </>
152
+ ) : products.length > 0 ? (
153
+ <>
154
+ {products.map((variantProduct) => (
155
+ <TableRow
156
+ key={`${variantProduct.name}-${variantProduct.id}`}
157
+ data-fs-quick-order-table-row={variantProduct.availability}
158
+ >
159
+ <TableCell data-fs-quick-order-cell="product" align="left">
160
+ <div data-fs-quick-order-table-cell-img-container>
161
+ <ImageComponent
162
+ height={48}
163
+ src={variantProduct.image.url}
164
+ alt={
165
+ variantProduct.image.alternateName ||
166
+ variantProduct.name
167
+ }
168
+ />
169
+ </div>
170
+
171
+ <div data-fs-quick-order-table-cell-name-container>
172
+ <div data-fs-quick-order-text={'primary'}>
173
+ {variantProduct.name}
174
+ </div>
175
+ <span data-fs-quick-order-text={'secondary'}>
176
+ {variantProduct.id}
177
+ </span>
178
+ </div>
179
+ {variantProduct.availability === 'available' &&
180
+ variantProduct.quantityUpdated && (
181
+ <Tooltip
182
+ content={messages?.quantityUpdatedTooltip}
183
+ placement="left-center"
184
+ >
185
+ <IconButton
186
+ aria-label={messages?.quantityUpdatedAriaLabel}
187
+ icon={<Icon name="CircleWarning" weight="bold" />}
188
+ />
189
+ </Tooltip>
190
+ )}
191
+ </TableCell>
192
+
193
+ <TableCell align="left">
194
+ {columns.availability.stockDisplaySettings ===
195
+ 'showAvailability' && (
196
+ <Badge
197
+ variant={
198
+ variantProduct.availability === 'outOfStock'
199
+ ? 'warning'
200
+ : 'success'
201
+ }
202
+ >
203
+ {variantProduct.availability === 'outOfStock'
204
+ ? messages?.outOfStockLabel
205
+ : messages?.availableLabel}
206
+ </Badge>
207
+ )}
208
+
209
+ {columns.availability.stockDisplaySettings ===
210
+ 'showStockQuantity' && variantProduct.inventory}
211
+ </TableCell>
212
+
213
+ <TableCell data-fs-quick-order-cell="price" align="right">
214
+ <Price
215
+ value={variantProduct.price}
216
+ variant="spot"
217
+ formatter={priceFormatter}
218
+ data-fs-quick-order-table-price={
219
+ variantProduct.availability
220
+ }
221
+ />
222
+ </TableCell>
223
+
224
+ <TableCell
225
+ align="right"
226
+ data-fs-quick-order-cell="quantity-selector"
227
+ >
228
+ <div data-fs-quick-order-table-action>
229
+ <QuantitySelector
230
+ min={0}
231
+ max={variantProduct.inventory}
232
+ disabled={
233
+ !variantProduct.inventory ||
234
+ variantProduct.availability === 'outOfStock'
235
+ }
236
+ initial={variantProduct.selectedCount}
237
+ onChange={(value) =>
238
+ onChangeQuantityItem(variantProduct.id, value)
239
+ }
240
+ aria-label={messages?.selectQuantityAriaLabel?.replace(
241
+ '{productName}',
242
+ variantProduct.name
243
+ )}
244
+ onValidateBlur={(
245
+ min: number,
246
+ maxValue: number,
247
+ quantity: number
248
+ ) => {
249
+ const title = messages?.invalidQuantityTitle
250
+ const message = messages?.invalidQuantityMessage
251
+ ? messages.invalidQuantityMessage(
252
+ min,
253
+ maxValue,
254
+ quantity
255
+ )
256
+ : ''
257
+
258
+ pushToast({
259
+ title,
260
+ message,
261
+ status: 'INFO',
262
+ icon: (
263
+ <Icon
264
+ name="CircleWavyWarning"
265
+ width={30}
266
+ height={30}
267
+ />
268
+ ),
269
+ })
270
+ }}
271
+ />
272
+ </div>
273
+ </TableCell>
274
+ <TableCell align="right" data-fs-quick-order-delete-cell>
275
+ <IconButton
276
+ onClick={() => onDelete(variantProduct.id)}
277
+ icon={<Icon name="Thrash" color="#1F1F1F" />}
278
+ aria-label={messages?.removeProductAriaLabel?.replace(
279
+ '{productName}',
280
+ variantProduct.name
281
+ )}
282
+ />
283
+ </TableCell>
284
+ </TableRow>
285
+ ))}
286
+ </>
287
+ ) : (
288
+ <TableRow>
289
+ <TableCell
290
+ align="center"
291
+ data-fs-quick-order-empty-state
292
+ {...({
293
+ colSpan: 5,
294
+ } as React.HTMLAttributes<HTMLTableCellElement>)}
295
+ >
296
+ <div data-fs-quick-order-empty-state-container>
297
+ <Icon
298
+ name="MagnifyingGlass"
299
+ width={48}
300
+ height={48}
301
+ weight="thin"
302
+ data-fs-quick-order-empty-state-icon
303
+ />
304
+ <div data-fs-quick-order-empty-state-content>
305
+ <p data-fs-quick-order-empty-state-title>
306
+ {messages?.emptyStateTitle}
307
+ </p>
308
+ <p data-fs-quick-order-empty-state-message>
309
+ {messages?.emptyStateMessage}
310
+ </p>
311
+ </div>
312
+ </div>
313
+ </TableCell>
314
+ </TableRow>
315
+ )}
316
+ </TableBody>
317
+ </Table>
318
+ </>
319
+ </div>
320
+ )
321
+ }
322
+
323
+ export default QuickOrderDrawerProducts
@@ -0,0 +1,19 @@
1
+ export { default as QuickOrderDrawer, default } from './QuickOrderDrawer'
2
+ export type { QuickOrderDrawerProps } from './QuickOrderDrawer'
3
+
4
+ export { default as QuickOrderDrawerHeader } from './QuickOrderDrawerHeader'
5
+ export type { QuickOrderDrawerHeaderProps } from './QuickOrderDrawerHeader'
6
+
7
+ export { default as QuickOrderDrawerProducts } from './QuickOrderDrawerProducts'
8
+ export type { QuickOrderDrawerProductsProps } from './QuickOrderDrawerProducts'
9
+
10
+ export { default as QuickOrderDrawerFooter } from './QuickOrderDrawerFooter'
11
+ export type { QuickOrderDrawerFooterProps } from './QuickOrderDrawerFooter'
12
+
13
+ export { useQuickOrderDrawer } from './provider/QuickOrderDrawerProvider'
14
+ export type {
15
+ AlertMessages,
16
+ Product,
17
+ QuickOrderDrawerProviderProps,
18
+ VariationProductColumn,
19
+ } from './provider/QuickOrderDrawerProvider'