diff --git a/packages/venia-concept/src/components/ButtonGroup/__tests__/buttonGroup.spec.js b/packages/venia-concept/src/components/ButtonGroup/__tests__/buttonGroup.spec.js new file mode 100644 index 0000000000..398eb3f19e --- /dev/null +++ b/packages/venia-concept/src/components/ButtonGroup/__tests__/buttonGroup.spec.js @@ -0,0 +1,34 @@ +import React from 'react'; +import TestRenderer from 'react-test-renderer'; + +import Button from '../button'; +import ButtonGroup from '../buttonGroup'; + +jest.mock('src/classify'); +jest.mock('../button'); + +test('renders a div', () => { + const { root } = TestRenderer.create(); + + const el = root.findByProps({ className: 'root' }); + + expect(el).toBeTruthy(); +}); + +test('renders children from `items`', () => { + const items = [ + { key: 'a', children: 'a' }, + { key: 'b', children: 'b' }, + { key: 'c', children: 'c' } + ]; + + const { root } = TestRenderer.create(); + + const el = root.findByProps({ className: 'root' }); + + expect(el.children).toHaveLength(3); + + for (const child of el.children) { + expect(child.type).toBe(Button); + } +}); diff --git a/packages/venia-concept/src/components/ButtonGroup/button.css b/packages/venia-concept/src/components/ButtonGroup/button.css new file mode 100644 index 0000000000..9ceaa906c1 --- /dev/null +++ b/packages/venia-concept/src/components/ButtonGroup/button.css @@ -0,0 +1,53 @@ +.root { + composes: root from '../clickable.css'; + background: none white; + border: 1px solid rgb(var(--venia-grey-dark)); + color: rgb(var(--venia-text)); + font-size: 0.75rem; + font-weight: 600; + height: 2rem; + margin-left: -1px; + min-width: 6rem; + transition-duration: 384ms; + transition-property: border-color, color; + transition-timing-function: var(--venia-anim-standard); + z-index: 1; +} + +.root:hover { + border-color: rgb(var(--venia-text)); + z-index: 2; +} + +.root:focus { + border-color: rgb(var(--venia-teal)); + box-shadow: 0 0 0 2px rgb(var(--venia-teal-light)), + 0 0 0.5rem 2px rgba(var(--venia-teal), 0.2); + color: rgb(var(--venia-teal)); + outline: none; + transition-duration: 128ms; + z-index: 3; +} + +.root:disabled { + border-color: rgb(var(--venia-grey-dark)); + color: rgb(var(--venia-grey-dark)); +} + +.root:nth-of-type(1) { + border-radius: 0.25rem 0 0 0.25rem; + margin-left: 0; +} + +.root:nth-last-of-type(1) { + border-radius: 0 0.25rem 0.25rem 0; +} + +.content { + align-items: center; + display: inline-grid; + gap: 0.5rem; + grid-auto-flow: column; + justify-content: center; + justify-items: center; +} diff --git a/packages/venia-concept/src/components/ButtonGroup/button.js b/packages/venia-concept/src/components/ButtonGroup/button.js new file mode 100644 index 0000000000..a5a27735dd --- /dev/null +++ b/packages/venia-concept/src/components/ButtonGroup/button.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; +import { shape, string } from 'prop-types'; + +import classify from 'src/classify'; +import defaultClasses from './button.css'; + +class Button extends Component { + static propTypes = { + classes: shape({ + content: string, + root: string + }).isRequired + }; + + render() { + const { children, classes, ...rest } = this.props; + + return ( + + ); + } +} + +export default classify(defaultClasses)(Button); diff --git a/packages/venia-concept/src/components/ButtonGroup/buttonGroup.css b/packages/venia-concept/src/components/ButtonGroup/buttonGroup.css new file mode 100644 index 0000000000..d597246284 --- /dev/null +++ b/packages/venia-concept/src/components/ButtonGroup/buttonGroup.css @@ -0,0 +1,6 @@ +.root { + display: inline-grid; + grid-auto-flow: column; + justify-content: start; + position: relative; +} diff --git a/packages/venia-concept/src/components/ButtonGroup/buttonGroup.js b/packages/venia-concept/src/components/ButtonGroup/buttonGroup.js new file mode 100644 index 0000000000..6a654ba15a --- /dev/null +++ b/packages/venia-concept/src/components/ButtonGroup/buttonGroup.js @@ -0,0 +1,36 @@ +import React, { Component } from 'react'; +import { arrayOf, node, shape, string } from 'prop-types'; + +import classify from 'src/classify'; +import Button from './button'; +import defaultClasses from './buttonGroup.css'; + +class ButtonGroup extends Component { + static propTypes = { + classes: shape({ + root: string + }).isRequired, + items: arrayOf( + shape({ + children: node.isRequired, + key: string.isRequired + }) + ).isRequired + }; + + static defaultProps = { + items: [] + }; + + render() { + const { classes, items } = this.props; + + const children = Array.from(items, ({ key, ...itemProps }) => ( + - ); - } - - render() { - const { classes, buttonGroupItems } = this.props; - - return ( -
- {buttonGroupItems.map(item => { - return this.getButtonGroupItem(item); - })} -
- ); - } -} - -export default classify(defaultClasses)(ButtonGroup); diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/__snapshots__/orderItem.spec.js.snap b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/__snapshots__/orderItem.spec.js.snap new file mode 100644 index 0000000000..1667f3e5c2 --- /dev/null +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/__snapshots__/orderItem.spec.js.snap @@ -0,0 +1,197 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders the expected tree 1`] = ` +
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ 43 +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+`; diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/orderItem.spec.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/orderItem.spec.js index f5191966ec..64a01c481e 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/orderItem.spec.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/__tests__/orderItem.spec.js @@ -1,10 +1,10 @@ import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; +import TestRenderer from 'react-test-renderer'; + import OrderItem from '../orderItem'; -import ButtonGroup from '../ButtonGroup'; +import classes from '../orderItem.css'; -configure({ adapter: new Adapter() }); +jest.mock('src/classify'); const itemMock = { id: 1, @@ -17,31 +17,70 @@ const itemMock = { sku: '24-MB01' }; -const classes = { - main: 'main', - imageAndPropsContainer: 'imageAndPropsContainer', - titleImage: 'titleImage', - propsColumnContainer: 'propsColumnContainer', - priceContainer: 'priceContainer' -}; +test('renders the expected tree', () => { + const tree = TestRenderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +test('renders elements with classnames', () => { + const { root } = TestRenderer.create(); + + expect(root.findByProps({ className: 'root' })).toBeTruthy(); + expect(root.findByProps({ className: 'main' })).toBeTruthy(); + expect(root.findByProps({ className: 'image' })).toBeTruthy(); + expect(root.findByProps({ className: 'propsList' })).toBeTruthy(); + expect(root.findByProps({ className: 'price' })).toBeTruthy(); + expect(root.findAllByProps({ className: 'propLabel' })).toHaveLength(4); + expect(root.findAllByProps({ className: 'propValue' })).toHaveLength(4); +}); + +test('defaults price to 0', () => { + const { price, ...customItemMock } = itemMock; + + const { root } = TestRenderer.create(); + + void price; + const element = root.findByProps({ className: 'price' }).children[0]; + + expect(element.props.value).toBe(0); +}); + +test('calls onBuyItem with item', () => { + const onBuyItem = jest.fn(); + + const { root } = TestRenderer.create( + + ); + + root.findByProps({ classes }).instance.buyItem(); + + expect(onBuyItem).toHaveBeenCalledTimes(1); + expect(onBuyItem).toHaveBeenLastCalledWith(itemMock); +}); + +test('calls onReviewItem with item', () => { + const onReviewItem = jest.fn(); + + const { root } = TestRenderer.create( + + ); + + root.findByProps({ classes }).instance.reviewItem(); + + expect(onReviewItem).toHaveBeenCalledTimes(1); + expect(onReviewItem).toHaveBeenLastCalledWith(itemMock); +}); + +test('calls onShareItem with item', () => { + const onShareItem = jest.fn(); + + const { root } = TestRenderer.create( + + ); + + root.findByProps({ classes }).instance.shareItem(); -test('renders correctly', () => { - const onBuyAgainMock = jest.fn(); - const onShareMock = jest.fn(); - - const wrapper = shallow( - - ).dive(); - - expect(wrapper.find(`.${classes.main}`)).toHaveLength(1); - expect(wrapper.find(`.${classes.imageAndPropsContainer}`)).toHaveLength(1); - expect(wrapper.find(`.${classes.titleImage}`)).toHaveLength(1); - expect(wrapper.find(`.${classes.propsColumnContainer}`)).toHaveLength(1); - expect(wrapper.find(`.${classes.priceContainer}`)).toHaveLength(1); - expect(wrapper.find(ButtonGroup)).toHaveLength(1); + expect(onShareItem).toHaveBeenCalledTimes(1); + expect(onShareItem).toHaveBeenLastCalledWith(itemMock); }); diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/constants.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/constants.js deleted file mode 100644 index 71750be35d..0000000000 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/constants.js +++ /dev/null @@ -1,12 +0,0 @@ -import PropTypes from 'prop-types'; - -export const itemPropType = PropTypes.shape({ - id: PropTypes.number, - name: PropTypes.string, - size: PropTypes.string, - color: PropTypes.string, - qty: PropTypes.number, - titleImageSrc: PropTypes.string, - price: PropTypes.number, - sku: PropTypes.string -}); diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/helpers.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/helpers.js deleted file mode 100644 index 97351aabb2..0000000000 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/helpers.js +++ /dev/null @@ -1,21 +0,0 @@ -export const getButtonGroupItems = ( - buyAgainHandler, - shareItemHandler, - reviewItemHandler -) => [ - { - onClickHandler: buyAgainHandler, - iconName: 'shopping-cart', - textNode: 'Buy Again' - }, - { - onClickHandler: shareItemHandler, - iconName: 'share-2', - textNode: 'Share Item' - }, - { - onClickHandler: reviewItemHandler, - iconName: 'message-square', - textNode: 'Review Item' - } -]; diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.css b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.css index 26f273dbe1..258351a296 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.css +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.css @@ -1,33 +1,54 @@ -.main { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0.5rem; +.root { + border-top: 1px solid rgb(var(--venia-border)); + display: grid; + gap: 1rem; + padding-top: 1.5rem; +} + +.root:nth-of-type(1) { + border-top-width: 0; + padding-top: 0; } -.imageAndPropsContainer { - display: flex; +.main { + display: grid; + gap: 1rem; + grid-auto-flow: column; + grid-template-columns: auto 1fr; } -.titleImage { +.image { height: 5rem; - margin-right: 0.375rem; } -.propsColumnContainer { - max-width: 10rem; +.image[src^='data:image'] { + background-color: rgb(var(--venia-grey)); +} + +.propsList { + align-items: center; + display: grid; font-size: 0.75rem; - line-height: 1.125rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + gap: 0 1.5rem; + grid-template-columns: auto auto; + justify-content: start; + line-height: 1rem; +} + +.propLabel { + color: rgb(var(--venia-text-alt)); +} + +.propLabel:nth-of-type(1) { + display: none; } -.name { +.propValue:nth-of-type(1) { font-weight: 600; + grid-column: 1 / span 2; } -.priceContainer { +.price { font-size: 0.75rem; - line-height: 0.9375rem; + line-height: 1rem; } diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.js index 91d6a25c39..2732a39d87 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItem/orderItem.js @@ -1,76 +1,152 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React, { Component, Fragment } from 'react'; +import { func, number, shape, string } from 'prop-types'; import { Price } from '@magento/peregrine'; +import MessageSquareIcon from 'react-feather/dist/icons/message-square'; +import ShoppingCartIcon from 'react-feather/dist/icons/shopping-cart'; +import Share2Icon from 'react-feather/dist/icons/share-2'; + import classify from 'src/classify'; +import ButtonGroup from 'src/components/ButtonGroup'; +import Icon from 'src/components/Icon'; import defaultClasses from './orderItem.css'; -import ButtonGroup from './ButtonGroup'; -import { itemPropType } from './constants'; -import { getButtonGroupItems } from './helpers'; + +const noop = () => {}; class OrderItem extends Component { static propTypes = { - classes: PropTypes.shape({ - root: PropTypes.string, - main: PropTypes.string, - imageAndPropsContainer: PropTypes.string, - titleImage: PropTypes.string, - propsColumnContainer: PropTypes.string, - title: PropTypes.string, - priceContainer: PropTypes.string + classes: shape({ + image: string, + main: string, + price: string, + propLabel: string, + propValue: string, + propsList: string, + root: string }), - item: itemPropType, - onBuyAgain: PropTypes.func, - onShare: PropTypes.func, - currencyCode: PropTypes.string + currencyCode: string, + item: shape({ + color: string, + id: number, + name: string, + price: number, + qty: number, + size: string, + sku: string, + titleImageSrc: string + }), + onBuyItem: func, + onReviewItem: func, + onShareItem: func }; //TODO: get currencyCode whether from item object or from order or from user cart static defaultProps = { item: {}, - currencyCode: 'USD' + currencyCode: 'USD', + onBuyItem: noop, + onReviewItem: noop, + onShareItem: noop }; - //TODO: make correct mapping from item - onBuyAgainHandler = () => { - this.props.onBuyAgain({ item: this.props.item, quantity: 1 }); + + buyItem = () => { + const { item, onBuyItem } = this.props; + + onBuyItem(item); }; - //TODO: make correct mapping from item - onShareHandler = () => { - this.props.onShare(this.props.item); + + reviewItem = () => { + const { item, onReviewItem } = this.props; + + onReviewItem(item); }; + shareItem = () => { + const { item, onShareItem } = this.props; + + onShareItem(item); + }; + + get buyContent() { + return ( + + + Buy + + ); + } + + get reviewContent() { + return ( + + + Review + + ); + } + + get shareContent() { + return ( + + + Share + + ); + } + render() { const { - classes, - item: { titleImageSrc, name, size, color, qty, price }, - currencyCode - } = this.props; - //TODO: implement reviewItem handler and use as argument in below function - const buttonGroupItems = getButtonGroupItems( - this.onBuyAgainHandler, - this.onShareHandler - ); + buyContent, + buyItem, + props, + reviewContent, + reviewItem, + shareContent, + shareItem + } = this; + const { classes, currencyCode, item } = props; + const { color, name, price, qty, size, titleImageSrc } = item; + + const buttonGroupItems = [ + { + key: 'buy', + onClick: buyItem, + children: buyContent + }, + { + key: 'share', + onClick: shareItem, + children: shareContent + }, + { + key: 'review', + onClick: reviewItem, + children: reviewContent + } + ]; return (
-
- itemOfClothes -
-
{name}
-
Size : {size}
-
Color : {color}
-
Qty : {qty}
-
-
-
+ itemOfClothes +
+
Name
+
{name}
+
Size
+
{size}
+
Color
+
{color}
+
Quantity
+
{qty}
+
+
- +
); } diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/OrderItemsList.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/OrderItemsList.js index c3532cd71d..b61f071c8a 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/OrderItemsList.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/OrderItemsList.js @@ -1,45 +1,50 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import { array, func, shape, string } from 'prop-types'; import { List } from '@magento/peregrine'; -import { itemPropType } from '../OrderItem/constants'; -import OrderItem from '../OrderItem'; import classify from 'src/classify'; +import OrderItem from '../OrderItem'; import defaultClasses from './orderItemsList.css'; class OrderItemsList extends Component { static propTypes = { - classes: PropTypes.shape({ - body: PropTypes.string, - header: PropTypes.string, - defaultItemRoot: PropTypes.string, - itemsContainer: PropTypes.string + classes: shape({ + heading: string, + list: string, + root: string }), - title: PropTypes.string, - items: PropTypes.arrayOf(itemPropType), - onBuyAgain: PropTypes.func, - onShare: PropTypes.func + items: array, + onBuyItem: func, + onReviewItem: func, + onShareItem: func, + title: string }; render() { - const { classes, items, title, onBuyAgain, onShare } = this.props; + const { + classes, + items, + onBuyItem, + onReviewItem, + onShareItem, + title + } = this.props; + return ( -
-

{title}

+
+

{title}

id} render={props => ( -
- {props.children} -
+
{props.children}
)} renderItem={props => ( )} /> diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/__snapshots__/orderItemsList.spec.js.snap b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/__snapshots__/orderItemsList.spec.js.snap new file mode 100644 index 0000000000..dd3c91410e --- /dev/null +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/__snapshots__/orderItemsList.spec.js.snap @@ -0,0 +1,403 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders the expected tree 1`] = ` +
+

+ a +

+
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ 42 +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ 42 +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+
+
+`; diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/orderItemsList.spec.js b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/orderItemsList.spec.js index 5c6a9e2437..9efe315d39 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/orderItemsList.spec.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/__tests__/orderItemsList.spec.js @@ -1,14 +1,9 @@ import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { List } from '@magento/peregrine'; -import OrderItemsList from '../OrderItemsList'; +import TestRenderer from 'react-test-renderer'; -configure({ adapter: new Adapter() }); +import OrderItemsList from '../OrderItemsList'; -const classes = { - header: 'header' -}; +jest.mock('src/classify'); const itemsMock = [ { @@ -33,11 +28,20 @@ const itemsMock = [ } ]; -test('renders correctly', () => { - const wrapper = shallow( - - ).dive(); +test('renders the expected tree', () => { + const tree = TestRenderer.create( + + ); + + expect(tree).toMatchSnapshot(); +}); + +test('renders elements with classnames', () => { + const { root } = TestRenderer.create( + + ); - expect(wrapper.find(`.${classes.header}`)).toHaveLength(1); - expect(wrapper.find(List)).toHaveLength(1); + expect(root.findByProps({ className: 'root' })).toBeTruthy(); + expect(root.findByProps({ className: 'heading' })).toBeTruthy(); + expect(root.findByProps({ className: 'list' })).toBeTruthy(); }); diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/orderItemsList.css b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/orderItemsList.css index c11478993f..751d320244 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/orderItemsList.css +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/OrderItemsList/orderItemsList.css @@ -1,20 +1,12 @@ -.body { - margin: 1rem 0 1.125rem; +.root { } -.defaultItemRoot { - padding: 0.625rem 0 2rem; - border-bottom: 1px solid rgb(var(--venia-border)); +.heading { + font-size: 0.875rem; + margin: 1rem 0 1.5rem; } -.defaultItemRoot:first-child { - padding-top: 2rem; - border-top: 1px solid rgb(var(--venia-border)); -} - -.header { - margin-bottom: 0.625rem; - font-size: 0.75rem; - font-weight: 600; - line-height: 0.875rem; +.list { + display: grid; + gap: 1.5rem; } diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/__snapshots__/purchaseDetails.spec.js.snap b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/__snapshots__/purchaseDetails.spec.js.snap new file mode 100644 index 0000000000..02ab4eb4c5 --- /dev/null +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/__snapshots__/purchaseDetails.spec.js.snap @@ -0,0 +1,718 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders the expected tree 1`] = ` +
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ size +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+

+ Order Details +

+
+
+ Order No +
+
+ orderNo +
+
+ Order Date +
+
+ orderDate +
+
+ Total +
+
+ total +
+
+ Products +
+
+ products +
+
+
+

+ Other Items in this Order +

+
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ size +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ size +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+
+
+ itemOfClothes +
+
+ Name +
+
+ name +
+
+ Size +
+
+ size +
+
+ Color +
+
+ color +
+
+ Quantity +
+
+ 1 +
+
+
+
+
+
+
+ + + +
+
+
+
+

+ Shipment Details +

+
+
+ Method +
+
+ method +
+
+ Delivered +
+
+ delivered +
+
+
+ +
+

+ Payment Details +

+
+
+ Method +
+
+ method +
+
+ Billing Address +
+
+ billingAddress +
+
+ Shipping Address +
+
+ shippingAddress +
+
+

+ Order Summary +

+
+
+ Items +
+
+ items +
+
+ Shipping and Handling +
+
+ shippingAndHandling +
+
+ Estimated Tax +
+
+ estimatedTax +
+
+
+`; diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/purchaseDetails.spec.js b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/purchaseDetails.spec.js index ab691f223c..28a21f6902 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/purchaseDetails.spec.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/__tests__/purchaseDetails.spec.js @@ -1,13 +1,12 @@ import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import DetailsBlock from '../../DetailsBlock'; +import TestRenderer from 'react-test-renderer'; + +import LoadingIndicator from 'src/components/LoadingIndicator'; import PurchaseDetails from '../purchaseDetails'; -import OrderItem from '../../OrderItem'; -import OrderItemsList from '../../OrderItemsList'; -import Button from 'src/components/Button'; -configure({ adapter: new Adapter() }); +jest.mock('src/components/LoadingIndicator'); + +const fetchOrderDetailsMock = jest.fn(); const commonOrderDetailsMock = [ { property: 'Order No', value: 'orderNo' }, @@ -65,7 +64,7 @@ const otherItemsMock = [ sku: 'sku' }, { - id: 1, + id: 2, name: 'name', size: 'size', color: 'color', @@ -75,7 +74,7 @@ const otherItemsMock = [ sku: 'sku' }, { - id: 1, + id: 3, name: 'name', size: 'size', color: 'color', @@ -86,21 +85,53 @@ const otherItemsMock = [ } ]; -test('renders correctly', () => { - const fetchOrderDetailsMock = jest.fn(); - const wrapper = shallow( +test('renders the expected tree', () => { + const tree = TestRenderer.create( + ).toJSON(); + + expect(tree).toMatchSnapshot(); +}); + +test('calls fetchOrderDetails on mount', () => { + TestRenderer.create( + + ); + + expect(fetchOrderDetailsMock).toHaveBeenCalledTimes(1); +}); + +test('renders a loading indicator while loading', () => { + const { root } = TestRenderer.create( + - ).dive(); - expect(wrapper.find(DetailsBlock)).toHaveLength(4); - expect(wrapper.find(Button)).toHaveLength(1); - expect(wrapper.find(OrderItem)).toHaveLength(1); - expect(wrapper.find(OrderItemsList)).toHaveLength(1); + ); + + const spinner = root.findByType(LoadingIndicator); + + expect(spinner).toBeTruthy(); }); diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/dress.jpg b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/dress.jpg deleted file mode 100644 index de489d6f42..0000000000 Binary files a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/dress.jpg and /dev/null differ diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/helpers.js b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/helpers.js deleted file mode 100644 index 9e060670f2..0000000000 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/helpers.js +++ /dev/null @@ -1,3 +0,0 @@ -import kebabCase from 'lodash/kebabCase'; -//TODO: implementation should be changed in the future -export const getProductPageUrl = ({ name }) => `/${kebabCase(name)}.html`; diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.css b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.css index 189df681ee..3988f57624 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.css +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.css @@ -1,60 +1,12 @@ .root { + display: grid; + gap: 1rem; margin: 0 auto; max-width: 60rem; - padding: 1rem 1.75rem; + padding: 2rem 1.75rem; } -.orderDetailsHeaderText { - color: black; - font-size: 0.875rem; - font-weight: 300; - line-height: 0.875rem; - text-align: center; - text-transform: uppercase; - margin-top: 2rem; - margin-bottom: 1rem; -} - -.detailsBlockHeaderText { - color: black; - font-size: 0.75rem; - font-weight: 600; - line-height: 1.125rem; - margin-bottom: 0.5rem; -} - -.customDetailsBlock { - composes: root from '../DetailsBlock/detailsBlock.css'; - margin-bottom: 1rem; -} - -.orderDetailsBlockRoot { - composes: customDetailsBlock; - padding: 1rem 0.625rem 0.5rem; -} - -.shipmentBlockRoot { - composes: customDetailsBlock; - padding: 0.5rem 0.625rem 0.625rem; -} - -.trackButtonRoot { - border-radius: 1.5rem; - min-width: 8.75rem; - background-color: black; - height: auto; - padding: 0.25rem 0.125rem; - border-color: black; - margin-bottom: 2rem; -} - -.trackButtonRoot:hover { - background-color: black; -} - -.trackButtonContent { - color: white; - font-size: 0.75rem; - line-height: 0.75rem; - text-align: center; +.heading { + font-size: 1rem; + margin-top: 1rem; } diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.js b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.js index a8cc0651bd..67c8d980ee 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetails.js @@ -1,108 +1,92 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import Button from 'src/components/Button'; +import { any, array, bool, func, shape, string } from 'prop-types'; + import classify from 'src/classify'; -import defaultClasses from './purchaseDetails.css'; +import Button from 'src/components/Button'; +import { loadingIndicator } from 'src/components/LoadingIndicator'; import OrderItem from '../OrderItem'; -import { itemPropType } from '../OrderItem/constants'; import OrderItemsList from '../OrderItemsList'; import DetailsBlock from '../DetailsBlock'; -import { getProductPageUrl } from './helpers'; +import defaultClasses from './purchaseDetails.css'; class PurchaseDetails extends Component { static propTypes = { - shipmentDetails: PropTypes.array, - orderDetails: PropTypes.array, - paymentDetails: PropTypes.array, - orderSummary: PropTypes.array, - classes: PropTypes.shape({}), - addItemToCart: PropTypes.func, - item: itemPropType, - otherItems: PropTypes.arrayOf(itemPropType), - fetchOrderDetails: PropTypes.func, - isFetching: PropTypes.bool + classes: shape({ + heading: string, + root: string, + shipmentActions: string + }).isRequired, + fetchOrderDetails: func.isRequired, + isFetching: bool, + item: any, + orderDetails: array, + orderSummary: array, + otherItems: array, + paymentDetails: array, + shipmentDetails: array }; - //TODO: implement executing url params for orderId and itemId - componentDidMount() { - this.props.fetchOrderDetails({}); - } + handleBuyItem = () => { + // TODO: wire up + }; - handleShare = item => { - const { history } = this.props; + handleReviewItem = () => { + // TODO: wire up + }; - history.push(getProductPageUrl(item)); + handleShareItem = () => { + // TODO: wire up }; - renderComponent = () => { + componentDidMount() { + // TODO: include orderId, itemId + this.props.fetchOrderDetails({}); + } + + render() { const { - shipmentDetails, - orderDetails, - paymentDetails, - orderSummary, classes, + isFetching, item, + orderDetails, + orderSummary, otherItems, - addItemToCart + paymentDetails, + shipmentDetails } = this.props; + if (isFetching) { + return loadingIndicator; + } + return (
-

- Order details -

- +

Order Details

+ -

- Shipment Details -

- - -

- Payment Details -

- -

- Order Summary -

- +

Shipment Details

+ +
+ +
+

Payment Details

+ +

Order Summary

+
); - }; - - render() { - const { isFetching } = this.props; - - return !isFetching ? this.renderComponent() :
Loading...
; } } diff --git a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetailsContainer.js b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetailsContainer.js index f0e0217bd0..f8944aefa9 100644 --- a/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetailsContainer.js +++ b/packages/venia-concept/src/components/PurchaseDetailsPage/PurchaseDetails/purchaseDetailsContainer.js @@ -1,7 +1,5 @@ import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { withRouter } from 'react-router-dom'; -import { addItemToCart } from 'src/actions/cart/asyncActions'; + import { fetchOrderDetails } from 'src/actions/purchaseDetails/asyncActions'; import purchaseDetailsPage from './purchaseDetails'; import { @@ -14,18 +12,17 @@ import { getItem } from './selectors'; -export default compose( - connect( - state => ({ - shipmentDetails: getShipmentDetails(state), - orderDetails: getCommonOrderDetails(state), - paymentDetails: getPaymentDetails(state), - orderSummary: getOrderSummary(state), - isFetching: getFetchingStatus(state), - otherItems: getOtherItems(state), - item: getItem(state) - }), - { addItemToCart, fetchOrderDetails } - ), - withRouter +// TODO: refactor to avoid all these selectors for simple object properties + +export default connect( + state => ({ + shipmentDetails: getShipmentDetails(state), + orderDetails: getCommonOrderDetails(state), + paymentDetails: getPaymentDetails(state), + orderSummary: getOrderSummary(state), + isFetching: getFetchingStatus(state), + otherItems: getOtherItems(state), + item: getItem(state) + }), + { fetchOrderDetails } )(purchaseDetailsPage);