Skip to content

Commit

Permalink
Fix all linting errors
Browse files Browse the repository at this point in the history
Had to override one of the link accesibility lints due to nextjs bug

vercel/next.js#5533
  • Loading branch information
marcqualie committed Dec 7, 2018
1 parent 6828cae commit 66307cd
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 46 deletions.
20 changes: 19 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,23 @@
"@moltin",
"@moltin/eslint-config/rules/react",
"@moltin/eslint-config/rules/react-a11y"
]
],
"rules": {
"jsx-a11y/anchor-is-valid": [
"error",
{
"components": [
"Link"
],
"specialLink": [
"hrefLeft",
"hrefRight"
],
"aspects": [
"invalidHref",
"preferButton"
]
}
]
}
}
18 changes: 17 additions & 1 deletion components/cart-item.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class CartItem extends Component {
render() {
const {
id, name, description, image, meta, quantity,
} = this.props.item
} = this.props

return (
<tr key={id}>
Expand All @@ -25,4 +26,19 @@ class CartItem extends Component {
}
}

CartItem.propTypes = {
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
quantity: PropTypes.number.isRequired,
description: PropTypes.string,
image: PropTypes.shape({ href: PropTypes.string }),
meta: PropTypes.object, // eslint-disable-line react/forbid-prop-types
}

CartItem.defaultProps = {
description: '',
image: { href: '' },
meta: {},
}

export default CartItem
18 changes: 13 additions & 5 deletions components/navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Link from 'next/link'
import { connect } from 'react-redux'

import { loadCart } from '../store'
import { loadCart, loadProducts } from '../store'

class Navbar extends Component {
componentDidMount() {
const { cartId } = this.props
this.props.dispatch(loadCart(cartId))
const { cartId, dispatch } = this.props
dispatch(loadProducts())
dispatch(loadCart(cartId))
}

render() {
Expand All @@ -22,7 +24,7 @@ class Navbar extends Component {
<div className="container d-flex justify-content-between">
<Link href="/">
<a className="navbar-brand">
Winter Wonderland
Winter Wonderland
</a>
</Link>

Expand All @@ -35,7 +37,7 @@ class Navbar extends Component {
<span>
{cartItemLength}
{' '}
items
items
</span>
</a>
</Link>
Expand All @@ -48,5 +50,11 @@ items
}
}

Navbar.propTypes = {
cartId: PropTypes.string.isRequired,
cartItems: PropTypes.arrayOf(PropTypes.object).isRequired,
dispatch: PropTypes.func.isRequired,
}

const mapStateToProps = state => ({ cartItems: state.cartItems, cartId: state.cartId })
export default connect(mapStateToProps)(Navbar)
33 changes: 26 additions & 7 deletions components/product.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { addToCart } from '../store'

class Product extends Component {
async addToCart() {
const { id, cartId } = this.props
this.props.dispatch(addToCart(cartId, id))
const { dispatch, id, cartId } = this.props
dispatch(addToCart(cartId, id))
}

render() {
const {
id, description, meta, main_image, name, sku, tax_code,
id, description, meta, main_image: mainImage, name, sku, tax_code: taxCode,
} = this.props

return (
<div key={id} className="card">
<img className="card-img-top" src={main_image.link.href} alt={name} />
<img className="card-img-top" src={mainImage.link.href} alt={name} />
<div className="card-body">
<h3 className="card-title">{name}</h3>
<p className="card-text">{description}</p>
Expand All @@ -25,7 +26,7 @@ SKU:
<br />
Tax Code:
{' '}
{tax_code}
{taxCode}
</p>
</div>
<div className="card-footer">
Expand All @@ -34,14 +35,32 @@ Tax Code:
{' '}
<small className="text-muted">(+ tax)</small>
</div>
<button onClick={() => this.addToCart()} className="float-right btn btn-primary">
Buy Now
<button type="button" onClick={() => this.addToCart()} className="float-right btn btn-primary">
Buy Now
</button>
</div>
</div>
)
}
}


Product.propTypes = {
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
sku: PropTypes.string.isRequired,
tax_code: PropTypes.string.isRequired,
main_image: PropTypes.shape({ href: '' }),
description: PropTypes.string,
meta: PropTypes.object, // eslint-disable-line react/forbid-prop-types
dispatch: PropTypes.func.isRequired,
}

Product.defaultProps = {
description: {},
main_image: { href: '' },
meta: {},
}

const mapStateToProps = state => ({ cartItems: state.cartItems, cartId: state.cartId })
export default connect(mapStateToProps)(Product)
2 changes: 1 addition & 1 deletion lib/moltin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createClient } from '@moltin/request'

export const client = new createClient({
export const client = new createClient({ // eslint-disable-line new-cap
client_id: '4c1wMvFpowqjse795EwbddDIk56z3PKgSyMFNW7JSd',
})

Expand Down
27 changes: 18 additions & 9 deletions lib/with-redux-store.js → lib/with-redux-store.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@ import React from 'react'
import { initializeStore } from '../store'

const isServer = typeof window === 'undefined'
const __NEXT_REDUX_STORE__ = '__NEXT_REDUX_STORE__'
const NEXT_REDUX_STORE = '__NEXT_REDUX_STORE__'

function getOrCreateStore(initialState) {
/* global window */
const getOrCreateStore = (initialState) => {
// Always make a new store if server, otherwise state is shared between requests
if (isServer) {
return initializeStore(initialState)
}

if (typeof window === 'undefined') {
return initializeStore(initialState)
}

// Create store if unavailable on the client and set it on the window object
if (!window[__NEXT_REDUX_STORE__]) {
window[__NEXT_REDUX_STORE__] = initializeStore(initialState)
if (!window[NEXT_REDUX_STORE]) {
window[NEXT_REDUX_STORE] = initializeStore(initialState)
}
return window[__NEXT_REDUX_STORE__]
return window[NEXT_REDUX_STORE]
}

export default App => class AppWithRedux extends React.Component {
Expand All @@ -23,12 +28,16 @@ export default App => class AppWithRedux extends React.Component {
// This allows you to set a custom default initialState
const reduxStore = getOrCreateStore()

// Provide the store to getInitialProps of pages
appContext.ctx.reduxStore = reduxStore

let appProps = {}
if (typeof App.getInitialProps === 'function') {
appProps = await App.getInitialProps(appContext)
appProps = await App.getInitialProps({
...appContext,
ctx: {
...appContext.ctx,
// Provide the store to getInitialProps of pages
reduxStore,
},
})
}

return {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@moltin/request": "^1.4.1",
"next": "^7.0.2",
"prop-types": "^15.6.2",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-redux": "^6.0.0",
Expand Down
5 changes: 3 additions & 2 deletions pages/cart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { loadProducts } from '../store'

class CartPage extends Component {
componentDidMount() {
this.props.dispatch(loadProducts())
const { dispatch } = this.props
dispatch(loadProducts())
}

render() {
Expand All @@ -27,7 +28,7 @@ class CartPage extends Component {
</tr>
</thead>
<tbody>
{cartItems.map(item => <CartItem item={item} {...cartItems} />)}
{cartItems.map(item => <CartItem key={item.id} {...item} />)}
</tbody>
</table>
</div>
Expand Down
5 changes: 0 additions & 5 deletions pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ import React, { Component } from 'react'
import { connect } from 'react-redux'

import Product from '../components/product'
import { loadProducts } from '../store'

class ProductsPage extends Component {
componentDidMount() {
this.props.dispatch(loadProducts())
}

render() {
const { products } = this.props

Expand Down
32 changes: 18 additions & 14 deletions store.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,24 @@ export const reducer = (state = initialState, action) => {
}
}

// Quick helpers to set some state
export const setProducts = products => ({ type: actionTypes.SET_PRODUCTS, products })
export const setCartItems = items => ({ type: actionTypes.SET_CART_ITEMS, items })

export const loadProducts = () => async (dispatch) => {
const products = await client.get('products?include=main_images')

products.data.map((product) => {
products.included.main_images.map((image) => {
if (image.id == product.relationships.main_image.data.id) {
product.main_image = image
}
})
const data = products.data.map((product) => {
const mainImage = products.included.main_images.find(image => (
image.id === product.relationships.main_image.data.id
))
return {
...product,
main_image: mainImage,
}
})

dispatch(setProducts(products.data))
dispatch(setProducts(data))
}

export const addToCart = (cartId, productId) => async (dispatch) => {
Expand All @@ -61,13 +67,11 @@ export const loadCart = cartId => async (dispatch) => {
dispatch(setCartItems(data))
}

export const setProducts = products => ({ type: actionTypes.SET_PRODUCTS, products })

export const setCartItems = items => ({ type: actionTypes.SET_CART_ITEMS, items })

export function initializeStore(initialStoreState = initialState) {
if (initialStoreState.cartId === null) {
initialStoreState.cartId = generateUUID()
export function initializeStore(state = initialState) {
const cartId = state.cartId || generateUUID()
const initialStoreState = {
...state,
cartId,
}
return createStore(reducer, initialStoreState, applyMiddleware(thunkMiddleware))
}
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@

"@moltin/eslint-config@git+ssh://[email protected]:moltin/eslint-config":
version "1.0.0"
resolved "git+ssh://[email protected]:moltin/eslint-config#dc1dfa481e6faf5ed620b16df4420f112e79d09d"
resolved "git+ssh://[email protected]:moltin/eslint-config#8123111faf0bd64212c89e36882db64dad96c7e0"
dependencies:
eslint "^5.8.0"
eslint-plugin-import "^2.14.0"
Expand Down

0 comments on commit 66307cd

Please sign in to comment.