diff --git a/src/App.js b/src/App.js index 54d9b49..3ff0175 100644 --- a/src/App.js +++ b/src/App.js @@ -6,238 +6,340 @@ import Button from "./components/Button"; import Theme from "./components/Theme"; import Dropdown from "./components/Dropdown"; import themes from "./data/themes.json"; -import { useState, useLayoutEffect } from "react"; -import isDuplicate from "./hooks/isDuplicate"; +import { useState, useEffect } from "react"; +import useLocalStorage from "./hooks/useLocalStorage"; +import DiceButton from "./components/DiceButton"; -function classNames(...classes) { - return classes.filter(Boolean).join(" "); +//a function that randomises a number. I use it to randomise office hosts, color of the background, and themes. +function makeRandom(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min) + min); } function App() { - //initiating the state and statehandler. + //initiating the state and statehandlers. + const [employeesArray, setEmployeesArray] = useState([...employees]); + const [themesArray, setThemesArray] = useState([...themes]); const [randomise, setRandomise] = useState(false); const [employee, setEmployee] = useState({ - person1: employees[0], - person2: employees[0], + person1: null, + person2: null, }); - const [theme, setTheme] = useState(); - //const [themeButton, setThemeButton] = useState(false); - const [themeIsLoading, setThemeIsLoading] = useState(false); + const [themeLoadingStatus, setThemeLoadingStatus] = useState("nothing"); + const [person1IsLoading, setPerson1IsLoading] = useState(false); + const [person2IsLoading, setPerson2IsLoading] = useState(false); const [gif, setGif] = useState(false); - const [themeIsDoneLoading, setThemeIsDoneLoading] = useState(false); - isDuplicate(); + //accessing the variables and functions through the useLocalStorage hook. + const { + storedThemes, + storedEmployees, + addUsedTheme, + addUsedEmployees, + removeDeSelectedTheme, + removeDeSelectedPerson, + employeeKey, + themeKey, + } = useLocalStorage(); - //deciding the colors for the background to randomise between these two - const colors = ["babyblue", "tulip"]; + //deciding the colors for the background to randomise between + const colorsArray = ["babyblue", "tulip"]; + const [colors, setColors] = useState( + colorsArray[makeRandom(0, colorsArray.length)] + ); - //a function that randomises a number to later apply this random number to the person component. I also use it to send a random number to the theme component to use to pick a random theme when the randomise button has been clicked. - function makeRandom(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min) + min); - } + //declaring the states for the themeLoadingStatuses so I can check if they are 'true' or 'false'. + const themeIsLoading = themeLoadingStatus === "loading"; + const themeDoneLoading = themeLoadingStatus === "theme-done-loading"; - //randomising the background color - let backgroundColor = colors[makeRandom(0, colors.length)]; + //this useEffect pushes the randomised or selected theme into an array in local storage by accessing a function declared in useLocalStorage.js. + useEffect(() => { + if (theme) { + addUsedTheme(theme); + } + }, [theme]); + + //this useEffect stores the people who have been randomised as office hosts in an array in localStorage. + useEffect(() => { + if (employee.person1 && employee.person2) { + addUsedEmployees([employee.person1, employee.person2]); + } + }); - //this function takes in the person object that should be compared to a new randomised person created when this function is called, it then compares the existing person object with the newly created person, and if it is the same then it re-runs the function. Otherwise it returns the newEmployee that was created through randomisation, which is then set to the person object. - const findUniqueAndRandomPerson = (otherPerson) => { - let newEmployee = employees[makeRandom(2, employees.length)]; - if (isDuplicate(newEmployee, otherPerson)) { - console.log(isDuplicate); + /* + ! CODE REVIEW ! + This function should make sure that two person objects should never become the same. However, it doesn't work because it compares the new person object with 'null' because the 'otherPerson' object is not assigned until both of them are. + */ + /* const findUniqueAndRandomPerson = (otherPerson) => { + let newEmployee = employeesArray[makeRandom(0, employeesArray.length)]; + //console.log("this is otherPerson:: ", otherPerson); + //console.log("this is newEmployee:: ", newEmployee); + if (isDuplicate(newEmployee.name, otherPerson.name)) { newEmployee = findUniqueAndRandomPerson(otherPerson); } else { return newEmployee; } return newEmployee; - }; + }; */ - //this is a state handler that executes when handleSetRandomiseAll() is called and when a number is passed into setEmployee(). It sets a random value to the employee array and stores this in person1 and person2 objects containing the whole object carried from the employees array. - //maybe this could be re-written as a switch-case? + //this statehandler assigns office hosts. Case 1 is triggered by a dice press on the left office host, case 2 is triggered by a dice press on the right office host and default runs when the user presses the first button to generate everything at the same time. const handleSetEmployee = (number) => { - if (number === 1) { - setEmployee({ - ...employee, - person1: employees[1], - }); - setTimeout(() => { - setEmployee({ - ...employee, - person1: findUniqueAndRandomPerson(employee.person2), - }); - }, 1500); - } else if (number === 2) { - setEmployee({ - ...employee, - person2: employees[1], - }); - setTimeout(() => { - setEmployee({ - ...employee, - person2: findUniqueAndRandomPerson(employee.person1), - }); - }, 1500); - } else { - setEmployee((state) => ({ ...state, person1: employees[1] })); - setTimeout(() => { - setEmployee((state) => ({ - ...state, - person1: findUniqueAndRandomPerson(employee.person2), - })); - }, 2500); - setEmployee((state) => ({ ...state, person2: employees[1] })); - setTimeout(() => { - setEmployee((state) => ({ - ...state, - person2: findUniqueAndRandomPerson(employee.person1), - })); - }, 5000); + switch (number) { + case 1: + setPerson1IsLoading(true); + //removing the deselected person from the local storage and storedEmployees array. + removeDeSelectedPerson(employee.person1); + //adding person1 back to employeesArray + setEmployeesArray([...employeesArray, employee.person1]); + setTimeout(() => { + setEmployee({ + ...employee, + person1: employeesArray[makeRandom(0, employeesArray.length)], + }); + setPerson1IsLoading(false); + }, 1500); + break; + case 2: + setPerson2IsLoading(true); + removeDeSelectedPerson(employee.person2); + setEmployeesArray([...employeesArray, employee.person2]); + setTimeout(() => { + setEmployee({ + ...employee, + person2: employeesArray[makeRandom(0, employeesArray.length)], + }); + setPerson2IsLoading(false); + }, 1500); + break; + /* + ! CODE REVIEW ! + The findUniqueAndRandomPerson function does not work as intended during the initialisation of the theme & office host generator. This is because person1 doesn't get set as the 'otherPerson' until after both office hosts are assigned. + */ + default: + setTimeout(() => { + setEmployee((state) => ({ + ...state, + //person1: findUniqueAndRandomPerson(employee.person2) + person1: employeesArray[makeRandom(0, employeesArray.length)], + })); + setPerson1IsLoading(false); + }, 2500); + setTimeout(() => { + setEmployee((state) => ({ + ...state, + //person1: findUniqueAndRandomPerson(employee.person1) + person2: employeesArray[makeRandom(0, employeesArray.length)], + })); + setPerson2IsLoading(false); + }, 5000); + break; } }; - //this is a state handler that takes in a specific theme from what theme is chosen in the dropdown menu and lets that change the theme. If the first generator button or randomise theme button is clicked it applies a randomised number to the themes array and store it in a variable called theme. + //this is a state handler that handles events connected to the theme. It can take in a specific theme that is chosen from the dropdown menu. It also randomises a theme when the first generator button or randomise theme button is clicked. const handleSetTheme = (specificTheme) => { if (specificTheme) { + //the randomised theme that is deselected by selecting a new theme from the dropdown gets removed from local storage and storedThemes + removeDeSelectedTheme(theme.theme); + //adding the deselected theme back into themesArray + setThemesArray([...themesArray, theme]); setTheme(specificTheme); - return; + handleSetGif(); } else { - setThemeIsDoneLoading(false); - setThemeIsLoading(true); + setThemeLoadingStatus("loading"); setTimeout(() => { - const theme = themes[makeRandom(0, themes.length)].theme; + const theme = themesArray[makeRandom(0, themesArray.length)]; setTheme(theme); - setThemeIsLoading(false); + setThemeLoadingStatus("theme-reveal"); + handleSetGif(); }, 8000); setTimeout(() => { - setThemeIsDoneLoading(true); + setThemeLoadingStatus("theme-done-loading"); + setColors(colorsArray[makeRandom(0, colorsArray.length)]); }, 10500); } }; - const handleSetRandomise = () => { - setRandomise(true); - handleSetTheme(); + //a statehandler that shows the gif for 2,5 seconds after a theme has been chosen/randomised. + const handleSetGif = () => { + setGif(true); + setThemeLoadingStatus("theme-reveal"); + setTimeout(() => { + setThemeLoadingStatus("theme-done-loading"); + setGif(false); + }, 2500); }; - //this state handler is triggered when the first button is pressed, to randomise both theme and office hosts at the same time. When randomise is true elements that are hidden in the first screen shows up. + /* + ! CODE REVIEW ! + This useEffect keeps track of which themes has already been, and removes them from the themesArray. The code works, but it feels ugly/wrong.. I've tried some other things (the outcommented bits) but none of them work as intended so I need some help with this. + */ + useEffect(() => { + for (let i = 0; i < themesArray.length; i++) { + for (let j = 0; j < storedThemes.length; j++) { + if (themesArray[i].theme === storedThemes[j]) { + setThemesArray(themesArray.filter((t) => t !== themesArray[i])); + } + } + } + }, [themesArray, storedThemes]); + + /* console.log("stored themes:: ", storedThemes); + console.log("themes array:: ", themesArray); */ + + /* + ! CODE REVIEW ! + Same as above: the code works, but it feels wrong. Since this is essentially the same code as above but with different parameters it might be able to be re-written as an abstraction of some sort? + */ + useEffect(() => { + for (let i = 0; i < employeesArray.length; i++) { + for (let j = 0; j < storedEmployees.length; j++) { + if (employeesArray[i].name === storedEmployees[j]) { + setEmployeesArray( + employeesArray.filter((e) => e !== employeesArray[i]) + ); + } + } + } + }, [employeesArray, storedEmployees]); + + /* + ! EVENTUAL CODE REVIEW ! + This replaces the empty (or almost empty) employees array with the original employees array and removes the stored employees from localStorage. However, when the employeesArray resets it causes a loop of re-renders and I dunno why. + */ + useEffect(() => { + if (employeesArray.length <= 1) { + setEmployeesArray([...employees]); + localStorage.removeItem(employeeKey); + } + }, [employeesArray.length, employeeKey]); + + //same as above but for themes. This also causes a loop of re-renders when it resets. + useEffect(() => { + if (themesArray.length === 0) { + setThemesArray([...themes]); + localStorage.removeItem(themeKey); + } + }, [themesArray.length, themeKey]); + + //this state handler is triggered when the first button is pressed const handleSetRandomiseAll = () => { - handleSetRandomise(); handleSetEmployee(); - }; - - //this useEffect listens to when the randomise new theme button has been pressed, and generates a new theme. - //maybe this could be removed if the randomisation of theme is written in another way?. - /* useLayoutEffect(() => { + setRandomise(true); handleSetTheme(); - }, [themeButton]); */ + setPerson1IsLoading(true); + setPerson2IsLoading(true); + setColors(colorsArray[makeRandom(0, colorsArray.length)]); + }; - //this useEffect checks whether the theme has been updated somehow and then triggers a confetti gif. - useLayoutEffect(() => { - randomise && handleSetGif(); - }, [theme]); + //these person functions handle the different displays of whether the person is unknown, loading or assigned. + const displayPerson1 = () => { + if (!randomise) { + return ; + } else if (person1IsLoading) { + return ; + } else { + return ; + } + }; - const handleSetGif = () => { - setGif(true); - setTimeout(() => { - setGif(false); - }, 2500); + const displayPerson2 = () => { + if (!randomise) { + return ; + } else if (person2IsLoading) { + return ; + } else { + return ; + } }; return (
- {/* {themeIsLoading && ( -
- -
- )} */} - {gif && ( -
- +
+ {`confetti
)} +
+ {displayPerson1()} + {!person1IsLoading && !person2IsLoading && themeDoneLoading && ( + handleSetEmployee(1)} /> + )} +
- {/* defining the employee from the employees array with a random number created through clicking the randomise button */} -
- - {randomise && ( -
-
- +
+
)}
) : ( -
+
)}
- -
- - {randomise && ( -
); } diff --git a/src/components/DiceButton.js b/src/components/DiceButton.js new file mode 100644 index 0000000..728f03e --- /dev/null +++ b/src/components/DiceButton.js @@ -0,0 +1,19 @@ +import Button from "./Button"; + +const DiceButton = ({ clickHandler }) => { + return ( + <> +