diff --git a/frontend/src/components/Map/index.js b/frontend/src/components/Map/index.js index 552642b9..260aaf32 100644 --- a/frontend/src/components/Map/index.js +++ b/frontend/src/components/Map/index.js @@ -7,6 +7,37 @@ import { sicknessStatus, testStatus, posToLatLng } from "../../routes/types"; import { Card, CardContent } from "@material-ui/core"; import Widget from "../Widget"; +//dependencies of Dashboard +import { + Link, + Collapse, + IconButton, + ListItemText, + Checkbox, + MenuItem, + TextField, + Grid, + Button, +} from "@material-ui/core"; +import { SpeedDial, SpeedDialAction, SpeedDialIcon } from "@material-ui/lab"; +import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; +//import classNames from "classnames"; +//import React, { useEffect, useState } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import paths from "routes/paths"; +//import { sicknessStatus, testStatus } from "routes/types"; +import styles2 from "routes/Dashboard/styles.module.css"; +import { fetchStory, submitMyStory, submitStory } from "actions/story"; +import { getStoryResources } from "actions/resources"; +import { LOADING } from "actions/types"; +import { useLocation } from "react-router-dom"; +//import api from "utils"; +//import Map from "components/Map"; +import { fields, initialFieldsState } from "routes/Dashboard/fields"; +import Text from "text.json"; +import { makeStyles } from "@material-ui/core/styles"; +// + const statusMapping = { [testStatus.POSITIVE]: { name: "Tested Positive", color: "red" }, [testStatus.NEGATIVE]: { name: "Tested Negative", color: "purple" }, @@ -19,7 +50,7 @@ const statusMapping = { mapboxgl.accessToken = "pk.eyJ1Ijoic3RlNTE5IiwiYSI6ImNrOHc1aHlvYTB0N2ozam51MHFiazE3bmcifQ.AHtFuA-pAqau_AJIy-hzOg"; -export default function Map(props, { draggable = true }) { +function Map(props, { draggable = true }) { const countryMinZoom = 3; const stateMaxZoom = 4; const initialZoom = 1; @@ -787,3 +818,380 @@ export default function Map(props, { draggable = true }) { ); } + + +/** + * From this point is the Dashboard component and + * its helpers + * + */ + +const professions = Text["Profession"]; +const medicalConditions = Text["Medical Conditions"]; + +const useStyles = makeStyles(() => ({ + profileBar: { + width: 600, + bottom: 0, + padding: "0px 30px 40px 20px", + zIndex: 2, + position: "absolute", + background: "rgba(0, 0, 0, 0.6)", + "& .MuiMenuItem-root": { + whiteSpace: "normal", + }, + }, + // eslint-disable-next-line + ["@media (max-width: 780px)"]: { + profileBar: { + width: "100%", + left: 0, + right: 0, + margin: 0, + }, + }, + submitBtn: { + background: "var(--primary) !important", + color: "white", + verticalAlign: "center", + width: "100%", + }, + root: { + "label + &": { + color: "white", + }, + }, +})); + +// const statusMapping = { +// [testStatus.POSITIVE]: { name: "Tested Positive", color: "red" }, +// [testStatus.NEGATIVE]: { name: "Tested Negative", color: "purple" }, +// [testStatus.NOT_TESTED]: { name: "Not Tested", color: "blue" }, +// [sicknessStatus.SICK]: { name: "Sick", color: "orange" }, +// [sicknessStatus.RECOVERED]: { name: "Recovered", color: "green" }, +// [sicknessStatus.NOT_SICK]: { name: "Not Sick", color: "gray" }, +// }; + +function Dashboard(props, { draggableMapRoutes = [] }) { + const dispatch = useDispatch(); + const [countries, setCountries] = useState([]); + const [formValues, setFormValues] = useState(initialFieldsState()); + const [open, setOpen] = useState(false); + const classes = useStyles(); + const [errorMsg, setErrorMsg] = useState({ display: "none", required: null }); + const [barDisplay, setBarDisplay] = useState(false); + // This myStory is only temporarily fetched from state to check whether it's needed to submit myStory + // For uses in components, use story.latestMyStory + const { story, status, tempStory, tempMyStory } = useSelector((state) => { + return state.story; + }); + + let location = useLocation(); + const [draggableMap, setDraggableMap] = useState(false); + const [expanded, setExpanded] = useState( + window.screen.width > 1024 ? true : false + ); + + const handleExpandClick = () => { + setExpanded(!expanded); + }; + + useEffect(() => { + if (tempStory) { + const nextPage = paths.dashboard; + const dto = { + story: tempStory, + nextPage, + travels: [], + closeContacts: [], + }; + dispatch(submitStory(dto)); + } else if (!story) { + dispatch(fetchStory()); + } else if (story && tempMyStory && tempMyStory.length) { + dispatch(submitMyStory(story.id, tempMyStory)); + } + if (story) { + const required = ["age", "sex", "profession"]; + Object.keys(story).forEach((key) => { + if (required.includes(key) && story[key] === null) { + setBarDisplay(true); + } + }); + } + // eslint-disable-next-line + }, [story, tempMyStory]); + + useEffect(() => { + let shouldDragMap = draggableMapRoutes.includes(location.pathname); + if (shouldDragMap !== draggableMap) { + setDraggableMap(draggableMapRoutes.includes(location.pathname)); + } + }, [location, draggableMap, setDraggableMap, draggableMapRoutes]); + + const handleClick = () => { + setOpen(!open); + }; + + const [storyList, setStoryList] = useState([]); + + useEffect(() => { + api(`stories/explore`, { + method: "GET", + }).then((stories) => { + setStoryList(stories); + }); + }, []); + + useEffect(() => { + fetch("https://restcountries.eu/rest/v2/all?fields=name") + .then((res) => res.json()) + .then( + (result) => { + setCountries(result); + }, + () => {} + ); + }, []); + + const handleFormChange = (field) => (event) => { + const intFields = [fields.AGE]; + const key = field.key; + + if (intFields.includes(field)) { + if (/^\d+$/.test(event.target.value)) + setFormValues({ ...formValues, [key]: parseInt(event.target.value) }); + else setFormValues({ ...formValues, [key]: "" }); + } else { + setFormValues({ ...formValues, [key]: event.target.value }); + } + }; + + const handleSubmit = () => { + let tempList = []; + Object.keys(formValues).forEach((key) => { + if (formValues[key] === null && key !== "countryOfOrigin") + tempList.push(key); + }); + if (tempList.length > 0) { + setErrorMsg({ + display: "block", + required: tempList.join(", "), + }); + } else { + const { ...newStory } = formValues; + Object.assign(story, newStory); + + const nextPage = paths.dashboard; + + const dto = { + story: story, + nextPage, + travels: [], + closeContacts: [], + }; + + dispatch(submitStory(dto, true)); + setBarDisplay(false); + } + }; + + const actions = [ + { + name: "MY STORIES", //hasMyStory ? "UPDATE MY STORY" : "ADD MY STORY", + href: paths.storyHistory, + //paths.myStory, + classes: "MuiFab-extended", + }, + { + name: "UPDATE MY STATUS", + href: paths.onboard, + state: { onboard: false }, + classes: classNames("MuiFab-extended assessment", styles2.assessment), + }, + { + name: "EDIT MY PROFILE", + href: paths.criticalQuestions, + classes: classNames("MuiFab-extended", styles2.profile), + }, + ]; + + const userStatus = () => ( +
+
+ + {statusMapping[story.sick].name.toUpperCase()} +
+
+ + {statusMapping[story.tested].name.toUpperCase()} +
+
+ ); + + const informationHeader = () => ( +
+ {userStatus()} + {/* {resources()} */} +
+ ); + + const profileBar = () => ( + +
+ Please complete the following fields: {errorMsg.required} +
+ + + + + + + Male + + + Female + + + Other + + + I prefer not to state + + + + + + {countries.map((option) => ( + + {option.name} + + ))} + + + + + + + + {professions.map((option) => ( + + {option} + + ))} + + + + selected.join(", "), + }} + > + {medicalConditions.map((name) => ( + + -1 + } + /> + + + ))} + + +
+ ); + + return ( +
+ {status.type === LOADING || !story ? ( + status.detail + ) : ( + <> + +
{informationHeader()}
+ {barDisplay ? profileBar() : ""} + } + onClick={handleClick} + open={open} + > + {actions.map((action) => ( + + props.history.push(action.href, action.state || {}) + } + > + ))} + + + )} +
+ ); +} +export default Dashboard; diff --git a/frontend/src/routes/Dashboard/index.js b/frontend/src/routes/Dashboard/index.js index a0b58b81..e16b5bcd 100644 --- a/frontend/src/routes/Dashboard/index.js +++ b/frontend/src/routes/Dashboard/index.js @@ -1,398 +1,5 @@ -import { - Link, - Collapse, - IconButton, - ListItemText, - Checkbox, - MenuItem, - TextField, - Grid, - Button, -} from "@material-ui/core"; -import { SpeedDial, SpeedDialAction, SpeedDialIcon } from "@material-ui/lab"; -import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; -import classNames from "classnames"; -import React, { useEffect, useState } from "react"; -import { useSelector, useDispatch } from "react-redux"; -import paths from "routes/paths"; -import { sicknessStatus, testStatus } from "routes/types"; -import styles from "./styles.module.css"; -import { fetchStory, submitMyStory, submitStory } from "actions/story"; -import { getStoryResources } from "actions/resources"; -import { LOADING } from "actions/types"; -import { useLocation } from "react-router-dom"; -import api from "utils"; -import Map from "components/Map"; -import { fields, initialFieldsState } from "./fields"; -import Text from "text.json"; -import { makeStyles } from "@material-ui/core/styles"; -const professions = Text["Profession"]; -const medicalConditions = Text["Medical Conditions"]; +import Dashboard from "components/Map" -const useStyles = makeStyles(() => ({ - profileBar: { - width: 600, - bottom: 0, - padding: "0px 30px 40px 20px", - zIndex: 2, - position: "absolute", - background: "rgba(0, 0, 0, 0.6)", - "& .MuiMenuItem-root": { - whiteSpace: "normal", - }, - }, - // eslint-disable-next-line - ["@media (max-width: 780px)"]: { - profileBar: { - width: "100%", - left: 0, - right: 0, - margin: 0, - }, - }, - submitBtn: { - background: "var(--primary) !important", - color: "white", - verticalAlign: "center", - width: "100%", - }, - root: { - "label + &": { - color: "white", - }, - }, -})); -const statusMapping = { - [testStatus.POSITIVE]: { name: "Tested Positive", color: "red" }, - [testStatus.NEGATIVE]: { name: "Tested Negative", color: "purple" }, - [testStatus.NOT_TESTED]: { name: "Not Tested", color: "blue" }, - [sicknessStatus.SICK]: { name: "Sick", color: "orange" }, - [sicknessStatus.RECOVERED]: { name: "Recovered", color: "green" }, - [sicknessStatus.NOT_SICK]: { name: "Not Sick", color: "gray" }, -}; - -function Dashboard(props, { draggableMapRoutes = [] }) { - const dispatch = useDispatch(); - const [countries, setCountries] = useState([]); - const [formValues, setFormValues] = useState(initialFieldsState()); - const [open, setOpen] = useState(false); - const classes = useStyles(); - const [errorMsg, setErrorMsg] = useState({ display: "none", required: null }); - const [barDisplay, setBarDisplay] = useState(false); - // This myStory is only temporarily fetched from state to check whether it's needed to submit myStory - // For uses in components, use story.latestMyStory - const { story, status, tempStory, tempMyStory } = useSelector((state) => { - return state.story; - }); - - let location = useLocation(); - const [draggableMap, setDraggableMap] = useState(false); - const [expanded, setExpanded] = useState( - window.screen.width > 1024 ? true : false - ); - - const handleExpandClick = () => { - setExpanded(!expanded); - }; - - useEffect(() => { - if (tempStory) { - const nextPage = paths.dashboard; - const dto = { - story: tempStory, - nextPage, - travels: [], - closeContacts: [], - }; - dispatch(submitStory(dto)); - } else if (!story) { - dispatch(fetchStory()); - } else if (story && tempMyStory && tempMyStory.length) { - dispatch(submitMyStory(story.id, tempMyStory)); - } - if (story) { - const required = ["age", "sex", "profession"]; - Object.keys(story).forEach((key) => { - if (required.includes(key) && story[key] === null) { - setBarDisplay(true); - } - }); - } - // eslint-disable-next-line - }, [story, tempMyStory]); - - useEffect(() => { - let shouldDragMap = draggableMapRoutes.includes(location.pathname); - if (shouldDragMap !== draggableMap) { - setDraggableMap(draggableMapRoutes.includes(location.pathname)); - } - }, [location, draggableMap, setDraggableMap, draggableMapRoutes]); - - const handleClick = () => { - setOpen(!open); - }; - - const [storyList, setStoryList] = useState([]); - - useEffect(() => { - api(`stories/explore`, { - method: "GET", - }).then((stories) => { - setStoryList(stories); - }); - }, []); - - useEffect(() => { - fetch("https://restcountries.eu/rest/v2/all?fields=name") - .then((res) => res.json()) - .then( - (result) => { - setCountries(result); - }, - () => {} - ); - }, []); - - const handleFormChange = (field) => (event) => { - const intFields = [fields.AGE]; - const key = field.key; - - if (intFields.includes(field)) { - if (/^\d+$/.test(event.target.value)) - setFormValues({ ...formValues, [key]: parseInt(event.target.value) }); - else setFormValues({ ...formValues, [key]: "" }); - } else { - setFormValues({ ...formValues, [key]: event.target.value }); - } - }; - - const handleSubmit = () => { - let tempList = []; - Object.keys(formValues).forEach((key) => { - if (formValues[key] === null && key !== "countryOfOrigin") - tempList.push(key); - }); - if (tempList.length > 0) { - setErrorMsg({ - display: "block", - required: tempList.join(", "), - }); - } else { - const { ...newStory } = formValues; - Object.assign(story, newStory); - - const nextPage = paths.dashboard; - - const dto = { - story: story, - nextPage, - travels: [], - closeContacts: [], - }; - - dispatch(submitStory(dto, true)); - setBarDisplay(false); - } - }; - - const actions = [ - { - name: "MY STORIES", //hasMyStory ? "UPDATE MY STORY" : "ADD MY STORY", - href: paths.storyHistory, - //paths.myStory, - classes: "MuiFab-extended", - }, - { - name: "UPDATE MY STATUS", - href: paths.onboard, - state: { onboard: false }, - classes: classNames("MuiFab-extended assessment", styles.assessment), - }, - { - name: "EDIT MY PROFILE", - href: paths.criticalQuestions, - classes: classNames("MuiFab-extended", styles.profile), - }, - ]; - - const userStatus = () => ( -
-
- - {statusMapping[story.sick].name.toUpperCase()} -
-
- - {statusMapping[story.tested].name.toUpperCase()} -
-
- ); - - const informationHeader = () => ( -
- {userStatus()} - {/* {resources()} */} -
- ); - - const profileBar = () => ( - -
- Please complete the following fields: {errorMsg.required} -
- - - - - - - Male - - - Female - - - Other - - - I prefer not to state - - - - - - {countries.map((option) => ( - - {option.name} - - ))} - - - - - - - - {professions.map((option) => ( - - {option} - - ))} - - - - selected.join(", "), - }} - > - {medicalConditions.map((name) => ( - - -1 - } - /> - - - ))} - - -
- ); - - return ( -
- {status.type === LOADING || !story ? ( - status.detail - ) : ( - <> - -
{informationHeader()}
- {barDisplay ? profileBar() : ""} - } - onClick={handleClick} - open={open} - > - {actions.map((action) => ( - - props.history.push(action.href, action.state || {}) - } - > - ))} - - - )} -
- ); -} export default Dashboard;