diff --git a/public/imgsFinalPractice/auditorium.jpg b/public/imgsFinalPractice/auditorium.jpg new file mode 100644 index 00000000..ec301d44 Binary files /dev/null and b/public/imgsFinalPractice/auditorium.jpg differ diff --git a/public/imgsFinalPractice/conferenceRoom.jpg b/public/imgsFinalPractice/conferenceRoom.jpg new file mode 100644 index 00000000..a8d500a4 Binary files /dev/null and b/public/imgsFinalPractice/conferenceRoom.jpg differ diff --git a/public/imgsFinalPractice/meetingRoom.jpg b/public/imgsFinalPractice/meetingRoom.jpg new file mode 100644 index 00000000..f1a05957 Binary files /dev/null and b/public/imgsFinalPractice/meetingRoom.jpg differ diff --git a/public/imgsFinalPractice/microphone.jpg b/public/imgsFinalPractice/microphone.jpg new file mode 100644 index 00000000..162c9a5f Binary files /dev/null and b/public/imgsFinalPractice/microphone.jpg differ diff --git a/public/imgsFinalPractice/presentationRoom.jpg b/public/imgsFinalPractice/presentationRoom.jpg new file mode 100644 index 00000000..77e1d30e Binary files /dev/null and b/public/imgsFinalPractice/presentationRoom.jpg differ diff --git a/public/imgsFinalPractice/projector.jpg b/public/imgsFinalPractice/projector.jpg new file mode 100644 index 00000000..28b46697 Binary files /dev/null and b/public/imgsFinalPractice/projector.jpg differ diff --git a/public/imgsFinalPractice/signpost.jpg b/public/imgsFinalPractice/signpost.jpg new file mode 100644 index 00000000..07c775d1 Binary files /dev/null and b/public/imgsFinalPractice/signpost.jpg differ diff --git a/public/imgsFinalPractice/smallMeetingRoom.jpg b/public/imgsFinalPractice/smallMeetingRoom.jpg new file mode 100644 index 00000000..f57a9cf0 Binary files /dev/null and b/public/imgsFinalPractice/smallMeetingRoom.jpg differ diff --git a/public/imgsFinalPractice/speakers.jpg b/public/imgsFinalPractice/speakers.jpg new file mode 100644 index 00000000..55f71bb2 Binary files /dev/null and b/public/imgsFinalPractice/speakers.jpg differ diff --git a/public/imgsFinalPractice/whiteboard.png b/public/imgsFinalPractice/whiteboard.png new file mode 100644 index 00000000..ef496a02 Binary files /dev/null and b/public/imgsFinalPractice/whiteboard.png differ diff --git a/src/ConferenceEvent.jsx b/src/ConferenceEvent.jsx index 612a4648..d337a29d 100644 --- a/src/ConferenceEvent.jsx +++ b/src/ConferenceEvent.jsx @@ -1,16 +1,27 @@ -import React, { useState } from "react"; +import { useState } from "react"; import "./ConferenceEvent.css"; import TotalCost from "./TotalCost"; import { useSelector, useDispatch } from "react-redux"; import { incrementQuantity, decrementQuantity } from "./venueSlice"; +import { incrementAvQuantity, decrementAvQuantity } from "./avSlice.js"; +import { toggleMealSelection } from './mealsSlice.js'; + const ConferenceEvent = () => { const [showItems, setShowItems] = useState(false); const [numberOfPeople, setNumberOfPeople] = useState(1); + + // venue: const venueItems = useSelector((state) => state.venue); - const dispatch = useDispatch(); + const dispatch = useDispatch(); // used by all slices const remainingAuditoriumQuantity = 3 - venueItems.find(item => item.name === "Auditorium Hall (Capacity:200)").quantity; - + // av: + const avItems = useSelector((state) => state.av); + + // meals: + const mealsItems = useSelector((state) => state.meals); + + const handleToggleItems = () => { console.log("handleToggleItems called"); setShowItems(!showItems); @@ -23,29 +34,93 @@ const ConferenceEvent = () => { dispatch(incrementQuantity(index)); }; - const handleRemoveFromCart = (index) => { - if (venueItems[index].quantity > 0) { - dispatch(decrementQuantity(index)); - } - }; + const handleRemoveFromCart = (index) => { + if (venueItems[index].quantity > 0) { + dispatch(decrementQuantity(index)); + } + }; + + // av: const handleIncrementAvQuantity = (index) => { + dispatch(incrementAvQuantity(index)); }; - + // av: const handleDecrementAvQuantity = (index) => { + dispatch(decrementAvQuantity(index)); }; + // meals: const handleMealSelection = (index) => { - + const item = mealsItems[index]; + if(item.selected && item.type === 'mealForPeople'){ + const newNumberOfPeople = item.selected ? numberOfPeople : 0; + dispatch(toggleMealSelection(index, newNumberOfPeople)); + }else{ + dispatch(toggleMealSelection(index)); + } }; const getItemsFromTotalCost = () => { const items = []; + venueItems.forEach((item) => { + if(item.quantity > 0){ + items.push({...item, type: "venue"}); + } + }); + avItems.forEach((item) => { + if( + item.quantity && !items.some((i) => i.name === item.name && i.type === "av") + ) { + items.push({...item, type: "av"}); + } + }); + mealsItems.forEach((item) => { + if(item.selected){ + const itemForDisplay = { ...item, type: "meals" }; + if(item.numberOfPeople){ + itemForDisplay.numberOfPeople = numberOfPeople; + } + items.push(itemForDisplay); + } + }); + + return items; }; const items = getItemsFromTotalCost(); const ItemsDisplay = ({ items }) => { - + console.log(items); + return <> +
+ {items.length === 0 &&

No items selected

} + + + + + + + + + + + {items.map((item, index) => ( + + + + + + + ))} + +
NameUnit CostQuantitySubtotal
{item.name}{item.cost} + {item.type === "meals" || item.numberOfPeople ? + ` For ${numberOfPeople} people` : item.quantity} + {item.type === "meals" || item.numberOfPeople ? + `${item.cost * numberOfPeople}` : `${item.cost * item.quantity}`} +
+
+ }; const calculateTotalCost = (section) => { let totalCost = 0; @@ -53,11 +128,30 @@ const ConferenceEvent = () => { venueItems.forEach((item) => { totalCost += item.cost * item.quantity; }); + }else if(section === "av"){ // adding the costs of the data from the av items + avItems.forEach((item) => { + totalCost += item.cost * item.quantity; + }); + }else if(section == "meals"){ + mealsItems.forEach((item) => { + if(item.selected){ + totalCost += item.cost * numberOfPeople; // if item is selected, its cost is multiplied by the numberOfPeople + } + }); } + return totalCost; }; + + // venue: const venueTotalCost = calculateTotalCost("venue"); + // av: + const avTotalCost = calculateTotalCost("av"); + + // meals: + const mealsTotalCost = calculateTotalCost("meals"); + const navigateToProducts = (idType) => { if (idType == '#venue' || idType == '#addons' || idType == '#meals') { if (showItems) { // Check if showItems is false @@ -66,6 +160,13 @@ const ConferenceEvent = () => { } } + // object that include the all three subtotals in the totalcost + const totalCosts = { + venue: venueTotalCost, + av: avTotalCost, + meals: mealsTotalCost, + }; + return ( <> @@ -146,21 +247,29 @@ const ConferenceEvent = () => {
Total Cost: ${venueTotalCost}
- {/*Necessary Add-ons*/}
-
-

Add-ons Selection

-
- + {avItems.map((item, index) => ( +
+
+ {item.name} +
+
{item.name}
+
${item.cost}
+
+ + {item.quantity} + +
+
+ ))}
-
Total Cost:
- +
Total Cost: {avTotalCost}
{/* Meal Section */} @@ -168,18 +277,33 @@ const ConferenceEvent = () => {
-

Meals Selection

+
+ {mealsItems.map((item, index) => ( +
+
+ handleMealSelection(index)} + /> + +
+
${item.cost}
+
+ ))} +
- + + setNumberOfPeople(parseInt(e.target.value))} + min="1" />
-
Total Cost:
- +
Total Cost: {mealsTotalCost}
@@ -190,9 +314,6 @@ const ConferenceEvent = () => { ) } - - - @@ -200,3 +321,15 @@ const ConferenceEvent = () => { }; export default ConferenceEvent; + +/* + tip added from copilot suggestions + TIP: For optimal code quality and easier debugging, + consider adding PropTypes to validate component props. + Example: + import PropTypes from 'prop-types'; + MyComponent.propTypes = { + items: PropTypes.array.isRequired, + }; + This helps catch bugs early and documents expected prop types. +*/ \ No newline at end of file diff --git a/src/TotalCost.jsx b/src/TotalCost.jsx index 845abca9..4e4102ac 100644 --- a/src/TotalCost.jsx +++ b/src/TotalCost.jsx @@ -2,7 +2,8 @@ import React, { useState, useEffect } from 'react'; import "./TotalCost.css"; const TotalCost = ({ totalCosts, ItemsDisplay }) => { - + + const total_amount = totalCosts.venue + totalCosts.av + totalCosts.meals; return (
@@ -12,11 +13,10 @@ const TotalCost = ({ totalCosts, ItemsDisplay }) => {

- + ${total_amount}

- -
- +
+
diff --git a/src/avSlice.js b/src/avSlice.js index cdd79aac..7cfff684 100644 --- a/src/avSlice.js +++ b/src/avSlice.js @@ -1,19 +1,59 @@ import { createSlice } from "@reduxjs/toolkit"; - +// 1. adding objects to provide data structure +// 2. create logic for incrementAvQuantity() and decrementAvQuantity() functions +// 3. export all reducer functions and actions (ln-61 and ln-63) export const avSlice = createSlice({ name: "av", initialState: [ - + { + img: "./imgsFinalPractice/projector.jpg", + name: "Projectors", + cost: 200, + quantity: 0, + }, + { + img: "./imgsFinalPractice/speakers.jpg", + name: "Speaker", + cost: 35, + quantity: 0, + }, + { + img: "./imgsFinalPractice/microphone.jpg", + name: "Microphones", + cost: 45, + quantity: 0, + }, + { + img: "./imgsFinalPractice/whiteboard.png", + name: "Whiteboards", + cost: 80, + quantity: 0, + }, + { + img: "./imgsFinalPractice/signpost.jpg", + name: "Signage", + cost: 80, + quantity: 0, + }, + ], - reducers: { + reducers: { // reducer functions: + incrementAvQuantity: (state, action) => { - + const item = state[action.payload]; + if(item){ + item.quantity++; + } }, decrementAvQuantity: (state, action) => { - + const item = state[action.payload]; + if(item && item.quantity > 0){ + item.quantity--; + } }, + }, }); diff --git a/src/mealsSlice.js b/src/mealsSlice.js index faf8138a..fc672863 100644 --- a/src/mealsSlice.js +++ b/src/mealsSlice.js @@ -1,13 +1,19 @@ // mealsSlice.js import { createSlice } from '@reduxjs/toolkit'; - +// 1. including the meal items inside the initialState array +// 2. adding the logic needed for function reducer toggleMealSelection export const mealsSlice = createSlice({ name: 'meals', initialState: [ - + { name: 'Breakfast', cost: 50, selected: false }, + { name: 'High Tea', cost: 25, selected: false }, + { name: 'Lunch', cost: 65, selected: false }, + { name: 'Dinner', cost: 70, selected: false }, ], + // reducer functions: reducers: { toggleMealSelection: (state, action) => { + state[action.payload].selected = ! state[action.payload].selected; // uses [action.payload] to identify the item to update }, }, }); diff --git a/src/store.js b/src/store.js index f05b9f8f..96cf5937 100644 --- a/src/store.js +++ b/src/store.js @@ -1,9 +1,15 @@ // store.js import { configureStore } from '@reduxjs/toolkit'; import venueReducer from './venueSlice'; +import avReducer from './avSlice.js'; +import mealsReducer from './mealsSlice.js'; +// 3. adding into the redux store the avSlice +// 3.2 adding into the redux store the mealsSlice export default configureStore({ reducer: { - venue: venueReducer, + venue: venueReducer, + av: avReducer, // same name as the key-value pair 'name: "av" in avSlice.js + meals: mealsReducer, }, });