diff --git a/client/app.js b/client/app.js index 2dc72eb..4ef0fdf 100644 --- a/client/app.js +++ b/client/app.js @@ -3,13 +3,25 @@ import React from 'react' import {Navbar} from './components' import Routes from './routes' -const App = () => { +const App = (props) => { + /* + if (props.unknownError) { + return
ERROR: {props.unknownError.message}. Please contact support.
+ } + if (props.unauthenticatedError) { + return + } + */ return (
- + {props.unknownError ?
Error
: }
) } -export default App +const mapState = (state) => { + return { unknownError: state.error.unknownError } +} + +export default connect(mapState, undefined)(App) diff --git a/client/components/EditProduct.js b/client/components/EditProduct.js index f1b61c1..bcfeaf6 100644 --- a/client/components/EditProduct.js +++ b/client/components/EditProduct.js @@ -141,7 +141,8 @@ const mapDispatchToProps = (dispatch, ownProps) => ({ const mapStateToProps = (state, ownProps) => { return { selectedProduct: state.products.selectedProduct, - isAdmin: state.currentUser.isAdmin + isAdmin: state.currentUser.isAdmin, + badRequest: state.error.badRequest } } diff --git a/client/components/home-page.js b/client/components/home-page.js index d32abae..2da4295 100644 --- a/client/components/home-page.js +++ b/client/components/home-page.js @@ -13,6 +13,10 @@ import { Pagination } from 'semantic-ui-react' +// GET /products +// state.products = [/* all the products */] + +// REVIEW: how large is allProducts const ProductsOnCurPage = (allProducts, curPage, itemsPerPage) => { return allProducts.slice( (curPage - 1) * itemsPerPage, diff --git a/client/store/categories.js b/client/store/categories.js index 670af10..43a852d 100644 --- a/client/store/categories.js +++ b/client/store/categories.js @@ -9,19 +9,24 @@ const getCategories = categories => ({ categories }) +const error = error => ({ type: 'ERROR', error }) + // Initial State const initialState = [] + // Thunk Creators export const fetchCategories = () => async dispatch => { try { const {data} = await axios.get('/api/products/categories') dispatch(getCategories(data)) } catch (error) { - console.log(error) + dispatch(error(error)) } } +// REVIEW: discuss alternate patterns for reducer cases +// and the value of consistency const dispatchers = { [GET_CATEGORIES]: (state, action) => action.categories } diff --git a/client/store/index.js b/client/store/index.js index bf8c955..991b488 100644 --- a/client/store/index.js +++ b/client/store/index.js @@ -12,6 +12,28 @@ import storage from 'redux-persist/lib/storage' import autoMergeLevel2 from 'redux-persist/es/stateReconciler/autoMergeLevel2' import orders from './orders' import reviews from './reviews' +//import errors from './errors' + +function errorReducer (state={}, action) { + if (action.type === GET_USER) return { ...state, unauthenticatedError: undefined } + if (action.type !== 'ERROR') return state + + const error = action.error; + if (error.response && error.response.status) { + if (error.response.status === 401) { + return {...state, unauthenticatedError: error } + } + else if (error.response.status === 403) { + return {...state, unauthorizedError: error } + } + else if (error.response.status === 400) { + return {...state, badRequest: error } + } + } + if (error) { + return {...state, unknownError: error} + } +} const reducer = combineReducers({ users, @@ -20,7 +42,8 @@ const reducer = combineReducers({ categories, cart, orders, - reviews + reviews, + error: errorReducer, }) const middleware = composeWithDevTools( diff --git a/client/store/orders.js b/client/store/orders.js index 6187e68..d64de12 100644 --- a/client/store/orders.js +++ b/client/store/orders.js @@ -19,6 +19,7 @@ export const editOrder = updatedOrder => ({type: EDIT_ORDER, updatedOrder}) // THUNK-TIONS export const fetchOrders = () => { + // REVIEW: gotta handle errors return async dispatch => { const {data} = await axios.get('/api/orders') dispatch(setOrders(data)) diff --git a/server/api/orders.js b/server/api/orders.js index 0b8e7bc..b7b8e07 100644 --- a/server/api/orders.js +++ b/server/api/orders.js @@ -18,6 +18,10 @@ router.get('/', adminCheckMiddleware, async (req, res, next) => { // Associated non-admin User instance should also have access to these specific routes +// REVIEW: +// GET /orders/user/:userId +// vs +// GET /users/:userId/orders router.get('/user/:userId', loginCheckMiddleware, async (req, res, next) => { try { const whichOrders = await Order.findAll({ diff --git a/server/api/products.js b/server/api/products.js index b849c5c..723eb3d 100644 --- a/server/api/products.js +++ b/server/api/products.js @@ -5,15 +5,71 @@ module.exports = router // All users can view all products and product by id +// PUBLIC api +// - no matter who requests this endpoint +// - no matter when they request this endpoint +// - everybody should see tha same data +// - based purely on the url (include query string) +// +// GET /products?page=2&category=sharpeners +// [...] +// +// GET /products?page=2&category=sharpeners +// [...] +// +// PRIVATE api +// - only some people CAN request this +// - different people get different data back +// +// GET /me +// { name: 'collin' } +// { name: 'finn' } router.get('/', async (req, res, next) => { try { - const allProducts = await Product.findAll({include: [Category]}) - res.json(allProducts) + // GET /products?page=2 + const page = req.query.page || 1 + const perPage = 10 + const currentPage = 1 + const offset = (currentPage - 1) * perPage; + // select * from products limit 10 offset ${offset} order by updateAt desc + // REVIEW: pagination + const pageOfProducts = await Product.findAll({ + include: [{model: Category, fields: ['title']}], + limit: perPage, + offset: offset, + orderBy: 'updatedAt desc' + }) + res.json(pageOfProducts) } catch (err) { next(err) } }) +// includes +// home page +// - list of products +// - prints title, image, price, category +// +// short-list +// - bullett list of title +// +// GET /products?page=1&category=sharpeners&include[]=Category&CategoryFields[]=title&CategoryFields[]=id +// GraphQL +// const query = ` +// query { +// products { +// id +// title +// price +// categories { +// id +// name +// } +// } +// ` +// const result = await runGraphQL(query) +// result.data.products[0].categories[0].name + router.get('/categories', async (req, res, next) => { try { const allCategories = await Category.findAll()