diff --git a/.gitignore b/.gitignore
index b6e47617d..5d725c7f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@ __pycache__/
*.py[cod]
*$py.class
+#node_modules
+node_modules
+
# C extensions
*.so
diff --git a/package-lock.json b/package-lock.json
index ca840cc2f..c094db7fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "bootstrap": "^5.2.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.7.1",
@@ -3078,6 +3079,16 @@
}
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -5358,6 +5369,24 @@
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
+ "node_modules/bootstrap": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/twbs"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ }
+ ],
+ "peerDependencies": {
+ "@popperjs/core": "^2.11.8"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
diff --git a/src/App.js b/src/App.js
index 5d1f338a3..26f248246 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,16 +1,40 @@
import React from 'react';
-import 'bootstrap/dist/css/bootstrap.min.css';
+import 'bootstrap/dist/css/bootstrap.min.css';
+
+
import { AppProvider } from './context/AppContext';
import CartValue from './components/CartValue';
import ExpenseList from './components/ExpenseList';
import ItemSelected from './components/ItemSelected';
import Location from './components/Location';
-function App() {
+const App = () => {
return (
-
-
+
+
+
Shopping App
+
+
Shopping Cart
+
+
Add Items
+
+
+
);
-}
-
-export default App;
+};
+export default App;
\ No newline at end of file
diff --git a/src/components/CartValue.js b/src/components/CartValue.js
index b1d063540..835d4c313 100644
--- a/src/components/CartValue.js
+++ b/src/components/CartValue.js
@@ -2,6 +2,16 @@ import React, { useContext } from 'react';
import { AppContext } from '../context/AppContext';
const CartValue = () => {
+ const { expenses, Location } = useContext(AppContext);
+ const totalExpenses = expenses.reduce((total, item) => {
+ return (total += (item.unitprice * item.quantity));
+ }, 0);
+
+ return (
+
+ Cart Value: {Location}{totalExpenses}
+
+ );
};
-export default CartValue;
+export default CartValue;
\ No newline at end of file
diff --git a/src/components/ExpenseItem.js b/src/components/ExpenseItem.js
index 067d1824e..d4441bac1 100644
--- a/src/components/ExpenseItem.js
+++ b/src/components/ExpenseItem.js
@@ -3,6 +3,29 @@ import { AppContext } from '../context/AppContext';
import { FaTimesCircle } from 'react-icons/fa';
const ExpenseItem = (props) => {
+ const { dispatch, Location } = useContext(AppContext);
+
+ const handleDeleteItem = () => {
+ const item = {
+ name: props.name,
+ };
+
+ dispatch({
+ type: 'DELETE_ITEM',
+ payload: item,
+ });
+ };
+
+
+ return (
+
+ {props.name} |
+ {props.quantity} |
+ {Location}{parseInt(props.unitprice)} |
+ {Location}{parseInt(props.quantity) * parseInt(props.unitprice)} |
+ |
+
+ );
};
-export default ExpenseItem;
+export default ExpenseItem;
\ No newline at end of file
diff --git a/src/components/ExpenseList.js b/src/components/ExpenseList.js
index 3c7a8af08..79f87e1ad 100644
--- a/src/components/ExpenseList.js
+++ b/src/components/ExpenseList.js
@@ -1,7 +1,28 @@
import React, { useContext } from 'react';
+import ExpenseItem from './ExpenseItem';
import { AppContext } from '../context/AppContext';
const ExpenseList = () => {
+ const { expenses } = useContext(AppContext);
+
+ return (
+
+
+
+ Items |
+ Quantity |
+ Unit Price |
+ Items Price |
+ Remove |
+
+
+
+ {expenses.map((expense) => (
+
+ ))}
+
+
+ );
};
-export default ExpenseList;
+export default ExpenseList;
\ No newline at end of file
diff --git a/src/components/ItemSelected.js b/src/components/ItemSelected.js
index 14045b414..b501f29e3 100644
--- a/src/components/ItemSelected.js
+++ b/src/components/ItemSelected.js
@@ -2,6 +2,76 @@ import React, { useContext, useState } from 'react';
import { AppContext } from '../context/AppContext';
const ItemSelected = (props) => {
+ const { dispatch } = useContext(AppContext);
+
+ const [name, setName] = useState('');
+ const [quantity, setQuantity] = useState('');
+ const [action, setAction] = useState('');
+
+
+ const submitEvent = () => {
+
+ const item = {
+ name: name,
+ quantity: parseInt(quantity),
+ };
+
+ if (action === "Reduce") {
+ dispatch({
+ type: 'RED_QUANTITY',
+ payload: item,
+ });
+ } else {
+ dispatch({
+ type: 'ADD_QUANTITY',
+ payload: item,
+ });
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
setQuantity(event.target.value)}>
+
+
+
+
+
+
+
+ );
};
-export default ItemSelected;
+export default ItemSelected;
\ No newline at end of file
diff --git a/src/components/Location.js b/src/components/Location.js
index c947c4258..98fde1a62 100644
--- a/src/components/Location.js
+++ b/src/components/Location.js
@@ -2,6 +2,27 @@ import React, { useContext } from 'react';
import { AppContext } from '../context/AppContext';
const Location = () => {
+ const { dispatch } = useContext(AppContext);
+
+ const changeLocation = (val) => {
+ dispatch({
+ type: 'CHG_LOCATION',
+ payload: val,
+ })
+ }
+
+
+ return (
+ Location {
+
+ }
+
+ );
};
export default Location;
\ No newline at end of file
diff --git a/src/context/AppContext.js b/src/context/AppContext.js
index 44355a62b..a4d6fa515 100644
--- a/src/context/AppContext.js
+++ b/src/context/AppContext.js
@@ -1 +1,100 @@
-import React, { createContext, useReducer } from 'react';
\ No newline at end of file
+import React, { createContext, useReducer } from 'react';
+
+// 5. The reducer - this is used to update the state, based on the action
+export const AppReducer = (state, action) => {
+ let new_expenses = [];
+ switch (action.type) {
+ case 'ADD_QUANTITY':
+ let updatedqty = false;
+ state.expenses.map((expense) => {
+ if (expense.name === action.payload.name) {
+ expense.quantity = expense.quantity + action.payload.quantity;
+ updatedqty = true;
+ }
+ new_expenses.push(expense);
+ return true;
+ })
+ state.expenses = new_expenses;
+ action.type = "DONE";
+ return {
+ ...state,
+ };
+
+ case 'RED_QUANTITY':
+ state.expenses.map((expense) => {
+ if (expense.name === action.payload.name) {
+ expense.quantity = expense.quantity - action.payload.quantity;
+ }
+ expense.quantity = expense.quantity < 0 ? 0 : expense.quantity;
+ new_expenses.push(expense);
+ return true;
+ })
+ state.expenses = new_expenses;
+ action.type = "DONE";
+ return {
+ ...state,
+ };
+ case 'DELETE_ITEM':
+ state.expenses.map((expense) => {
+ if (expense.name === action.payload.name) {
+ expense.quantity = 0;
+ }
+ new_expenses.push(expense);
+ return true;
+ })
+ state.expenses = new_expenses;
+ action.type = "DONE";
+ return {
+ ...state,
+ };
+ case 'CHG_LOCATION':
+ action.type = "DONE";
+ state.Location = action.payload;
+ return {
+ ...state
+ }
+
+ default:
+ return state;
+ }
+};
+
+// 1. Sets the initial state when the app loads
+const initialState = {
+ expenses: [
+ { id: "Shirt", name: 'Shirt', quantity: 0, unitprice: 500 },
+ { id: "Jeans", name: 'Jeans', quantity: 0, unitprice: 300 },
+ { id: "Dress", name: 'Dress', quantity: 0, unitprice: 400 },
+ { id: "Dinner set", name: 'Dinner set', quantity: 0, unitprice: 600 },
+ { id: "Bags", name: 'Bags', quantity: 0, unitprice: 200 },
+ ],
+ Location: '£'
+};
+
+// 2. Creates the context this is the thing our components import and use to get the state
+export const AppContext = createContext();
+
+// 3. Provider component - wraps the components we want to give access to the state
+// Accepts the children, which are the nested(wrapped) components
+export const AppProvider = (props) => {
+ // 4. Sets up the app state. takes a reducer, and an initial state
+ const [state, dispatch] = useReducer(AppReducer, initialState);
+
+ const totalExpenses = state.expenses.reduce((total, item) => {
+ return (total = total + (item.unitprice * item.quantity));
+ }, 0);
+ state.CartValue = totalExpenses;
+
+ return (
+
+ {props.children}
+
+ );
+};
\ No newline at end of file