-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add OutOfStock component (#1314)
Co-authored-by: Filipe W. Lima <filipe.lima@vtex.com.br> Co-authored-by: Eduardo Formiga <eduardo.formiga@gmail.com>
- Loading branch information
1 parent
aa8eaee
commit 37eac86
Showing
10 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 122 additions & 0 deletions
122
packages/ui/src/organisms/OutOfStock/OutOfStock.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { render, screen } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
import { axe } from 'jest-axe' | ||
import React from 'react' | ||
|
||
import { OutOfStockMessage, OutOfStockTitle } from '.' | ||
import Button from '../../atoms/Button' | ||
import Input from '../../atoms/Input' | ||
import Label from '../../atoms/Label' | ||
import OutOfStock from './OutOfStock' | ||
|
||
const SimpleOutOfStock = () => ( | ||
<OutOfStock> | ||
<OutOfStockTitle> | ||
Text <span>icon</span> | ||
</OutOfStockTitle> | ||
<OutOfStockMessage>Notify me when available</OutOfStockMessage> | ||
<Label> | ||
<Input /> | ||
</Label> | ||
<Button>Notify me</Button> | ||
</OutOfStock> | ||
) | ||
|
||
describe('OutOfStock', () => { | ||
it('`Out Of Stock` components should have corrects attributes', () => { | ||
render(<SimpleOutOfStock />) | ||
|
||
const outOfStock = screen.getByTestId('store-out-of-stock') | ||
const outOfStockTitle = screen.getByTestId('store-out-of-stock-title') | ||
const outOfStockMessage = screen.getByTestId('store-out-of-stock-message') | ||
const outOfStockForm = screen.getByTestId('store-out-of-stock-form') | ||
|
||
expect(outOfStock).toHaveAttribute('data-store-out-of-stock') | ||
expect(outOfStockForm).toHaveAttribute('data-out-of-stock-form') | ||
expect(outOfStockTitle).toHaveAttribute('data-out-of-stock-title') | ||
expect(outOfStockMessage).toHaveAttribute('data-out-of-stock-message') | ||
}) | ||
|
||
it('Should emit event', () => { | ||
const onSubmitMock = jest.fn((e) => e.preventDefault()) | ||
|
||
render( | ||
<OutOfStock onSubmit={onSubmitMock}> | ||
<OutOfStockTitle>Out of Stock</OutOfStockTitle> | ||
<Input name="email" /> | ||
<Button type="submit">Notify me</Button> | ||
</OutOfStock> | ||
) | ||
|
||
const outOfStockEventButton = screen.getByTestId('store-button') | ||
|
||
userEvent.click(outOfStockEventButton) | ||
|
||
expect(onSubmitMock).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
it('Should not render message', () => { | ||
render( | ||
<OutOfStock> | ||
<OutOfStockTitle>Out of Stock</OutOfStockTitle> | ||
<Input name="email" /> | ||
<Button type="submit">Notify me</Button> | ||
</OutOfStock> | ||
) | ||
|
||
const message = screen.queryByTestId('store-out-of-stock-message') | ||
|
||
expect(message).not.toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
describe('Accessibility', () => { | ||
it('should not have violations or incompletes', async () => { | ||
const { container } = render(<SimpleOutOfStock />) | ||
|
||
expect(await axe(container)).toHaveNoViolations() | ||
expect(await axe(container)).toHaveNoIncompletes() | ||
}) | ||
|
||
it('Out of Stock component should be a `section`', () => { | ||
render(<SimpleOutOfStock />) | ||
const outOfStock = screen.getByTestId('store-out-of-stock') | ||
|
||
expect(outOfStock.tagName).toEqual('SECTION') | ||
}) | ||
|
||
it('Out of Stock `title` component should be a `heading 2` as default', () => { | ||
render(<SimpleOutOfStock />) | ||
const outOfStockTitle = screen.getByTestId('store-out-of-stock-title') | ||
|
||
expect(outOfStockTitle.tagName).toEqual('H2') | ||
}) | ||
|
||
it('Out of Stock `message` should be a `paragraph` as default', () => { | ||
render(<SimpleOutOfStock />) | ||
const outOfStockMessage = screen.getByTestId('store-out-of-stock-message') | ||
|
||
expect(outOfStockMessage.tagName).toEqual('P') | ||
}) | ||
|
||
it('Out of Stock should render `title` as heading 1 and `message` as span', () => { | ||
render( | ||
<OutOfStock> | ||
<OutOfStockTitle as="h1">Head Out Os Stock</OutOfStockTitle> | ||
<OutOfStockMessage as="span">Head Out Os Stock</OutOfStockMessage> | ||
<Label> | ||
<Input /> | ||
</Label> | ||
<Button>Notify me</Button> | ||
</OutOfStock> | ||
) | ||
|
||
const outOfStockMessage = screen.getByTestId('store-out-of-stock-message') | ||
const outOfStockTitle = screen.getByTestId('store-out-of-stock-title') | ||
|
||
expect(outOfStockTitle.tagName).toEqual('H1') | ||
expect(outOfStockMessage.tagName).toEqual('SPAN') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from 'react' | ||
import type { ReactNode, FormHTMLAttributes } from 'react' | ||
|
||
import Form from '../../molecules/Form' | ||
|
||
export type OutOfStockBaseProps = { | ||
/** | ||
* ID to find this component in testing tools (e.g.: cypress, | ||
* testing-library, and jest). | ||
*/ | ||
testId?: string | ||
/** | ||
* Children for Out of Stock components. | ||
*/ | ||
children: string | ReactNode | ||
} | ||
|
||
export type OutOfStockProps = OutOfStockBaseProps & { | ||
/** | ||
* Event emitted when form is submitted. | ||
*/ | ||
onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void | ||
} & FormHTMLAttributes<HTMLFormElement> | ||
|
||
const OutOfStock = ({ | ||
testId = 'store-out-of-stock', | ||
children, | ||
...otherProps | ||
}: OutOfStockProps) => { | ||
return ( | ||
<section data-store-out-of-stock data-testid={testId}> | ||
<Form data-out-of-stock-form testId={`${testId}-form`} {...otherProps}> | ||
{children} | ||
</Form> | ||
</section> | ||
) | ||
} | ||
|
||
export default OutOfStock |
22 changes: 22 additions & 0 deletions
22
packages/ui/src/organisms/OutOfStock/OutOfStockMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React from 'react' | ||
|
||
import type { OutOfStockBaseProps } from './OutOfStock' | ||
|
||
export type OutOfStockMessageProps = { | ||
/** | ||
* Attribute used for polymorphic component. | ||
*/ | ||
as?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'div' | 'span' | ||
} & OutOfStockBaseProps | ||
|
||
export const OutOfStockMessage = ({ | ||
as: MessageComponent = 'p', | ||
testId = 'store-out-of-stock-message', | ||
children, | ||
}: OutOfStockMessageProps) => { | ||
return ( | ||
<MessageComponent data-out-of-stock-message data-testid={testId}> | ||
{children} | ||
</MessageComponent> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React from 'react' | ||
|
||
import type { OutOfStockBaseProps } from './OutOfStock' | ||
|
||
export type OutOfStockTitleProps = { | ||
/** | ||
* Attribute used for polymorphic component. | ||
*/ | ||
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | ||
} & OutOfStockBaseProps | ||
|
||
export const OutOfStockTitle = ({ | ||
as: TitleComponent = 'h2', | ||
testId = 'store-out-of-stock-title', | ||
children, | ||
}: OutOfStockTitleProps) => { | ||
return ( | ||
<TitleComponent data-out-of-stock-title data-testid={testId}> | ||
{children} | ||
</TitleComponent> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export { default } from './OutOfStock' | ||
export { OutOfStockMessage } from './OutOfStockMessage' | ||
export { OutOfStockTitle } from './OutOfStockTitle' | ||
export type { OutOfStockProps } from './OutOfStock' | ||
export type { OutOfStockMessageProps } from './OutOfStockMessage' | ||
export type { OutOfStockTitleProps } from './OutOfStockTitle' |
37 changes: 37 additions & 0 deletions
37
packages/ui/src/organisms/OutOfStock/stories/OutOfStock.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { Canvas, Props, Story, ArgsTable } from '@storybook/addon-docs' | ||
|
||
import OutOfStock from '../OutOfStock' | ||
|
||
# OutOfStock | ||
|
||
<Canvas> | ||
<Story id="organisms-outofstock--out-of-stock" /> | ||
</Canvas> | ||
|
||
The `OutOfStock` uses the [Compound Component](https://kentcdodds.com/blog/compound-components-with-react-hooks) pattern, its components are: | ||
|
||
- `OutOfStock`: the form wrapper of the out of stock component with title and message; | ||
- `OutOfStockTitle`: the main title component for out of stock component; | ||
- `OutOfStockMessage`: the message component for out of stock component; | ||
|
||
## Props | ||
|
||
### `OutOfStock` | ||
|
||
<ArgsTable of={ OutOfStock } /> | ||
|
||
## CSS Selectors | ||
|
||
```css | ||
[data-store-out-of-stock] { | ||
} | ||
|
||
[data-out-of-stock-form] { | ||
} | ||
|
||
[data-out-of-stock-title] { | ||
} | ||
|
||
[data-out-of-stock-message] { | ||
} | ||
``` |
73 changes: 73 additions & 0 deletions
73
packages/ui/src/organisms/OutOfStock/stories/OutOfStock.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import type { Story, Meta } from '@storybook/react' | ||
import React, { useState } from 'react' | ||
|
||
import type { | ||
OutOfStockMessageProps, | ||
OutOfStockTitleProps, | ||
OutOfStockProps, | ||
} from '..' | ||
import Component, { OutOfStockTitle, OutOfStockMessage } from '..' | ||
import Button from '../../../atoms/Button' | ||
import Input from '../../../atoms/Input' | ||
import mdx from './OutOfStock.mdx' | ||
|
||
type OutOfStockTemplateProps = { | ||
title: string | ||
message: string | ||
titleAs: OutOfStockTitleProps['as'] | ||
messageAs: OutOfStockMessageProps['as'] | ||
} & OutOfStockProps | ||
|
||
const OutOfStockTemplate: Story<OutOfStockTemplateProps> = ({ | ||
title, | ||
message, | ||
titleAs, | ||
messageAs, | ||
...props | ||
}) => { | ||
const [value, setValue] = useState('') | ||
|
||
const handlerSubmitForm = (e: React.FormEvent<HTMLFormElement>) => { | ||
e.preventDefault() | ||
|
||
// eslint-disable-next-line no-alert | ||
alert(value) | ||
} | ||
|
||
return ( | ||
<Component onSubmit={handlerSubmitForm} {...props}> | ||
<OutOfStockTitle as={titleAs}>{title}</OutOfStockTitle> | ||
<OutOfStockMessage as={messageAs}>{message}</OutOfStockMessage> | ||
<Input value={value} onChange={(e) => setValue(e.target.value)} /> | ||
<Button>Notify me</Button> | ||
</Component> | ||
) | ||
} | ||
|
||
export const OutOfStock = OutOfStockTemplate.bind({}) | ||
OutOfStock.storyName = 'OutOfStock' | ||
|
||
export default { | ||
title: 'Organisms/OutOfStock', | ||
parameters: { | ||
docs: { | ||
page: mdx, | ||
}, | ||
}, | ||
args: { | ||
title: 'Notify me', | ||
message: 'Notify me when available', | ||
}, | ||
argTypes: { | ||
titleAs: { | ||
defaultValue: 'h2', | ||
options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'], | ||
control: { type: 'select' }, | ||
}, | ||
messageAs: { | ||
defaultValue: 'p', | ||
options: ['h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'span'], | ||
control: { type: 'select' }, | ||
}, | ||
}, | ||
} as Meta |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import './out-of-stock.css'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
[data-store-out-of-stock] [data-out-of-stock-form] { | ||
display: flex; | ||
align-items: center; | ||
flex-direction: column; | ||
} | ||
|
||
[data-store-out-of-stock] [data-out-of-stock-title] { | ||
margin-bottom: .25rem; | ||
font-size: inherit; | ||
font-weight: inherit; | ||
} | ||
|
||
[data-store-out-of-stock] [data-out-of-stock-message] { | ||
align-items: center; | ||
margin-bottom: 1rem; | ||
} | ||
|
||
[data-out-of-stock-form] [data-store-button] { | ||
width: 100%; | ||
margin-top: 1rem; | ||
} | ||
|
||
[data-out-of-stock-form] [data-store-input] { | ||
width: 100%; | ||
margin-top: 0.25rem; | ||
max-width: initial; | ||
} |
37eac86
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
faststore – ./
www.faststore.dev
faststore-docs.vercel.app
faststore-git-main-faststore.vercel.app
faststore.dev
faststore-faststore.vercel.app