Skip to content

Commit

Permalink
refactor: Extract CartItem component from the starter (#1461)
Browse files Browse the repository at this point in the history
## What's the purpose of this pull request?

Extract the `CartItem` component from our starter to `@faststore/ui`.

## How to test it?

Run `yarn storybook` and check the new `CartItem` entry at http://localhost:6006/?path=/story/molecules-cartitem--default.
<img width="1028" alt="CleanShot 2022-09-12 at 08 28 54@2x" src="https://user-images.githubusercontent.com/381395/189643277-522a16b5-a9ba-4502-a0d0-d0cbc6e4534b.png">

### Starters Deploy Preview

Check https://sfj-4a90f81--nextjs.preview.vtex.app/4k-philips-monitor-99988213/p from https://github.com/vtex-sites/nextjs.store/pull/239. Add a product to the min-cart and you should see the `CartItem` being rendered in the sidebar.

## References

- https://vtex-dev.atlassian.net/browse/FS-361 (internal)
- https://github.com/vtex-sites/nextjs.store/pull/239
  • Loading branch information
filipewl authored Sep 12, 2022
1 parent 194bdc5 commit ff70925
Show file tree
Hide file tree
Showing 15 changed files with 485 additions and 1 deletion.
54 changes: 54 additions & 0 deletions packages/styles/src/molecules/cart-item.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[data-fs-cart-item] {
padding: 16px;
color: #171a1c;
background-color: #ffffff;
border: 2px solid #e3e6e8;
border-radius: 4px;
}

[data-fs-cart-item-content] {
display: grid;
grid-template-columns: 72px repeat(4, 1fr);
column-gap: 8px;
align-items: center;
}

[data-fs-cart-item-summary] {
flex-direction: column;
grid-column: 2 / span 4;
}

[data-fs-cart-item-title] {
margin-bottom: 0;
line-height: 1.2;
text-decoration: none;
outline: none;
}

[data-fs-cart-item-prices] {
display: flex;
align-items: baseline;
}

[data-fs-cart-item-prices] [data-store-price] + [data-store-price] {
margin-left: 16px;
}

[data-fs-cart-item-prices] [data-store-price][data-variant="listing"] {
font-size: 0.875rem;
color: #5d666f;
}

[data-fs-cart-item-prices] [data-store-price][data-variant="spot"] {
font-size: 1.25rem;
}

[data-fs-cart-item-actions] [data-store-quantity-selector] [data-store-icon] {
color: #00419e;
}

[data-fs-cart-item-actions] {
display: flex;
justify-content: space-between;
margin-top: 16px;
}
1 change: 1 addition & 0 deletions packages/styles/src/molecules/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@import './breadcrumb.css';
@import './card.css';
@import './carousel.css';
@import './cart-item.css';
@import './dropdown.css';
@import './form.css';
@import './gift.css';
Expand Down
19 changes: 19 additions & 0 deletions packages/ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,25 @@ export type {
CardActionsProps,
} from './molecules/Card'

export {
default as CartItem,
CartItemActions,
CartItemContent,
CartItemImage,
CartItemPrices,
CartItemSummary,
CartItemTitle,
} from './molecules/CartItem'
export type {
CartItemProps,
CartItemActionsProps,
CartItemContentProps,
CartItemImageProps,
CartItemPricesProps,
CartItemSummaryProps,
CartItemTitleProps,
} from './molecules/CartItem'

export { default as Bullets } from './molecules/Bullets'
export type { BulletsProps } from './molecules/Bullets'

Expand Down
79 changes: 79 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { render } from '@testing-library/react'
import { axe } from 'jest-axe'
import React from 'react'

import CartItem, {
CartItemActions,
CartItemContent,
CartItemImage,
CartItemPrices,
CartItemSummary,
CartItemTitle,
} from './'

const product = {
name: 'Apple Magic Mouse',
imageUrl:
'https://assets.vtex.app/unsafe/216x216/center/middle/https%3A%2F%2Fstoreframework.vtexassets.com%2Farquivos%2Fids%2F190902%2Funsplash-magic-mouse.jpg%3Fv%3D637800136963870000',
price: {
listing: 999,
spot: 950,
},
}

const CartItemTest = () => {
return (
<CartItem>
<CartItemContent>
<CartItemImage>
<img alt={product.name} src={product.imageUrl} />
</CartItemImage>

<CartItemSummary>
<CartItemTitle>{product.name}</CartItemTitle>

<CartItemPrices>
<span>{product.price.listing}</span>
<span>{product.price.spot}</span>
</CartItemPrices>
</CartItemSummary>
</CartItemContent>

<CartItemActions>
<button>Remove</button>

<span>Quantity Selector</span>
</CartItemActions>
</CartItem>
)
}

describe('`CartItem`', () => {
describe('Data attributes', () => {
it(`should have the correct format`, () => {
const testIdToDataAttributeMap = {
'store-cart-item': 'data-fs-cart-item',
'store-cart-item-content': 'data-fs-cart-item-content',
'store-cart-item-image': 'data-fs-cart-item-image',
'store-cart-item-summary': 'data-fs-cart-item-summary',
'store-cart-item-title': 'data-fs-cart-item-title',
'store-cart-item-prices': 'data-fs-cart-item-prices',
'store-cart-item-actions': 'data-fs-cart-item-actions',
}
const { getByTestId } = render(<CartItemTest />)

for (const [testId, dataAttribute] of Object.entries(testIdToDataAttributeMap)) {
expect(getByTestId(testId)).toHaveAttribute(dataAttribute)
}
})
})

describe('Accessibility', () => {
it('should have no violations', async () => {
const { getByTestId } = render(<CartItemTest />)

expect(await axe(getByTestId('store-cart-item'))).toHaveNoViolations()
expect(await axe(getByTestId('store-cart-item'))).toHaveNoIncompletes()
})
})
})
22 changes: 22 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { forwardRef } from 'react'
import type { HTMLAttributes } from 'react'

export interface CartItemProps extends HTMLAttributes<HTMLDivElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItem = forwardRef<HTMLDivElement, CartItemProps>(function CartItem(
{ testId = 'store-cart-item', children, ...otherProps },
ref
) {
return (
<article ref={ref} data-fs-cart-item data-testid={testId} {...otherProps}>
{children}
</article>
)
})

export default CartItem
24 changes: 24 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { forwardRef } from 'react'
import type { HTMLAttributes } from 'react'

export interface CartItemActionsProps extends HTMLAttributes<HTMLDivElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemActions = forwardRef<HTMLDivElement, CartItemActionsProps>(
function CartItemActions(
{ testId = 'store-cart-item-actions', children, ...otherProps },
ref
) {
return (
<div ref={ref} data-fs-cart-item-actions data-testid={testId} {...otherProps}>
{children}
</div>
)
}
)

export default CartItemActions
24 changes: 24 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

export interface CartItemContentProps extends HTMLAttributes<HTMLElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemContent = forwardRef<HTMLElement, CartItemContentProps>(
function CartItemContent(
{ testId = 'store-cart-item-content', children, ...otherProps },
ref
) {
return (
<section ref={ref} data-fs-cart-item-content data-testid={testId} {...otherProps}>
{children}
</section>
)
}
)

export default CartItemContent
22 changes: 22 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

export interface CartItemImageProps extends HTMLAttributes<HTMLDivElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemImage = forwardRef<HTMLDivElement, CartItemImageProps>(function CartItemImage(
{ testId = 'store-cart-item-image', children, ...otherProps },
ref
) {
return (
<div ref={ref} data-fs-cart-item-image data-testid={testId} {...otherProps}>
{children}
</div>
)
})

export default CartItemImage
24 changes: 24 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemPrices.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { forwardRef } from 'react'
import type { HTMLAttributes } from 'react'

export interface CartItemPricesProps extends HTMLAttributes<HTMLSpanElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemPrices = forwardRef<HTMLSpanElement, CartItemPricesProps>(
function CartItemPrices(
{ testId = 'store-cart-item-prices', children, ...otherProps },
ref
) {
return (
<span ref={ref} data-fs-cart-item-prices data-testid={testId} {...otherProps}>
{children}
</span>
)
}
)

export default CartItemPrices
24 changes: 24 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { forwardRef } from 'react'
import type { HTMLAttributes } from 'react'

export interface CartItemSummaryProps extends HTMLAttributes<HTMLDivElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemSummary = forwardRef<HTMLDivElement, CartItemSummaryProps>(
function CartItemSummary(
{ testId = 'store-cart-item-summary', children, ...otherProps },
ref
) {
return (
<div ref={ref} data-fs-cart-item-summary data-testid={testId} {...otherProps}>
{children}
</div>
)
}
)

export default CartItemSummary
22 changes: 22 additions & 0 deletions packages/ui/src/molecules/CartItem/CartItemTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { HTMLAttributes } from 'react'
import React, { forwardRef } from 'react'

export interface CartItemTitleProps extends HTMLAttributes<HTMLDivElement> {
/**
* ID to find this component in testing tools (e.g.: Cypress, Testing Library, and Jest).
*/
testId?: string
}

const CartItemTitle = forwardRef<HTMLDivElement, CartItemTitleProps>(function CartItemTitle(
{ testId = 'store-cart-item-title', children, ...otherProps },
ref
) {
return (
<div ref={ref} data-fs-cart-item-title data-testid={testId} {...otherProps}>
{children}
</div>
)
})

export default CartItemTitle
20 changes: 20 additions & 0 deletions packages/ui/src/molecules/CartItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export { default } from './CartItem'
export type { CartItemProps } from './CartItem'

export { default as CartItemActions } from './CartItemActions'
export type { CartItemActionsProps } from './CartItemActions'

export { default as CartItemContent } from './CartItemContent'
export type { CartItemContentProps } from './CartItemContent'

export { default as CartItemImage } from './CartItemImage'
export type { CartItemImageProps } from './CartItemImage'

export { default as CartItemPrices } from './CartItemPrices'
export type { CartItemPricesProps } from './CartItemPrices'

export { default as CartItemSummary } from './CartItemSummary'
export type { CartItemSummaryProps } from './CartItemSummary'

export { default as CartItemTitle } from './CartItemTitle'
export type { CartItemTitleProps } from './CartItemTitle'
Loading

1 comment on commit ff70925

@vercel
Copy link

@vercel vercel bot commented on ff70925 Sep 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.