From e5c620aa48aebce7d3eedf4a1fbd79eaddb36a18 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz Date: Sun, 4 Aug 2024 18:02:10 -0400 Subject: [PATCH 01/10] Main --- frontend/components/PizzaForm.js | 70 ++++++++++++++-- frontend/state/Orderapi.js | 35 ++++++++ frontend/state/Orderslice.js | 35 ++++++++ frontend/state/store.js | 9 ++- package-lock.json | 133 ++++++++++++++++++++++--------- package.json | 3 +- 6 files changed, 236 insertions(+), 49 deletions(-) create mode 100644 frontend/state/Orderapi.js create mode 100644 frontend/state/Orderslice.js diff --git a/frontend/components/PizzaForm.js b/frontend/components/PizzaForm.js index 39f0509..516d1c3 100644 --- a/frontend/components/PizzaForm.js +++ b/frontend/components/PizzaForm.js @@ -1,4 +1,8 @@ -import React from 'react' +import React, { useReducer } from 'react' +import { useCreateOrderMutation } from '../state/Orderapi' + +const CHANGE_INPUT = 'CHANGE_INPUT' +const RESET_FORM = 'RESET_FORM' const initialFormState = { // suggested fullName: '', @@ -10,12 +14,64 @@ const initialFormState = { // suggested '5': false, } +const reducer = (state, action) => { + switch (action.type) { + case CHANGE_INPUT: { + const { name, value } = action.payload + return { ...state, [name]: value } + } + case RESET_FORM: + return { + fullName: '', + size: '', + '1': false, + '2': false, + '3': false, + '4': false, + '5': false, + } + default: return state + } +} + export default function PizzaForm() { + const [state, dispatch] = useReducer(reducer, initialFormState) + const [createOrder, { error: createOrderError, isLoading: creatingOrder }] = useCreateOrderMutation() + const onChange = ({ target: { name, value } }) => { + dispatch({ type: CHANGE_INPUT, payload: { name, value } }) + } + const resetForm = () => { + dispatch({ type: RESET_FORM }) + } + const onNewOrder = evt => { + evt.preventDefault() + const { fullName, size, + '1': pepperoni, + '2': greenPeppers, + '3': pineapple, + '4': mushrooms, + '5': ham } = state + createOrder({ + fullName, size, + '1': pepperoni, + '2': greenPeppers, + '3': pineapple, + '4': mushrooms, + '5': ham + }) + .unwrap() + .then(() => { + resetForm() + }) + .catch(err => { + console.log(err) + }) + } return ( -
+

Pizza Form

- {true &&
Order in progress...
} - {true &&
Order failed: fullName is required
} + {true &&
{creatingOrder && creatingOrder.data.message}
} + {true &&
{createOrderError}
}
@@ -25,7 +81,9 @@ export default function PizzaForm() { id="fullName" name="fullName" placeholder="Type full name" + onChange={onChange} type="text" + value={state.fullName} />
@@ -33,7 +91,7 @@ export default function PizzaForm() {

- @@ -62,4 +120,4 @@ export default function PizzaForm() { ) -} +} \ No newline at end of file diff --git a/frontend/state/Orderapi.js b/frontend/state/Orderapi.js new file mode 100644 index 0000000..3fa04ef --- /dev/null +++ b/frontend/state/Orderapi.js @@ -0,0 +1,35 @@ +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; + +export const orderApi = createApi({ + reducerPath: 'orderApi', + baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:9009/api/pizza/'}), + tagTypes: ['History', 'Order'], + endpoints: build => ({ + getHistory: build.query({ + query: () => 'history', + providesTags: ['History'] + }), + createOrder: build.mutation({ + query: order => ({ + url: 'order', + method: 'POST', + body: order + }), + invalidatesTags: ['Order'] + }), + filterSize: build.mutation({ + query: ({ size, hx }) => ({ + url: `history/${size}`, + method: 'PUT', + body: hx + }), + invalidatesTags: ['History'] + }) + }) +}) + +export const { + useGetHistoryQuery, + useCreateOrderMutation, + useFilterSizeMutation +} = orderApi \ No newline at end of file diff --git a/frontend/state/Orderslice.js b/frontend/state/Orderslice.js new file mode 100644 index 0000000..a2cf9c9 --- /dev/null +++ b/frontend/state/Orderslice.js @@ -0,0 +1,35 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + displayAllSizes: true, + amountOfToppings: 0, + '1': false, + '2': false, + '3': false, + '4': false, + '5': false +} + +export const orderSlice = createSlice({ + name: 'order', + initialState, + reducers: { + toggleSizes(state) { + state.displayAllSizes = !state.displayAllSizes + }, + setAmountOfToppings(state, action) { + if('1' || '2' || '3' || '4' || '5' === true) { + state.amountOfToppings + action.payload + } else { + state.amountOfToppings = 0 + } + } + } +}) + +export const { + toggleSizes, + setAmountOfToppings +} = orderSlice.actions + +export default orderSlice.reducer \ No newline at end of file diff --git a/frontend/state/store.js b/frontend/state/store.js index bc9b754..fd33335 100644 --- a/frontend/state/store.js +++ b/frontend/state/store.js @@ -1,4 +1,6 @@ import { configureStore } from '@reduxjs/toolkit' +import orderReducer from './Orderslice' +import { orderApi } from './Orderapi' const exampleReducer = (state = { count: 0 }) => { return state @@ -6,13 +8,14 @@ const exampleReducer = (state = { count: 0 }) => { export const resetStore = () => configureStore({ reducer: { - example: exampleReducer, - // add your reducer(s) here + orderState: orderReducer, + [orderApi.reducerPath]: orderApi.reducer }, middleware: getDefault => getDefault().concat( // if using RTK Query for your networking: add your middleware here // if using Redux Thunk for your networking: you can ignore this + orderApi.middleware ), }) -export const store = resetStore() +export const store = resetStore() \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2d49b6c..4640f23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "w_s10_challenge", "version": "0.0.1", "dependencies": { - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.7", "axios": "^1.6.7", "cors": "^2.8.5", "express": "^4.18.2", @@ -16,6 +16,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", + "react-router": "^6.26.0", "react-router-dom": "^6.22.1", "styled-components": "^6.1.8", "yup": "^1.3.3" @@ -3183,14 +3184,15 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz", - "integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.7.tgz", + "integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==", + "license": "MIT", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "reselect": "^5.0.1" + "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", @@ -4832,12 +4834,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4845,7 +4848,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -4858,6 +4861,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4865,7 +4869,8 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", @@ -4894,12 +4899,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4995,6 +5001,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5637,6 +5644,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5651,6 +5659,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -7183,16 +7192,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7223,6 +7233,15 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7380,10 +7399,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7543,15 +7563,16 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -8982,6 +9003,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -11843,6 +11865,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13295,6 +13318,7 @@ "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -13364,9 +13388,10 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -13433,11 +13458,12 @@ } }, "node_modules/react-router": { - "version": "6.22.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", - "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", + "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.15.1" + "@remix-run/router": "1.19.0" }, "engines": { "node": ">=14.0.0" @@ -13462,6 +13488,30 @@ "react-dom": ">=16.8" } }, + "node_modules/react-router-dom/node_modules/react-router": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", + "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router/node_modules/@remix-run/router": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", + "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -15157,6 +15207,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -15267,6 +15318,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -15686,14 +15738,16 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.0.0.tgz", - "integrity": "sha512-tZ5hqsWwww/8DislmrzXE3x+4f+v10H1z57mA2dWFrILb4i3xX+dPhTkcdR0DLyQztrhF2AUmO5nN085UYjd/Q==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, @@ -16256,10 +16310,11 @@ "dev": true }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 81e181b..4969638 100755 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "webpack-dev-server": "^5.0.2" }, "dependencies": { - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.7", "axios": "^1.6.7", "cors": "^2.8.5", "express": "^4.18.2", @@ -49,6 +49,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^9.1.0", + "react-router": "^6.26.0", "react-router-dom": "^6.22.1", "styled-components": "^6.1.8", "yup": "^1.3.3" From 99fe1ed487ddce29d13a763a648baf8f8d18e913 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:50:36 -0400 Subject: [PATCH 02/10] Update App.js From 00f1b497dd407971d3ef3267fc414ba869193fe6 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:51:23 -0400 Subject: [PATCH 03/10] Update PizzaForm.js --- frontend/components/PizzaForm.js | 192 +++++++++++++++++++------------ 1 file changed, 120 insertions(+), 72 deletions(-) diff --git a/frontend/components/PizzaForm.js b/frontend/components/PizzaForm.js index 516d1c3..5b6fc68 100644 --- a/frontend/components/PizzaForm.js +++ b/frontend/components/PizzaForm.js @@ -1,78 +1,83 @@ -import React, { useReducer } from 'react' -import { useCreateOrderMutation } from '../state/Orderapi' +import React, { useReducer, useState } from 'react'; +import { useCreateOrderMutation } from '../state/ordersApi'; -const CHANGE_INPUT = 'CHANGE_INPUT' -const RESET_FORM = 'RESET_FORM' +const CHANGE_INPUT = 'CHANGE_INPUT'; +const TOGGLE_TOPPING = 'TOGGLE_TOPPING'; +const RESET_FORM = 'RESET_FORM'; -const initialFormState = { // suggested +const initialFormState = { fullName: '', size: '', - '1': false, - '2': false, - '3': false, - '4': false, - '5': false, -} + toppings: [], +}; const reducer = (state, action) => { switch (action.type) { case CHANGE_INPUT: { - const { name, value } = action.payload - return { ...state, [name]: value } + const { name, value } = action.payload; + return { ...state, [name]: value }; + } + case TOGGLE_TOPPING: { + const { topping } = action.payload; + const newToppings = state.toppings.includes(topping) + ? state.toppings.filter(t => t !== topping) + : [...state.toppings, topping]; + return { ...state, toppings: newToppings }; } case RESET_FORM: - return { - fullName: '', - size: '', - '1': false, - '2': false, - '3': false, - '4': false, - '5': false, - } - default: return state + return initialFormState; + default: + return state; } -} +}; export default function PizzaForm() { - const [state, dispatch] = useReducer(reducer, initialFormState) - const [createOrder, { error: createOrderError, isLoading: creatingOrder }] = useCreateOrderMutation() + const [state, dispatch] = useReducer(reducer, initialFormState); + const [error, setError] = useState(''); + const [createOrder, { isLoading: creatingOrder }] = useCreateOrderMutation(); + const onChange = ({ target: { name, value } }) => { - dispatch({ type: CHANGE_INPUT, payload: { name, value } }) - } + dispatch({ type: CHANGE_INPUT, payload: { name, value } }); + setError(''); + }; + + const onToppingChange = ({ target: { name } }) => { + dispatch({ type: TOGGLE_TOPPING, payload: { topping: name } }); + }; + const resetForm = () => { - dispatch({ type: RESET_FORM }) - } - const onNewOrder = evt => { - evt.preventDefault() - const { fullName, size, - '1': pepperoni, - '2': greenPeppers, - '3': pineapple, - '4': mushrooms, - '5': ham } = state - createOrder({ - fullName, size, - '1': pepperoni, - '2': greenPeppers, - '3': pineapple, - '4': mushrooms, - '5': ham - }) + dispatch({ type: RESET_FORM }); + setError(''); + }; + + const handleSubmit = (evt) => { + evt.preventDefault(); + const { fullName, size, toppings } = state; + + if (!fullName) { + setError('fullName is required'); + return; + } + if (!['S', 'M', 'L'].includes(size)) { + setError('Size must be one of the following values: S, M, L'); + return; + } + + createOrder({ fullName, size, toppings }) .unwrap() .then(() => { - resetForm() - }) - .catch(err => { - console.log(err) + resetForm(); }) - } + .catch((err) => { + setError('Order failed: ' + err.message); + }); + }; + return ( -
+

Pizza Form

- {true &&
{creatingOrder && creatingOrder.data.message}
} - {true &&
{createOrderError}
} - + {creatingOrder &&
Order in progress...
} + {error &&
{error}
}

@@ -81,17 +86,22 @@ export default function PizzaForm() { id="fullName" name="fullName" placeholder="Type full name" - onChange={onChange} type="text" value={state.fullName} + onChange={onChange} />
-

- @@ -99,25 +109,63 @@ export default function PizzaForm() {
-
+ + Pepperoni
+ + + Green Peppers
+ + + Pineapple
+ + + Mushrooms
+ + + Ham
+
- +
- ) -} \ No newline at end of file + ); +} From d3ffcd40c6270c05603231741e3c635e1068c8c6 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:51:58 -0400 Subject: [PATCH 04/10] Update OrderList.js --- frontend/components/OrderList.js | 53 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/frontend/components/OrderList.js b/frontend/components/OrderList.js index 548c197..cd2de8f 100644 --- a/frontend/components/OrderList.js +++ b/frontend/components/OrderList.js @@ -1,35 +1,52 @@ -import React from 'react' +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useGetOrdersQuery } from '../state/ordersApi'; +import { toggleSizeFilter } from '../state/ordersSlice'; export default function OrderList() { - const orders = [] + // eslint-disable-next-line no-unused-vars + const { data: orders, isLoading: ordersLoading, isFetching: ordersRefreshing, error } = useGetOrdersQuery(); + + const filterSize = useSelector(state => state.ordersState.filterSize); + const dispatch = useDispatch(); + + const handleSizeFilterChange = (size) => { + dispatch(toggleSizeFilter(size)); + }; + return (
-

Pizza Orders

+

Pizza Orders {(ordersLoading || ordersRefreshing) && 'loading...'}

    { - orders.map(() => { - return ( -
  1. -
    - order details here -
    -
  2. - ) - }) + ordersLoading ? 'loading...' : + orders?.filter(order => filterSize === 'All' || order.size === filterSize) + .map(order => ( +
  3. +
    +
    {order.customer} ordered a size {order.size} with {order.toppings?.length > 0 ? `${order.toppings.length} toppings` : 'no toppings'}
    +
    +
  4. + )) }
Filter by size: { ['All', 'S', 'M', 'L'].map(size => { - const className = `button-filter${size === 'All' ? ' active' : ''}` - return + const className = `button-filter${size === 'All' ? ' active' : ''}`; + return ( + + ); }) }
- ) + ); } From 9b6d5df87de5c383719db16bfba08706330151b4 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:52:25 -0400 Subject: [PATCH 05/10] Update App.js From 8db7aa58795e0665fee49f66062ff24bf17896cf Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:03:51 -0400 Subject: [PATCH 06/10] Update Orderapi.js --- frontend/state/Orderapi.js | 44 ++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/frontend/state/Orderapi.js b/frontend/state/Orderapi.js index 3fa04ef..b1c945f 100644 --- a/frontend/state/Orderapi.js +++ b/frontend/state/Orderapi.js @@ -1,35 +1,27 @@ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; -export const orderApi = createApi({ - reducerPath: 'orderApi', - baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:9009/api/pizza/'}), - tagTypes: ['History', 'Order'], - endpoints: build => ({ - getHistory: build.query({ +export const ordersApi = createApi({ + reducerPath: 'ordersApi', + baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:9009/api/pizza/' }), + tagTypes: ['Orders'], + endpoints: (builder) => ({ + getOrders: builder.query({ query: () => 'history', - providesTags: ['History'] + transformResponse: (response) => { + console.log('Fetched Orders:', response); + return response; + }, + providesTags: ['Orders'], }), - createOrder: build.mutation({ - query: order => ({ + createOrder: builder.mutation({ + query: (order) => ({ url: 'order', method: 'POST', - body: order + body: order, }), - invalidatesTags: ['Order'] + invalidatesTags: ['Orders'], }), - filterSize: build.mutation({ - query: ({ size, hx }) => ({ - url: `history/${size}`, - method: 'PUT', - body: hx - }), - invalidatesTags: ['History'] - }) - }) -}) + }), +}); -export const { - useGetHistoryQuery, - useCreateOrderMutation, - useFilterSizeMutation -} = orderApi \ No newline at end of file +export const { useGetOrdersQuery, useCreateOrderMutation} = ordersApi; From 087dcb5c60dd2f9f93562f401894fa861f2c2da7 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:04:17 -0400 Subject: [PATCH 07/10] Rename Orderapi.js to ordersApi.js --- frontend/state/{Orderapi.js => ordersApi.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename frontend/state/{Orderapi.js => ordersApi.js} (100%) diff --git a/frontend/state/Orderapi.js b/frontend/state/ordersApi.js similarity index 100% rename from frontend/state/Orderapi.js rename to frontend/state/ordersApi.js From 2ca0c6b470595e4c73b4821c3da2bb05112b779a Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:05:05 -0400 Subject: [PATCH 08/10] Update store.js --- frontend/state/store.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/frontend/state/store.js b/frontend/state/store.js index fd33335..98094fa 100644 --- a/frontend/state/store.js +++ b/frontend/state/store.js @@ -1,21 +1,16 @@ import { configureStore } from '@reduxjs/toolkit' -import orderReducer from './Orderslice' -import { orderApi } from './Orderapi' +import ordersReducer from './ordersSlice'; +import { ordersApi } from './ordersApi'; -const exampleReducer = (state = { count: 0 }) => { - return state -} export const resetStore = () => configureStore({ reducer: { - orderState: orderReducer, - [orderApi.reducerPath]: orderApi.reducer + ordersState: ordersReducer, + [ordersApi.reducerPath]: ordersApi.reducer, }, middleware: getDefault => getDefault().concat( - // if using RTK Query for your networking: add your middleware here - // if using Redux Thunk for your networking: you can ignore this - orderApi.middleware + ordersApi.middleware, ), }) -export const store = resetStore() \ No newline at end of file +export const store = resetStore() From 87b4c55da435a7846030d2dd69638fff99d2b3a9 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:07:43 -0400 Subject: [PATCH 09/10] Update and rename Orderslice.js to ordersSlice.js --- frontend/state/Orderslice.js | 35 ----------------------------------- frontend/state/ordersSlice.js | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 35 deletions(-) delete mode 100644 frontend/state/Orderslice.js create mode 100644 frontend/state/ordersSlice.js diff --git a/frontend/state/Orderslice.js b/frontend/state/Orderslice.js deleted file mode 100644 index a2cf9c9..0000000 --- a/frontend/state/Orderslice.js +++ /dev/null @@ -1,35 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; - -const initialState = { - displayAllSizes: true, - amountOfToppings: 0, - '1': false, - '2': false, - '3': false, - '4': false, - '5': false -} - -export const orderSlice = createSlice({ - name: 'order', - initialState, - reducers: { - toggleSizes(state) { - state.displayAllSizes = !state.displayAllSizes - }, - setAmountOfToppings(state, action) { - if('1' || '2' || '3' || '4' || '5' === true) { - state.amountOfToppings + action.payload - } else { - state.amountOfToppings = 0 - } - } - } -}) - -export const { - toggleSizes, - setAmountOfToppings -} = orderSlice.actions - -export default orderSlice.reducer \ No newline at end of file diff --git a/frontend/state/ordersSlice.js b/frontend/state/ordersSlice.js new file mode 100644 index 0000000..33c7eee --- /dev/null +++ b/frontend/state/ordersSlice.js @@ -0,0 +1,25 @@ +import { createSlice } from "@reduxjs/toolkit"; + +export const ordersSlice = createSlice({ + name: 'orders', + initialState: { + showAllOrders: true, + orderList: [], + filterSize: 'All', + }, + reducers: { + toggleShowAllOrders: state => { + state.showAllOrders = !state.showAllOrders; + }, + setOrders: (state, action) => { + state.orderList = action.payload; + }, + toggleSizeFilter: (state, action) => { + state.filterSize = action.payload; + }, + }, +}); + +export const { toggleShowAllOrders, setOrders, toggleSizeFilter } = ordersSlice.actions; + +export default ordersSlice.reducer; From f1712698a6bcef6ee492f16fbf5c3dd452960153 Mon Sep 17 00:00:00 2001 From: Brandon Notowitz <151097606+BNOTOWITZ@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:09:09 -0400 Subject: [PATCH 10/10] Update OrderList.js --- frontend/components/OrderList.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/components/OrderList.js b/frontend/components/OrderList.js index cd2de8f..67e7a82 100644 --- a/frontend/components/OrderList.js +++ b/frontend/components/OrderList.js @@ -4,7 +4,6 @@ import { useGetOrdersQuery } from '../state/ordersApi'; import { toggleSizeFilter } from '../state/ordersSlice'; export default function OrderList() { - // eslint-disable-next-line no-unused-vars const { data: orders, isLoading: ordersLoading, isFetching: ordersRefreshing, error } = useGetOrdersQuery(); const filterSize = useSelector(state => state.ordersState.filterSize);