diff --git a/culinaryFrontend/src/App.css b/culinaryFrontend/src/App.css index 281f29c..a5e3015 100644 --- a/culinaryFrontend/src/App.css +++ b/culinaryFrontend/src/App.css @@ -128,6 +128,19 @@ background-image: url('assets/buttons/action_hover.svg'); } +.App-button-action-wide{ + background-size: contain; + width: 21vmin; + height: 5vmin; + color: black; + font-weight: 600; + background-image: url('assets/buttons/action_wide.svg'); +} + +.App-button-action-wide:hover { + background-image: url('assets/buttons/action_wide_hover.svg'); +} + .App-button-disable { pointer-events: none; opacity: 0.4; diff --git a/culinaryFrontend/src/assets/buttons/action_hover.svg b/culinaryFrontend/src/assets/buttons/action_hover.svg index 762f179..7d8ebc4 100644 --- a/culinaryFrontend/src/assets/buttons/action_hover.svg +++ b/culinaryFrontend/src/assets/buttons/action_hover.svg @@ -1,6 +1,6 @@ - + diff --git a/culinaryFrontend/src/assets/buttons/action_wide.svg b/culinaryFrontend/src/assets/buttons/action_wide.svg new file mode 100644 index 0000000..ccd9771 --- /dev/null +++ b/culinaryFrontend/src/assets/buttons/action_wide.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/culinaryFrontend/src/assets/buttons/action_wide_hover.svg b/culinaryFrontend/src/assets/buttons/action_wide_hover.svg new file mode 100644 index 0000000..b0a341c --- /dev/null +++ b/culinaryFrontend/src/assets/buttons/action_wide_hover.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/culinaryFrontend/src/components/Pot.tsx b/culinaryFrontend/src/components/Pot.tsx index 6fa0642..825df17 100644 --- a/culinaryFrontend/src/components/Pot.tsx +++ b/culinaryFrontend/src/components/Pot.tsx @@ -9,7 +9,8 @@ type PotProps = { cucumber: number, tomato: number, carrot: number, - soupHue: number + soupHue: number, + spiced: boolean } } diff --git a/culinaryFrontend/src/components/screens/MainActionsScreen.tsx b/culinaryFrontend/src/components/screens/MainActionsScreen.tsx index 45f6eaa..938de2b 100644 --- a/culinaryFrontend/src/components/screens/MainActionsScreen.tsx +++ b/culinaryFrontend/src/components/screens/MainActionsScreen.tsx @@ -1,5 +1,5 @@ import {GameState} from "../GameScreen"; -import {useState} from "react"; +import {useEffect, useState} from "react"; import {JsAction} from '../../models/JsAction' import {JsItemType} from '../../models/JsItemType' import axios from "axios"; @@ -17,20 +17,74 @@ type MainActionsScreenProps = { export default function MainActionsScreen({gameStateSetter}: MainActionsScreenProps) { + const taskTypeUrl = "/functions/current-task" const refillUrl = "/functions/refill-fridge" const soupUrl = "/functions/tomato-soup" const spiceUrl = "/functions/soup-spices" const tasteUrl = "/functions/check-soup" const saladListUrl = "/functions/salad-list" const saladSequenceUrl = "/functions/salad-sequence" - const smoothieListUrl = "/functions/smoothie-list" - const smoothieSequenceUrl = "/functions/smoothie-sequence" + const smoothieUrl = "/functions/smoothie" - const soupName = "soup" + let infoTextActionMap: { [key: string]: string } = { + "SHOW_ON_COUNTER": "", + "PUT_IN_POT": "Putting into the pot", + "SIMMER": "Cooking!", + "ADD_TO_SALAD": "Adding to the salad", + "MIX_SALAD": "Mixing the salad", + "BLEND": "Blending", + "ADD_TO_BLENDER": "Adding to the blender", + "REMOVE_FROM_COUNTER": "", + "CUT_ON_COUNTER": "Cutting", + } + + let infoTextItemMap: { [key: string]: string } = { + "CITRUS_BASKET": "citrus basket", + "BERRY_BASKET": "berry basket", + "ROT_TOMATO": "rot tomato", + "FRESH_TOMATO": "fresh tomato", + "CUT_TOMATO": "cut tomato", + "ROT_CUCUMBER": "rot cucumber", + "FRESH_CUCUMBER": "fresh cucumber", + "CUT_CUCUMBER": "cut cucumber", + "ROT_CARROT": "rot carrot", + "FRESH_CARROT": "fresh carrot", + "CUT_CARROT": "cut carrot", + "BERRY": "berry", + "CITRUS": "orange", + "SALT": "salt", + "PEPPER": "pepper", + "OREGANO": "oregano", + } + + const startupMsg = "Press button to start" + const getTaskErrMsg = "Can't get task type. Check backend." + + const refillSuccMsg = "Fridge is refilled!" + const refillErrMsg = "Failed to refill the fridge. Check your implementation." + const soupEmptyListMsg = "You need at least three fresh tomato in the fridge! Try to refill!" + + const cookingNoActionsMsg = "Not enough ingredients to make" + const cookingDoneMsg = "Cooking is done!" + const cookingErrMsg = "Failed to cook. Check your implementation." + + const noSoupSpicingMsg = "You need to cook the soup first!" + const beforeSpicingMsg = "Let's add some spices!" + const afterSpicingMsg = "Adding spices is done!" + const spicingErrMsg = "Failed to add spices. Check your implementation." + + const tasteGoodMsg = "It tastes great! 🎉" + const tasteBadMsg = "It tastes so bad... Try to cook the soup again." + const tasteErrMsg = "Failed to get taste status. Check your implementation." + + const saladEmptyListMsg = "Try to refill the fridge!" + + const soupName = "tomato soup" const saladListName = "salad (list)" const saladSequenceName = "salad (sequence)" - const smoothieListName = "smoothie (list)" - const smoothieSequenceName = "smoothie (sequence)" + const smoothieName = "smoothie" + + const cookingDelay = 1000 // ms type BlenderOptions = { visible: boolean, @@ -41,7 +95,7 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr } const initialBlenderOptions: BlenderOptions = { - visible: false, + visible: true, full: false, shake: false, berry: 0, @@ -59,6 +113,7 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr tomato: number, carrot: number, soupHue: number, + spiced: boolean } const initialPotOptions: PotOptions = { @@ -72,6 +127,7 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr tomato: 0, carrot: 0, soupHue: 0, + spiced: false } type SaladBowlOptions = { @@ -110,16 +166,27 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr count: 5, } + useEffect(() => { + axios.get(taskTypeUrl).then(async (response) => { + console.log(`Current task type: ${response.data as String}`) + setCurrentTask(response.data as String) + SaladBowlVisSetter((response.data as String)==="SALAD") + }).catch(error => { + infoTextSetter(getTaskErrMsg) + }) + }, []) + let [counterProducts, counterProductsSetter] = useState>([]) let [fridgeProducts, fridgeProductsSetter] = useState>([]) - let [infoText, infoTextSetter] = useState("Press button to start") - let [spicesShelfVis, spicesShelfVisSetter] = useState(false) + let [infoText, infoTextSetter] = useState(startupMsg) + let [spicesShelfVis, spicesShelfVisSetter] = useState(true) let [blenderOptions, setBlenderOptions] = useState(initialBlenderOptions); let [potOptions, setPotOptions] = useState(initialPotOptions); let [saladBowlOptions, setSaladBowlOptions] = useState(initialSaladBowlOptions); let [berryBasketOptions, setBerryBasketOptions] = useState(initialBerryBasketOptions); let [citrusBasketOptions, setCitrusBasketOptions] = useState(initialCitrusBasketOptions); let [buttonBlocker, setButtonBlocker] = useState(""); + let [currentTask, setCurrentTask] = useState(""); function berryBasketVisSetter(value: boolean){ setBerryBasketOptions(prevOptions => ({ @@ -156,49 +223,18 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr })); } - let infoTextActionMap: { [key: string]: string } = { - "SHOW_ON_COUNTER": "", - "PUT_IN_POT": "", - "SIMMER": "", - "ADD_TO_SALAD": "", - "MIX_SALAD": "", - "BLEND": "", - "ADD_TO_BLENDER": "", - "REMOVE_FROM_COUNTER": "", - } - - let infoTextItemMap: { [key: string]: string } = { - "CITRUS_BASKET": "", - "BERRY_BASKET": "", - "ROT_TOMATO": "", - "FRESH_TOMATO": "", - "CUT_TOMATO": "", - "ROT_CUCUMBER": "", - "FRESH_CUCUMBER": "", - "CUT_CUCUMBER": "", - "ROT_CARROT": "", - "FRESH_CARROT": "", - "CUT_CARROT": "", - "BERRY": "", - "CITRUS": "", - "SALT": "", - "PEPPER": "", - "OREGANO": "", - } - let counterVisMap: { [key: string]: (arg: boolean) => void } = { "BERRY_BASKET": berryBasketVisSetter, - "???SALAD_BOWL???": SaladBowlVisSetter, "CITRUS_BASKET": citrusBasketVisSetter, - "???SPICES_SHELF???": spicesShelfVisSetter, "BLENDER": blenderVisSetter, "POT": potVisSetter } function showOnCounter(arg: string | null) { console.log("showOnCounter", arg) - if (!arg) + if (!arg) { return + } if (arg in counterVisMap) { counterVisMap[arg](true) } else { @@ -213,7 +249,7 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr function putInPot(arg: string | null) { if (arg == null) return - removeFromCounter(arg) + //removeFromCounter(arg) let potMap: { [key: string]: () => void } = { "PEPPER": () => { setPotOptions(prevOptions => ({ @@ -301,7 +337,7 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr console.log(arg) if (arg == null) return - removeFromCounter(arg) + //removeFromCounter(arg) let saladMap: { [key: string]: () => void } = { "CUT_TOMATO": () => { setSaladBowlOptions(prevOptions => ({ @@ -394,71 +430,13 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr blenderMap[arg]() } - function equipKitchen(actions: Array) { - console.log("equipKitchen()") - let equipmentMap: { [key: string]: () => void } = { - "ADD_TO_BLENDER": () => { - blenderVisSetter(true) - }, - "BLEND": () => { - blenderVisSetter(true) - }, - "MIX_SALAD": () => { - SaladBowlVisSetter(true) - }, - "ADD_TO_SALAD": () => { - SaladBowlVisSetter(true) - }, - "PUT_IN_POT": () => { - potVisSetter(true) - }, - "SIMMER": () => { - potVisSetter(true) - }, - "SALT": () => { - spicesShelfVisSetter(true) - setPotOptions(prevOptions => ({ - ...prevOptions, - soup: true - })); - }, - "PEPPER": () => { - spicesShelfVisSetter(true) - setPotOptions(prevOptions => ({ - ...prevOptions, - soup: true - })); - }, - "OREGANO": () => { - spicesShelfVisSetter(true) - setPotOptions(prevOptions => ({ - ...prevOptions, - soup: true - })); - }, - } - - for (const action of actions) { - // check is SALT PEPPER or OREGANO is shown on the counter - if (String(action.type) == "SHOW_ON_COUNTER" || String(action.type) == "PUT_IN_POT") { - if (String(action.parameter) in equipmentMap) { - equipmentMap[String(action.parameter)]() - } - } else { // check is POT BLENDER or SALAD-bowl is used in cooking - if (String(action.type) in equipmentMap) { - equipmentMap[String(action.type)]() - } - } - } - } function removeFromCounter(arg: string | null) { console.log("removeFromCounter", arg) - if (!arg) + if (!arg){ return - if (arg in counterVisMap) { - counterVisMap[arg](false) - } else { + } + else { console.log("counter: ", counterProducts) console.log("filter: ", counterProducts.filter(item => JsItemType[item] !== arg)) counterProductsSetter((prevState) => { @@ -499,37 +477,38 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr "MIX_SALAD": mixSalad, "BLEND": blend, "ADD_TO_BLENDER": addToBlender, - "REMOVE_FROM_COUNTER": removeFromCounter + "REMOVE_FROM_COUNTER": removeFromCounter, + "CUT_ON_COUNTER": removeFromCounter }; function refill(){ setBlenderOptions(initialBlenderOptions); setPotOptions(initialPotOptions); setSaladBowlOptions(initialSaladBowlOptions) + SaladBowlVisSetter(currentTask==="SALAD") setCitrusBasketOptions(initialCitrusBasketOptions) setBerryBasketOptions(initialBerryBasketOptions) - spicesShelfVisSetter(false) counterProductsSetter([]) - fridgeProductsSetter([]) - infoTextSetter("Fridge refilling...") let items = Array() axios.get(refillUrl).then(async (response) => { const receivedItems: Array = response.data; items = receivedItems.map(item => JsItemType[item]); console.log("Refill GOT: " + items) fridgeProductsSetter(items) - infoTextSetter("Fridge is refilled!") + infoTextSetter(refillSuccMsg) + }).catch(error => { + infoTextSetter(refillErrMsg); }) } - function cook(url: string, dishName: string){ + function cook(url: string, dishName: string, emptyListMsg: string = ""){ setBlenderOptions(initialBlenderOptions); setPotOptions(initialPotOptions); setSaladBowlOptions(initialSaladBowlOptions) + SaladBowlVisSetter(currentTask==="SALAD") setCitrusBasketOptions(initialCitrusBasketOptions) setBerryBasketOptions(initialBerryBasketOptions) - spicesShelfVisSetter(false) counterProductsSetter([]) setButtonBlocker(dishName) @@ -537,26 +516,27 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr let actions = Array() axios.get(url).then(async (response) => { + console.log("GOT: " + JSON.stringify(response.data, null, 2)) actions = response.data as Array - console.log("GOT: " + actions) if (actions.length == 0){ - infoTextSetter(`Not enough ingredients to make ${dishName}!`) + infoTextSetter(`${cookingNoActionsMsg} ${dishName}! ${emptyListMsg}`) setButtonBlocker("") return } infoTextSetter("Let's go!") - equipKitchen(actions) - console.log("equipKitchen() DONE") - await delay(1500); + await delay(cookingDelay); for (const action of actions) { console.log(infoTextActionMap[String(action.type)] + " " + (action.parameter ? infoTextItemMap[String(action.parameter)] : "")) infoTextSetter(infoTextActionMap[String(action.type)] + " " + (action.parameter ? infoTextItemMap[String(action.parameter)] : "")) actionMap[String(action.type)]( action.parameter ? String(action.parameter) : null ) - await delay(1500); + await delay(cookingDelay); } - infoTextSetter("Cooking is done!") + infoTextSetter(cookingDoneMsg) + }).catch(error => { + infoTextSetter(cookingErrMsg) + }).finally(() => { setButtonBlocker("") }) } @@ -570,23 +550,28 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr actions = response.data as Array console.log("GOT: " + actions) if (actions.length == 0){ - infoTextSetter("You need to cook the soup first!") + infoTextSetter(noSoupSpicingMsg) setButtonBlocker("") return } - infoTextSetter("Let's add some spices!") - equipKitchen(actions) - console.log("equipKitchen() DONE") - await delay(1500); + infoTextSetter(beforeSpicingMsg) + await delay(cookingDelay); for (const action of actions) { console.log(infoTextActionMap[String(action.type)] + " " + (action.parameter ? infoTextItemMap[String(action.parameter)] : "")) infoTextSetter(infoTextActionMap[String(action.type)] + " " + (action.parameter ? infoTextItemMap[String(action.parameter)] : "")) actionMap[String(action.type)]( action.parameter ? String(action.parameter) : null ) - await delay(1500); + await delay(cookingDelay); } - infoTextSetter("Adding the spices is done!") + infoTextSetter(afterSpicingMsg) + setPotOptions(prevOptions => ({ + ...prevOptions, + spiced: true + })); + }).catch(error => { + infoTextSetter(spicingErrMsg) + }).finally(() => { setButtonBlocker("") }) } @@ -596,10 +581,12 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr let isTasteGood = response.data as boolean console.log("isTasteGood: " + isTasteGood) if(isTasteGood){ - infoTextSetter("It tastes great! 🎉") + infoTextSetter(tasteGoodMsg) } else { - infoTextSetter("It tastes so bad... Try it again!") + infoTextSetter(tasteBadMsg) } + }).catch(error => { + infoTextSetter(tasteErrMsg) }) } @@ -641,40 +628,46 @@ export default function MainActionsScreen({gameStateSetter}: MainActionsScreenPr }
- - - - - - - - - - + {(currentTask === "SOUP" || currentTask === "SALAD") && ( + + )} + {currentTask === "SOUP" && ( + <> + + + + + )} + {currentTask === "SALAD" && ( + <> + + + + )} + {currentTask === "SMOOTHIE" && ( + + )}
); diff --git a/culinaryFrontend/src/models/JsActionType.ts b/culinaryFrontend/src/models/JsActionType.ts index ca8f17a..718979e 100644 --- a/culinaryFrontend/src/models/JsActionType.ts +++ b/culinaryFrontend/src/models/JsActionType.ts @@ -1,5 +1,6 @@ export enum JsActionType { SHOW_ON_COUNTER, // baskets, fruits, vegetables + CUT_ON_COUNTER, PUT_IN_POT, // cut vegetables SIMMER, // null ADD_TO_SALAD, // vegetables