@faststore/ui 1.11.8 → 1.11.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/molecules/CartItem/CartItem.d.ts +10 -0
- package/dist/molecules/CartItem/CartItem.js +6 -0
- package/dist/molecules/CartItem/CartItem.js.map +1 -0
- package/dist/molecules/CartItem/CartItemActions.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemActions.js +6 -0
- package/dist/molecules/CartItem/CartItemActions.js.map +1 -0
- package/dist/molecules/CartItem/CartItemContent.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemContent.js +6 -0
- package/dist/molecules/CartItem/CartItemContent.js.map +1 -0
- package/dist/molecules/CartItem/CartItemImage.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemImage.js +6 -0
- package/dist/molecules/CartItem/CartItemImage.js.map +1 -0
- package/dist/molecules/CartItem/CartItemPrices.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemPrices.js +6 -0
- package/dist/molecules/CartItem/CartItemPrices.js.map +1 -0
- package/dist/molecules/CartItem/CartItemSummary.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemSummary.js +6 -0
- package/dist/molecules/CartItem/CartItemSummary.js.map +1 -0
- package/dist/molecules/CartItem/CartItemTitle.d.ts +10 -0
- package/dist/molecules/CartItem/CartItemTitle.js +6 -0
- package/dist/molecules/CartItem/CartItemTitle.js.map +1 -0
- package/dist/molecules/CartItem/index.d.ts +14 -0
- package/dist/molecules/CartItem/index.js +8 -0
- package/dist/molecules/CartItem/index.js.map +1 -0
- package/dist/molecules/OrderSummary/OrderSummary.d.ts +35 -0
- package/dist/molecules/OrderSummary/OrderSummary.js +16 -0
- package/dist/molecules/OrderSummary/OrderSummary.js.map +1 -0
- package/dist/molecules/OrderSummary/index.d.ts +2 -0
- package/dist/molecules/OrderSummary/index.js +2 -0
- package/dist/molecules/OrderSummary/index.js.map +1 -0
- package/dist/molecules/SkuSelector/SkuSelector.d.ts +58 -0
- package/dist/molecules/SkuSelector/SkuSelector.js +15 -0
- package/dist/molecules/SkuSelector/SkuSelector.js.map +1 -0
- package/dist/molecules/SkuSelector/index.d.ts +2 -0
- package/dist/molecules/SkuSelector/index.js +2 -0
- package/dist/molecules/SkuSelector/index.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +25 -0
- package/src/molecules/CartItem/CartItem.test.tsx +79 -0
- package/src/molecules/CartItem/CartItem.tsx +22 -0
- package/src/molecules/CartItem/CartItemActions.tsx +24 -0
- package/src/molecules/CartItem/CartItemContent.tsx +24 -0
- package/src/molecules/CartItem/CartItemImage.tsx +22 -0
- package/src/molecules/CartItem/CartItemPrices.tsx +24 -0
- package/src/molecules/CartItem/CartItemSummary.tsx +24 -0
- package/src/molecules/CartItem/CartItemTitle.tsx +22 -0
- package/src/molecules/CartItem/index.tsx +20 -0
- package/src/molecules/CartItem/stories/CartItem.mdx +79 -0
- package/src/molecules/CartItem/stories/CartItem.stories.tsx +70 -0
- package/src/molecules/OrderSummary/OrderSummary.test.tsx +103 -0
- package/src/molecules/OrderSummary/OrderSummary.tsx +109 -0
- package/src/molecules/OrderSummary/index.tsx +2 -0
- package/src/molecules/OrderSummary/stories/OrderSummary.mdx +29 -0
- package/src/molecules/OrderSummary/stories/OrderSummary.stories.tsx +29 -0
- package/src/molecules/QuantitySelector/stories/QuantitySelector.mdx +1 -1
- package/src/molecules/SkuSelector/SkuSelector.test.tsx +42 -0
- package/src/molecules/SkuSelector/SkuSelector.tsx +106 -0
- package/src/molecules/SkuSelector/index.tsx +2 -0
- package/src/molecules/SkuSelector/stories/SkuSelector.mdx +24 -0
- package/src/molecules/SkuSelector/stories/SkuSelector.stories.tsx +52 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import type { HTMLAttributes } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemActionsProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemActions = forwardRef<HTMLDivElement, CartItemActionsProps>(
|
|
12
|
+
function CartItemActions(
|
|
13
|
+
{ testId = 'store-cart-item-actions', children, ...otherProps },
|
|
14
|
+
ref
|
|
15
|
+
) {
|
|
16
|
+
return (
|
|
17
|
+
<div ref={ref} data-fs-cart-item-actions data-testid={testId} {...otherProps}>
|
|
18
|
+
{children}
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default CartItemActions
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemContentProps extends HTMLAttributes<HTMLElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemContent = forwardRef<HTMLElement, CartItemContentProps>(
|
|
12
|
+
function CartItemContent(
|
|
13
|
+
{ testId = 'store-cart-item-content', children, ...otherProps },
|
|
14
|
+
ref
|
|
15
|
+
) {
|
|
16
|
+
return (
|
|
17
|
+
<section ref={ref} data-fs-cart-item-content data-testid={testId} {...otherProps}>
|
|
18
|
+
{children}
|
|
19
|
+
</section>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default CartItemContent
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemImageProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemImage = forwardRef<HTMLDivElement, CartItemImageProps>(function CartItemImage(
|
|
12
|
+
{ testId = 'store-cart-item-image', children, ...otherProps },
|
|
13
|
+
ref
|
|
14
|
+
) {
|
|
15
|
+
return (
|
|
16
|
+
<div ref={ref} data-fs-cart-item-image data-testid={testId} {...otherProps}>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export default CartItemImage
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import type { HTMLAttributes } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemPricesProps extends HTMLAttributes<HTMLSpanElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemPrices = forwardRef<HTMLSpanElement, CartItemPricesProps>(
|
|
12
|
+
function CartItemPrices(
|
|
13
|
+
{ testId = 'store-cart-item-prices', children, ...otherProps },
|
|
14
|
+
ref
|
|
15
|
+
) {
|
|
16
|
+
return (
|
|
17
|
+
<span ref={ref} data-fs-cart-item-prices data-testid={testId} {...otherProps}>
|
|
18
|
+
{children}
|
|
19
|
+
</span>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default CartItemPrices
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import type { HTMLAttributes } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemSummaryProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemSummary = forwardRef<HTMLDivElement, CartItemSummaryProps>(
|
|
12
|
+
function CartItemSummary(
|
|
13
|
+
{ testId = 'store-cart-item-summary', children, ...otherProps },
|
|
14
|
+
ref
|
|
15
|
+
) {
|
|
16
|
+
return (
|
|
17
|
+
<div ref={ref} data-fs-cart-item-summary data-testid={testId} {...otherProps}>
|
|
18
|
+
{children}
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export default CartItemSummary
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
|
|
4
|
+
export interface CartItemTitleProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
|
|
7
|
+
*/
|
|
8
|
+
testId?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CartItemTitle = forwardRef<HTMLDivElement, CartItemTitleProps>(function CartItemTitle(
|
|
12
|
+
{ testId = 'store-cart-item-title', children, ...otherProps },
|
|
13
|
+
ref
|
|
14
|
+
) {
|
|
15
|
+
return (
|
|
16
|
+
<div ref={ref} data-fs-cart-item-title data-testid={testId} {...otherProps}>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export default CartItemTitle
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { default } from './CartItem'
|
|
2
|
+
export type { CartItemProps } from './CartItem'
|
|
3
|
+
|
|
4
|
+
export { default as CartItemActions } from './CartItemActions'
|
|
5
|
+
export type { CartItemActionsProps } from './CartItemActions'
|
|
6
|
+
|
|
7
|
+
export { default as CartItemContent } from './CartItemContent'
|
|
8
|
+
export type { CartItemContentProps } from './CartItemContent'
|
|
9
|
+
|
|
10
|
+
export { default as CartItemImage } from './CartItemImage'
|
|
11
|
+
export type { CartItemImageProps } from './CartItemImage'
|
|
12
|
+
|
|
13
|
+
export { default as CartItemPrices } from './CartItemPrices'
|
|
14
|
+
export type { CartItemPricesProps } from './CartItemPrices'
|
|
15
|
+
|
|
16
|
+
export { default as CartItemSummary } from './CartItemSummary'
|
|
17
|
+
export type { CartItemSummaryProps } from './CartItemSummary'
|
|
18
|
+
|
|
19
|
+
export { default as CartItemTitle } from './CartItemTitle'
|
|
20
|
+
export type { CartItemTitleProps } from './CartItemTitle'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ArgsTable, Canvas, Props, Story } from '@storybook/addon-docs'
|
|
2
|
+
|
|
3
|
+
import CartItem, {
|
|
4
|
+
CartItemActions,
|
|
5
|
+
CartItemContent,
|
|
6
|
+
CartItemImage,
|
|
7
|
+
CartItemPrices,
|
|
8
|
+
CartItemSummary,
|
|
9
|
+
CartItemTitle,
|
|
10
|
+
} from '../'
|
|
11
|
+
|
|
12
|
+
# Cart Item
|
|
13
|
+
|
|
14
|
+
<Canvas>
|
|
15
|
+
<Story id="molecules-cartitem--default" />
|
|
16
|
+
</Canvas>
|
|
17
|
+
|
|
18
|
+
## Components
|
|
19
|
+
|
|
20
|
+
The `CartItem` uses the [Compound Component](https://kentcdodds.com/blog/compound-components-with-react-hooks) pattern, its components are:
|
|
21
|
+
|
|
22
|
+
- `CartItem`: the wrapper component;
|
|
23
|
+
- `CartItemContent`: the wrapper component for the image and summary;
|
|
24
|
+
- `CartItemImage`: the wrapper component for the content's image;
|
|
25
|
+
- `CartItemSummary`: the wrapper component for the title and prices;
|
|
26
|
+
- `CartItemTitle`: the wrapper component for the title;
|
|
27
|
+
- `CartItemPrices`: the wrapper component for the prices;
|
|
28
|
+
- `CartItemActions`: the wrapper component for the remove from cart button and quantity selector;
|
|
29
|
+
|
|
30
|
+
## Props
|
|
31
|
+
|
|
32
|
+
All CartItem-related components support all attributes also supported by the `<div>` tag.
|
|
33
|
+
|
|
34
|
+
### `CartItem`
|
|
35
|
+
|
|
36
|
+
<ArgsTable of={CartItem} />
|
|
37
|
+
|
|
38
|
+
### `CartItemContent`
|
|
39
|
+
|
|
40
|
+
<ArgsTable of={CartItemContent} />
|
|
41
|
+
|
|
42
|
+
### `CartItemImage`
|
|
43
|
+
|
|
44
|
+
<ArgsTable of={CartItemImage} />
|
|
45
|
+
|
|
46
|
+
### `CartItemSummary`
|
|
47
|
+
|
|
48
|
+
<ArgsTable of={CartItemSummary} />
|
|
49
|
+
|
|
50
|
+
### `CartItemTitle`
|
|
51
|
+
|
|
52
|
+
<ArgsTable of={CartItemTitle} />
|
|
53
|
+
|
|
54
|
+
### `CartItemPrices`
|
|
55
|
+
|
|
56
|
+
<ArgsTable of={CartItemPrices} />
|
|
57
|
+
|
|
58
|
+
### `CartItemActions`
|
|
59
|
+
|
|
60
|
+
<ArgsTable of={CartItemActions} />
|
|
61
|
+
|
|
62
|
+
## CSS Selectors
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
[data-fs-cart-item] {
|
|
66
|
+
}
|
|
67
|
+
[data-fs-cart-item-content] {
|
|
68
|
+
}
|
|
69
|
+
[data-fs-cart-item-image] {
|
|
70
|
+
}
|
|
71
|
+
[data-fs-cart-item-summary] {
|
|
72
|
+
}
|
|
73
|
+
[data-fs-cart-item-title] {
|
|
74
|
+
}
|
|
75
|
+
[data-fs-cart-item-prices] {
|
|
76
|
+
}
|
|
77
|
+
[data-fs-cart-item-actions] {
|
|
78
|
+
}
|
|
79
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import CartItem, {
|
|
4
|
+
CartItemActions,
|
|
5
|
+
CartItemContent,
|
|
6
|
+
CartItemImage,
|
|
7
|
+
CartItemPrices,
|
|
8
|
+
CartItemSummary,
|
|
9
|
+
CartItemTitle,
|
|
10
|
+
} from '../'
|
|
11
|
+
import { Button, Price, QuantitySelector } from '../../../'
|
|
12
|
+
import mdx from './CartItem.mdx'
|
|
13
|
+
|
|
14
|
+
import type { Meta, Story } from '@storybook/react'
|
|
15
|
+
import type { CartItemProps } from '../'
|
|
16
|
+
|
|
17
|
+
const product = {
|
|
18
|
+
name: 'Apple Magic Mouse',
|
|
19
|
+
imageUrl:
|
|
20
|
+
'https://assets.vtex.app/unsafe/216x216/center/middle/https%3A%2F%2Fstoreframework.vtexassets.com%2Farquivos%2Fids%2F190902%2Funsplash-magic-mouse.jpg%3Fv%3D637800136963870000',
|
|
21
|
+
price: {
|
|
22
|
+
listing: 999,
|
|
23
|
+
spot: 950,
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const CartItemTemplate: Story<CartItemProps> = ({ testId }) => {
|
|
28
|
+
return (
|
|
29
|
+
<CartItem testId={testId}>
|
|
30
|
+
<CartItemContent>
|
|
31
|
+
<CartItemImage>
|
|
32
|
+
<img alt={product.name} src={product.imageUrl} />
|
|
33
|
+
</CartItemImage>
|
|
34
|
+
|
|
35
|
+
<CartItemSummary>
|
|
36
|
+
<CartItemTitle>{product.name}</CartItemTitle>
|
|
37
|
+
|
|
38
|
+
<CartItemPrices>
|
|
39
|
+
<Price variant="listing" value={product.price.listing} />
|
|
40
|
+
<Price variant="spot" value={product.price.spot} />
|
|
41
|
+
</CartItemPrices>
|
|
42
|
+
</CartItemSummary>
|
|
43
|
+
</CartItemContent>
|
|
44
|
+
|
|
45
|
+
<CartItemActions>
|
|
46
|
+
<Button>Remove</Button>
|
|
47
|
+
|
|
48
|
+
<QuantitySelector
|
|
49
|
+
quantity={1}
|
|
50
|
+
leftButtonProps={{ icon: <span>-</span> }}
|
|
51
|
+
rightButtonProps={{ icon: <span>+</span> }}
|
|
52
|
+
inputProps={{ readOnly: true }}
|
|
53
|
+
/>
|
|
54
|
+
</CartItemActions>
|
|
55
|
+
</CartItem>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const Default = CartItemTemplate.bind({})
|
|
60
|
+
|
|
61
|
+
Default.storyName = 'CartItem'
|
|
62
|
+
|
|
63
|
+
export default {
|
|
64
|
+
title: 'Molecules/CartItem',
|
|
65
|
+
parameters: {
|
|
66
|
+
docs: {
|
|
67
|
+
page: mdx,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
} as Meta
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import { axe } from 'jest-axe'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import OrderSummary from './OrderSummary'
|
|
6
|
+
|
|
7
|
+
const ELEMENT_NOT_FOUND_MESSAGE = 'Unable to find an element by:'
|
|
8
|
+
|
|
9
|
+
describe('OrderSummary', () => {
|
|
10
|
+
it('should have `data-fs-order-summary` attribute', () => {
|
|
11
|
+
const { getByTestId } = render(<OrderSummary />)
|
|
12
|
+
|
|
13
|
+
expect(getByTestId('store-order-summary')).toHaveAttribute(
|
|
14
|
+
'data-fs-order-summary'
|
|
15
|
+
)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should always render total labels and values elements', async () => {
|
|
19
|
+
const { getByTestId } = render(<OrderSummary />)
|
|
20
|
+
|
|
21
|
+
expect(getByTestId('store-order-summary-total-label')).toBeInTheDocument()
|
|
22
|
+
expect(getByTestId('store-order-summary-total-value')).toBeInTheDocument()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should not render subtotal or discount labels and values if subtotalValue or discountValue are not provided', async () => {
|
|
26
|
+
const { getByTestId } = render(
|
|
27
|
+
<OrderSummary totalLabel="Total" totalValue="250$" />
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
expect(() =>
|
|
31
|
+
getByTestId('store-order-summary-subtotal-label')
|
|
32
|
+
).toThrowError(ELEMENT_NOT_FOUND_MESSAGE)
|
|
33
|
+
expect(() => getByTestId('store-order-summary-subtotal-value')).toThrow(
|
|
34
|
+
ELEMENT_NOT_FOUND_MESSAGE
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
expect(() => getByTestId('store-order-summary-discount-label')).toThrow(
|
|
38
|
+
ELEMENT_NOT_FOUND_MESSAGE
|
|
39
|
+
)
|
|
40
|
+
expect(() => getByTestId('store-order-summary-discount-value')).toThrow(
|
|
41
|
+
ELEMENT_NOT_FOUND_MESSAGE
|
|
42
|
+
)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should render subtotal label and value if subtotalValue is provided', async () => {
|
|
46
|
+
const { getByTestId } = render(
|
|
47
|
+
<OrderSummary
|
|
48
|
+
subtotalLabel="Subtotal"
|
|
49
|
+
totalLabel="Total"
|
|
50
|
+
subtotalValue="300$"
|
|
51
|
+
totalValue="250$"
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
expect(
|
|
56
|
+
getByTestId('store-order-summary-subtotal-label')
|
|
57
|
+
).toBeInTheDocument()
|
|
58
|
+
expect(getByTestId('store-order-summary-subtotal-label')).toHaveTextContent(
|
|
59
|
+
'Subtotal'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(
|
|
63
|
+
getByTestId('store-order-summary-subtotal-value')
|
|
64
|
+
).toBeInTheDocument()
|
|
65
|
+
expect(getByTestId('store-order-summary-subtotal-value')).toHaveTextContent(
|
|
66
|
+
'300$'
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should render discount label and value if discountValue is provided', async () => {
|
|
71
|
+
const { getByTestId } = render(
|
|
72
|
+
<OrderSummary
|
|
73
|
+
subtotalLabel="Subtotal"
|
|
74
|
+
totalLabel="Total"
|
|
75
|
+
subtotalValue="300$"
|
|
76
|
+
totalValue="250$"
|
|
77
|
+
discountLabel="Discount"
|
|
78
|
+
discountValue="-50$"
|
|
79
|
+
/>
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
expect(
|
|
83
|
+
getByTestId('store-order-summary-discount-label')
|
|
84
|
+
).toBeInTheDocument()
|
|
85
|
+
expect(getByTestId('store-order-summary-discount-label')).toHaveTextContent(
|
|
86
|
+
'Discount'
|
|
87
|
+
)
|
|
88
|
+
expect(
|
|
89
|
+
getByTestId('store-order-summary-discount-value')
|
|
90
|
+
).toBeInTheDocument()
|
|
91
|
+
expect(getByTestId('store-order-summary-discount-value')).toHaveTextContent(
|
|
92
|
+
'-50$'
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe('Accessibility', () => {
|
|
97
|
+
it('should have no violations', async () => {
|
|
98
|
+
const { getByTestId } = render(<OrderSummary />)
|
|
99
|
+
|
|
100
|
+
expect(await axe(getByTestId('store-order-summary'))).toHaveNoViolations()
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
})
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import List, { ListProps } from '../../atoms/List'
|
|
3
|
+
|
|
4
|
+
export interface OrderSummaryProps<T = HTMLElement> extends Omit<ListProps<T>, 'variant'> {
|
|
5
|
+
/**
|
|
6
|
+
* ID to find this component in testing tools (e.g.: cypress,
|
|
7
|
+
* testing-library, and jest).
|
|
8
|
+
*/
|
|
9
|
+
testId?: string
|
|
10
|
+
/**
|
|
11
|
+
* Label for the subtotal value of the order. Will only show if subtotalValue is provided.
|
|
12
|
+
*/
|
|
13
|
+
subtotalLabel?: string
|
|
14
|
+
/**
|
|
15
|
+
* Subtotal value of the order. If provided, subtotal label and value will be shown.
|
|
16
|
+
*/
|
|
17
|
+
subtotalValue?: string
|
|
18
|
+
/**
|
|
19
|
+
* Label for the discount value for the order. Will only show if discountValue is provided.
|
|
20
|
+
*/
|
|
21
|
+
discountLabel?: string
|
|
22
|
+
/**
|
|
23
|
+
* Discount value for the order. If provided, discount label and value will be shown.
|
|
24
|
+
*/
|
|
25
|
+
discountValue?: string
|
|
26
|
+
/**
|
|
27
|
+
* Label for the total value of the order.
|
|
28
|
+
*/
|
|
29
|
+
totalLabel?: string
|
|
30
|
+
/**
|
|
31
|
+
* Total value of the order.
|
|
32
|
+
*/
|
|
33
|
+
totalValue?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const OrderSummary = forwardRef<HTMLUListElement, OrderSummaryProps>(
|
|
37
|
+
function OrderSummary(
|
|
38
|
+
{
|
|
39
|
+
testId = 'store-order-summary',
|
|
40
|
+
children,
|
|
41
|
+
subtotalLabel,
|
|
42
|
+
subtotalValue,
|
|
43
|
+
discountLabel,
|
|
44
|
+
discountValue,
|
|
45
|
+
totalLabel,
|
|
46
|
+
totalValue,
|
|
47
|
+
...otherProps
|
|
48
|
+
},
|
|
49
|
+
ref
|
|
50
|
+
) {
|
|
51
|
+
return (
|
|
52
|
+
<List
|
|
53
|
+
ref={ref}
|
|
54
|
+
data-fs-order-summary
|
|
55
|
+
data-testid={testId}
|
|
56
|
+
{...otherProps}
|
|
57
|
+
>
|
|
58
|
+
{subtotalValue ? (
|
|
59
|
+
<li data-fs-order-summary-subtotal>
|
|
60
|
+
<span
|
|
61
|
+
data-fs-order-summary-subtotal-label
|
|
62
|
+
data-testid={`${testId}-subtotal-label`}
|
|
63
|
+
>
|
|
64
|
+
{subtotalLabel}
|
|
65
|
+
</span>
|
|
66
|
+
<span
|
|
67
|
+
data-fs-order-summary-subtotal-value
|
|
68
|
+
data-testid={`${testId}-subtotal-value`}
|
|
69
|
+
>
|
|
70
|
+
{subtotalValue}
|
|
71
|
+
</span>
|
|
72
|
+
</li>
|
|
73
|
+
) : null}
|
|
74
|
+
{discountValue ? (
|
|
75
|
+
<li data-fs-order-summary-discount>
|
|
76
|
+
<span
|
|
77
|
+
data-fs-order-summary-discount-label
|
|
78
|
+
data-testid={`${testId}-discount-label`}
|
|
79
|
+
>
|
|
80
|
+
{discountLabel}
|
|
81
|
+
</span>
|
|
82
|
+
<span
|
|
83
|
+
data-fs-order-summary-discount-value
|
|
84
|
+
data-testid={`${testId}-discount-value`}
|
|
85
|
+
>
|
|
86
|
+
{discountValue}
|
|
87
|
+
</span>
|
|
88
|
+
</li>
|
|
89
|
+
) : null}
|
|
90
|
+
<li data-fs-order-summary-total>
|
|
91
|
+
<span
|
|
92
|
+
data-fs-order-summary-total-label
|
|
93
|
+
data-testid={`${testId}-total-label`}
|
|
94
|
+
>
|
|
95
|
+
{totalLabel}
|
|
96
|
+
</span>
|
|
97
|
+
<span
|
|
98
|
+
data-fs-order-summary-total-value
|
|
99
|
+
data-testid={`${testId}-total-value`}
|
|
100
|
+
>
|
|
101
|
+
{totalValue}
|
|
102
|
+
</span>
|
|
103
|
+
</li>
|
|
104
|
+
</List>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
export default OrderSummary
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Canvas, Props, Story, ArgsTable } from '@storybook/addon-docs'
|
|
2
|
+
|
|
3
|
+
import OrderSummary from '../OrderSummary'
|
|
4
|
+
|
|
5
|
+
# OrderSummary
|
|
6
|
+
|
|
7
|
+
<Canvas>
|
|
8
|
+
<Story id="molecules-ordersummary--order-summary" />
|
|
9
|
+
</Canvas>
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
<ArgsTable of={ OrderSummary } />
|
|
14
|
+
|
|
15
|
+
## CSS Selectors
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
[data-fs-order-summary] {}
|
|
19
|
+
[data-fs-order-summary-subtotal] {}
|
|
20
|
+
[data-fs-order-summary-subtotal-label] {}
|
|
21
|
+
[data-fs-order-summary-subtotal-value] {}
|
|
22
|
+
[data-fs-order-summary-discount] {}
|
|
23
|
+
[data-fs-order-summary-discount-label] {}
|
|
24
|
+
[data-fs-order-summary-discount-value] {}
|
|
25
|
+
[data-fs-order-summary-total] {}
|
|
26
|
+
[data-fs-order-summary-total-label] {}
|
|
27
|
+
[data-fs-order-summary-total-value] {}
|
|
28
|
+
|
|
29
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Story, Meta } from '@storybook/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import type { OrderSummaryProps } from '../OrderSummary'
|
|
5
|
+
import Component from '../OrderSummary'
|
|
6
|
+
import mdx from './OrderSummary.mdx'
|
|
7
|
+
|
|
8
|
+
const OrderSummaryTemplate: Story<OrderSummaryProps> = () => (
|
|
9
|
+
<Component
|
|
10
|
+
subtotalLabel='Subtotal (3 products)'
|
|
11
|
+
subtotalValue='$300'
|
|
12
|
+
discountLabel='Discount'
|
|
13
|
+
discountValue='-$50'
|
|
14
|
+
totalLabel='Total'
|
|
15
|
+
totalValue='250$'
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
export const OrderSummary = OrderSummaryTemplate.bind({})
|
|
20
|
+
OrderSummary.storyName = 'OrderSummary'
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
title: 'Molecules/OrderSummary',
|
|
24
|
+
parameters: {
|
|
25
|
+
docs: {
|
|
26
|
+
page: mdx,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
} as Meta
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { render } from '@testing-library/react'
|
|
2
|
+
import { axe } from 'jest-axe'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import SkuSelector from './SkuSelector'
|
|
6
|
+
|
|
7
|
+
const SkuSelectorTest = () => {
|
|
8
|
+
const options = [
|
|
9
|
+
{ label: 'Option round', value: 'Round' },
|
|
10
|
+
{ label: 'Option square', value: 'Square' },
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
return <SkuSelector variant="label" options={options} activeValue="Square" />
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('SkuSelector', () => {
|
|
17
|
+
describe('Data attributes', () => {
|
|
18
|
+
it('should have `data-fs-sku-selector` attribute', () => {
|
|
19
|
+
const { getByTestId } = render(<SkuSelectorTest />)
|
|
20
|
+
|
|
21
|
+
expect(getByTestId('store-sku-selector')).toHaveAttribute(
|
|
22
|
+
'data-fs-sku-selector'
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should have `data-fs-sku-selector-variant` attribute', () => {
|
|
27
|
+
const { getByTestId } = render(<SkuSelectorTest />)
|
|
28
|
+
|
|
29
|
+
expect(getByTestId('store-sku-selector')).toHaveAttribute(
|
|
30
|
+
'data-fs-sku-selector-variant'
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('Accessibility', () => {
|
|
36
|
+
it('should have no violations', async () => {
|
|
37
|
+
const { getByTestId } = render(<SkuSelectorTest />)
|
|
38
|
+
|
|
39
|
+
expect(await axe(getByTestId('store-sku-selector'))).toHaveNoViolations()
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
})
|