diff --git a/README.md b/README.md index 31636b4..8bfa280 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,12 @@ You can learn more in the [Create React App documentation](https://facebook.gith To learn React, check out the [React documentation](https://reactjs.org/). - ## Attributes -Images for Associate Games Icons made by [pongsakornRed]("https://www.flaticon.com/authors/pongsakornred"), [mynamepong](https://www.flaticon.com/authors/mynamepong) from [flaticon]("https://www.flaticon.com/") \ No newline at end of file + +### Images for Associate Games + +Icons made by [pongsakornRed](https://www.flaticon.com/authors/pongsakornred), [mynamepong](https://www.flaticon.com/authors/mynamepong) from [flaticon](https://www.flaticon.com/) + +### Images for Language Games + +Icons made by [monkik](https://www.flaticon.com/authors/monkik) from [flaticon](https://www.flaticon.com/) diff --git a/src/app/AuthenticatedApp.tsx b/src/app/AuthenticatedApp.tsx index d955fdd..f6d3e62 100644 --- a/src/app/AuthenticatedApp.tsx +++ b/src/app/AuthenticatedApp.tsx @@ -8,7 +8,8 @@ import { import Dashboard from 'routes/dashboard'; import Associate from 'routes/associate'; -import { PROFILE, ASSOCIATE } from 'constants/routes'; +import Language from 'routes/language'; +import { PROFILE, ASSOCIATE, LANGUAGE } from 'constants/routes'; const RedirectPath = () => { const history = useHistory(); @@ -24,6 +25,7 @@ const AuthenticatedApp: React.FC = () => { + diff --git a/src/assets/images/languages/occupations/Astronaut.tsx b/src/assets/images/languages/occupations/Astronaut.tsx new file mode 100644 index 0000000..a0e355a --- /dev/null +++ b/src/assets/images/languages/occupations/Astronaut.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Astronaut: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Astronaut; diff --git a/src/assets/images/languages/occupations/Baker.tsx b/src/assets/images/languages/occupations/Baker.tsx new file mode 100644 index 0000000..c6f3e9f --- /dev/null +++ b/src/assets/images/languages/occupations/Baker.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Baker: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Baker; diff --git a/src/assets/images/languages/occupations/Barber.tsx b/src/assets/images/languages/occupations/Barber.tsx new file mode 100644 index 0000000..e5de5fd --- /dev/null +++ b/src/assets/images/languages/occupations/Barber.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Barber: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Barber; diff --git a/src/assets/images/languages/occupations/Cashier.tsx b/src/assets/images/languages/occupations/Cashier.tsx new file mode 100644 index 0000000..69589f6 --- /dev/null +++ b/src/assets/images/languages/occupations/Cashier.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Cashier: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Cashier; diff --git a/src/assets/images/languages/occupations/Chef.tsx b/src/assets/images/languages/occupations/Chef.tsx new file mode 100644 index 0000000..c2703a8 --- /dev/null +++ b/src/assets/images/languages/occupations/Chef.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Chef: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Chef; diff --git a/src/assets/images/languages/occupations/Doctor.tsx b/src/assets/images/languages/occupations/Doctor.tsx new file mode 100644 index 0000000..929326b --- /dev/null +++ b/src/assets/images/languages/occupations/Doctor.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Doctor: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Doctor; diff --git a/src/assets/images/languages/occupations/Farmer.tsx b/src/assets/images/languages/occupations/Farmer.tsx new file mode 100644 index 0000000..a164756 --- /dev/null +++ b/src/assets/images/languages/occupations/Farmer.tsx @@ -0,0 +1,158 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Farmer: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Farmer; diff --git a/src/assets/images/languages/occupations/Fireman.tsx b/src/assets/images/languages/occupations/Fireman.tsx new file mode 100644 index 0000000..f80af58 --- /dev/null +++ b/src/assets/images/languages/occupations/Fireman.tsx @@ -0,0 +1,118 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Fireman: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Fireman; diff --git a/src/assets/images/languages/occupations/Librarian.tsx b/src/assets/images/languages/occupations/Librarian.tsx new file mode 100644 index 0000000..52ef5dd --- /dev/null +++ b/src/assets/images/languages/occupations/Librarian.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Librarian: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Librarian; diff --git a/src/assets/images/languages/occupations/Nurse.tsx b/src/assets/images/languages/occupations/Nurse.tsx new file mode 100644 index 0000000..3fce411 --- /dev/null +++ b/src/assets/images/languages/occupations/Nurse.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Nurse: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Nurse; diff --git a/src/assets/images/languages/occupations/Painter.tsx b/src/assets/images/languages/occupations/Painter.tsx new file mode 100644 index 0000000..b65d035 --- /dev/null +++ b/src/assets/images/languages/occupations/Painter.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Painter: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Painter; diff --git a/src/assets/images/languages/occupations/Pilot.tsx b/src/assets/images/languages/occupations/Pilot.tsx new file mode 100644 index 0000000..eb02d31 --- /dev/null +++ b/src/assets/images/languages/occupations/Pilot.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Pilot: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Pilot; diff --git a/src/assets/images/languages/occupations/Policeman.tsx b/src/assets/images/languages/occupations/Policeman.tsx new file mode 100644 index 0000000..a53cfdd --- /dev/null +++ b/src/assets/images/languages/occupations/Policeman.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Policeman: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Policeman; diff --git a/src/assets/images/languages/occupations/Scientist.tsx b/src/assets/images/languages/occupations/Scientist.tsx new file mode 100644 index 0000000..aae82ed --- /dev/null +++ b/src/assets/images/languages/occupations/Scientist.tsx @@ -0,0 +1,123 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Scientist: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Scientist; diff --git a/src/assets/images/languages/occupations/Student.tsx b/src/assets/images/languages/occupations/Student.tsx new file mode 100644 index 0000000..3d89127 --- /dev/null +++ b/src/assets/images/languages/occupations/Student.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Student: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Student; diff --git a/src/assets/images/languages/occupations/Teacher.tsx b/src/assets/images/languages/occupations/Teacher.tsx new file mode 100644 index 0000000..031ec3a --- /dev/null +++ b/src/assets/images/languages/occupations/Teacher.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Teacher: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Teacher; diff --git a/src/assets/images/languages/occupations/Vet.tsx b/src/assets/images/languages/occupations/Vet.tsx new file mode 100644 index 0000000..a4be569 --- /dev/null +++ b/src/assets/images/languages/occupations/Vet.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Vet: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Vet; diff --git a/src/assets/images/languages/occupations/Waiter.tsx b/src/assets/images/languages/occupations/Waiter.tsx new file mode 100644 index 0000000..5d51844 --- /dev/null +++ b/src/assets/images/languages/occupations/Waiter.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +import { SvgrProps } from '.'; + +const Waiter: React.FC = ({ height = 512, width = 512 }) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Waiter; diff --git a/src/assets/images/languages/occupations/index.ts b/src/assets/images/languages/occupations/index.ts new file mode 100644 index 0000000..f130a6a --- /dev/null +++ b/src/assets/images/languages/occupations/index.ts @@ -0,0 +1,23 @@ +export { default as Astronaut } from './Astronaut'; +export { default as Baker } from './Baker'; +export { default as Barber } from './Barber'; +export { default as Cashier } from './Cashier'; +export { default as Chef } from './Chef'; +export { default as Doctor } from './Doctor'; +export { default as Farmer } from './Farmer'; +export { default as Fireman } from './Fireman'; +export { default as Librarian } from './Librarian'; +export { default as Nurse } from './Nurse'; +export { default as Painter } from './Painter'; +export { default as Pilot } from './Pilot'; +export { default as Policeman } from './Policeman'; +export { default as Scientist } from './Scientist'; +export { default as Student } from './Student'; +export { default as Teacher } from './Teacher'; +export { default as Vet } from './Vet'; +export { default as Waiter } from './Waiter'; + +export interface SvgrProps { + height?: any; + width?: any; +} diff --git a/src/assets/scss/main.scss b/src/assets/scss/main.scss new file mode 100644 index 0000000..711db8f --- /dev/null +++ b/src/assets/scss/main.scss @@ -0,0 +1 @@ +@import '../../../node_modules/bulma/bulma.sass'; diff --git a/src/components/navbar/SideBar.tsx b/src/components/navbar/SideBar.tsx index 8f106e0..abeccd1 100644 --- a/src/components/navbar/SideBar.tsx +++ b/src/components/navbar/SideBar.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Link, useHistory } from 'react-router-dom'; import APP_LOGO from 'assets/images/app.png'; -import { PROFILE, HOME, ASSOCIATE } from 'constants/routes'; +import { PROFILE, HOME, ASSOCIATE, LANGUAGE } from 'constants/routes'; import firebase from 'utils/firebase'; import './SideBar.scss'; @@ -32,6 +32,9 @@ const SideBar: React.FC = ({ isOpen, setIsOpen }) => { setIsOpen(false)}> Associate + setIsOpen(false)}> + Language +
+
+ + + ); + } +}; + +export default Language; diff --git a/src/routes/language/Occupations/Occupations.scss b/src/routes/language/Occupations/Occupations.scss new file mode 100644 index 0000000..04bf073 --- /dev/null +++ b/src/routes/language/Occupations/Occupations.scss @@ -0,0 +1,65 @@ +.occupations { + margin-top: 2rem; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + + &__loading { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + + &__expressive { + &--title { + margin-top: 1rem; + } + + &--answers { + .button { + margin: 0.7rem 0; + } + width: 100%; + } + + &--description { + margin-bottom: 1.5rem; + } + } + + &__receptive { + &--title { + margin-top: 1rem; + .title:not(:last-child) { + margin-bottom: 0; + } + } + + &--job-name { + margin-top: 0; + font-size: 4rem; + font-weight: bold; + text-transform: uppercase; + line-height: 4rem; + } + + &--options { + .button { + margin: 0.7rem 0; + } + width: 100%; + } + + &--description { + margin-bottom: 1.5rem; + } + + &--button.button { + width: calc(50% - 1rem); + margin: 0.5rem; + height: auto; + } + } +} diff --git a/src/routes/language/Occupations/Occupations.tsx b/src/routes/language/Occupations/Occupations.tsx new file mode 100644 index 0000000..f9c3859 --- /dev/null +++ b/src/routes/language/Occupations/Occupations.tsx @@ -0,0 +1,188 @@ +import React, { useReducer, useEffect } from 'react'; +import { useToasts } from 'react-toast-notifications'; + +import DataLoader from 'components/dataLoader'; +import { getRandomElement, getNRandomElements } from 'utils/randomUtils'; +import { occupationData, OccupationDataset } from './data'; + +import './Occupations.scss'; + +interface OccupationsProps { + handleBackToMenu: () => void; +} + +// enum OccupationGameType { +// EXPRESSIVE, +// RECEPTIVE +// } + +interface OccupationsState { + isLoading: boolean; + occupations: OccupationDataset[]; + answer: OccupationDataset | null; + gameType: string; + isCompleted: boolean; + isCorrect: boolean; +} + +const Occupations: React.FC = ({ handleBackToMenu }) => { + const { addToast } = useToasts(); + const [state, setState] = useReducer( + (a: OccupationsState, s: any) => ({ ...a, ...s }), + { + isLoading: true, + occupations: [], + answer: null, + gameType: 'EXPRESSIVE', + isCompleted: false + } + ); + + const handleNewGame = (): void => { + setState({ + isLoading: true, + isCompleted: false + }); + const previousAnswer = state.answer; + const finalOccupations = getNRandomElements(occupationData, 4); + let finalAnswer = getRandomElement(finalOccupations); + while (previousAnswer && finalAnswer.name === previousAnswer.name) { + finalAnswer = getRandomElement(finalOccupations); + } + setState({ + occupations: finalOccupations, + answer: finalAnswer, + gameType: Math.random() < 0.5 ? 'RECEPTIVE' : 'EXPRESSIVE', + isLoading: false + }); + }; + + useEffect((): void => { + handleNewGame(); + }, []); + + const handleSelect = (option: string): void => { + const isCorrect = option === state.answer.name; + if (isCorrect) { + addToast(`Great job!`, { + appearance: 'success', + autoDismiss: true + }); + setState({ + isCompleted: true + }); + } else { + addToast(`Oh dear, do try again!`, { + appearance: 'error', + autoDismiss: true + }); + } + }; + + if (state.isLoading) { + return ( +
+ +
+ ); + } + + if (state.gameType === 'EXPRESSIVE') { + return ( +
+
+

Who is this?

+
+
+ +
+
+

+ {state.isCompleted + ? 'Great job! What next?' + : 'Say out the occupation before selecting the option!'} +

+ {!state.isCompleted && + state.occupations.map((o: OccupationDataset) => ( + + ))} + {state.isCompleted && ( + <> + + + + )} +
+
+ ); + } + + return ( +
+
+

Choose the

+

+ {state.answer.name} +

+
+
+

+ {state.isCompleted + ? 'Great job! What next?' + : 'Tap the photo that best shows the above occupation!'} +

+ {state.isCompleted && ( + <> + + + + )} +
+ {!state.isCompleted && ( +
+ {state.occupations.map((o: OccupationDataset) => ( + + ))} +
+ )} +
+ ); +}; + +export default Occupations; diff --git a/src/routes/language/Occupations/data.ts b/src/routes/language/Occupations/data.ts new file mode 100644 index 0000000..c65b1be --- /dev/null +++ b/src/routes/language/Occupations/data.ts @@ -0,0 +1,83 @@ +import React from 'react'; + +import * as OccupationSvg from 'assets/images/languages/occupations'; + +export interface OccupationDataset { + svg: React.FC; + name: string; +} + +export const occupationData: OccupationDataset[] = [ + { + svg: OccupationSvg.Astronaut, + name: 'Astronaut' + }, + { + svg: OccupationSvg.Baker, + name: 'Baker' + }, + { + svg: OccupationSvg.Barber, + name: 'Barber' + }, + { + svg: OccupationSvg.Cashier, + name: 'Cashier' + }, + { + svg: OccupationSvg.Chef, + name: 'Chef' + }, + { + svg: OccupationSvg.Doctor, + name: 'Doctor' + }, + { + svg: OccupationSvg.Farmer, + name: 'Farmer' + }, + { + svg: OccupationSvg.Fireman, + name: 'Fireman' + }, + { + svg: OccupationSvg.Librarian, + name: 'Librarian' + }, + { + svg: OccupationSvg.Nurse, + name: 'Nurse' + }, + { + svg: OccupationSvg.Painter, + name: 'Painter' + }, + { + svg: OccupationSvg.Pilot, + name: 'Pilot' + }, + { + svg: OccupationSvg.Policeman, + name: 'Policeman' + }, + { + svg: OccupationSvg.Scientist, + name: 'Scientist' + }, + { + svg: OccupationSvg.Student, + name: 'Student' + }, + { + svg: OccupationSvg.Teacher, + name: 'Teacher' + }, + { + svg: OccupationSvg.Vet, + name: 'Vet' + }, + { + svg: OccupationSvg.Waiter, + name: 'Waiter' + } +]; diff --git a/src/routes/language/Occupations/index.ts b/src/routes/language/Occupations/index.ts new file mode 100644 index 0000000..58c26ec --- /dev/null +++ b/src/routes/language/Occupations/index.ts @@ -0,0 +1 @@ +export { default } from './Occupations'; diff --git a/src/routes/language/index.ts b/src/routes/language/index.ts new file mode 100644 index 0000000..3f1ae84 --- /dev/null +++ b/src/routes/language/index.ts @@ -0,0 +1 @@ +export { default } from './Language'; diff --git a/src/utils/randomUtils.ts b/src/utils/randomUtils.ts new file mode 100644 index 0000000..95cce91 --- /dev/null +++ b/src/utils/randomUtils.ts @@ -0,0 +1,10 @@ +export const getRandomElement = (items: any[]): any => { + return items[Math.floor(Math.random() * items.length)]; +}; + +export const getNRandomElements = (items: any[], n: number): any[] => { + const copy = items.slice(); + // eslint-disable-next-line no-unused-vars + copy.sort((_a, _b) => 0.5 - Math.random()); + return copy.slice(0, n); +};