diff --git a/frontend/src/components/NotesDisplayCard.jsx b/frontend/src/components/NotesDisplayCard.jsx
index a1bf4d33..824c6374 100644
--- a/frontend/src/components/NotesDisplayCard.jsx
+++ b/frontend/src/components/NotesDisplayCard.jsx
@@ -1,5 +1,5 @@
-import { useState, useEffect } from "react";
import { usePost } from "hooks/crudHooks";
+import { useEffect, useState } from "react";
import styles from "../styling/NotesDisplayCard.module.scss";
import Note from "./Note";
@@ -16,25 +16,22 @@ export default function NotesDisplayCard({ group, user, handleClose }) {
}
// refetch group data to get updated notes
- async function loadGroup() {
+ async function fetchNotesData() {
const groupData = await usePost("/api/group/", {
groupId: group._id,
});
- loadNotes(groupData);
+ await loadNotes(groupData);
}
- const checkRole = () => {
+ useEffect(() => {
+ // Check roles
group.users.forEach((userToCheck) => {
if (userToCheck.email === user.email) {
setRole(userToCheck.role);
}
});
- };
- useEffect(() => {
- console.log(user);
- loadGroup();
- checkRole();
+ fetchNotesData();
}, []);
const handleCreate = async () => {
@@ -47,7 +44,7 @@ export default function NotesDisplayCard({ group, user, handleClose }) {
role: userRole,
});
console.log("note created");
- loadGroup();
+ fetchNotesData();
};
const handleKeyPress = (e) => {
@@ -77,7 +74,7 @@ export default function NotesDisplayCard({ group, user, handleClose }) {
id={note.id}
group={group}
user={user}
- refetchGroup={loadGroup}
+ refetchGroup={fetchNotesData}
/>
))}
-
-
-
diff --git a/frontend/src/containers/pages/InvalidRolePage.jsx b/frontend/src/containers/pages/InvalidRolePage.jsx
index 590a3452..d1bf768f 100644
--- a/frontend/src/containers/pages/InvalidRolePage.jsx
+++ b/frontend/src/containers/pages/InvalidRolePage.jsx
@@ -1,9 +1,10 @@
+import { Button } from "@mui/material";
import { useContext, useState } from "react";
-import AuthenticationContext from "../../context/AuthenticationContext";
-import NotesDisplayCard from "../../components/NotesDisplayCard";
import BacktoScenarioSelectionButton from "../../components/BacktoScenarioSelectionButton";
+import NotesDisplayCard from "../../components/NotesDisplayCard";
+import AuthenticationContext from "../../context/AuthenticationContext";
-function InvalidRolePage(group) {
+function InvalidRolePage({ group }) {
const currentUserRole = "Doctor";
const rolesWithAccess = ["Nurse", "Patient"];
const [noteOpen, setNoteOpen] = useState(false);
@@ -42,13 +43,23 @@ function InvalidRolePage(group) {
Someone else is playing through this section of the scenario!
Please wait for your role: {currentUserRole}
+
+
+ — or —
+
Roles with access to this scene: {rolesWithAccess.join(", ")}
-
{noteOpen && (
)}
diff --git a/frontend/src/containers/pages/ManageGroups/ManageGroups.jsx b/frontend/src/containers/pages/ManageGroups/ManageGroups.jsx
new file mode 100644
index 00000000..e69de29b
diff --git a/frontend/src/containers/pages/ManageGroups/ManageGroupsPage.jsx b/frontend/src/containers/pages/ManageGroups/ManageGroupsPage.jsx
index 70f9f7c0..fb93138a 100644
--- a/frontend/src/containers/pages/ManageGroups/ManageGroupsPage.jsx
+++ b/frontend/src/containers/pages/ManageGroups/ManageGroupsPage.jsx
@@ -1,36 +1,52 @@
import { Button } from "@material-ui/core";
-import { useRef, useState } from "react";
-import { useParams } from "react-router-dom";
-import Papa from "papaparse";
-import ScreenContainer from "components/ScreenContainer";
+import { Alert, Snackbar } from "@mui/material";
import axios from "axios";
+import ScreenContainer from "components/ScreenContainer";
import { useGet } from "hooks/crudHooks";
-import TopBar from "./TopBar";
+import Papa from "papaparse";
+import { useRef, useState } from "react";
+import { useParams } from "react-router-dom";
import GroupsTable from "./GroupTable";
+import TopBar from "./TopBar";
/**
* Page that shows the groups that the admin can manipulate
*
* @container
*/
-
export default function ManageGroupsPage() {
const { scenarioId } = useParams();
const [scenarioGroupInfo, setScenarioGroupInfo] = useState([]);
- let groups;
+
+ const [isToastShowing, setIsToastShowing] = useState(false);
+ const [toastText, setToastText] = useState("");
+ const [toastType, setToastType] = useState("");
+
+ let users = [];
// fetch groups assigned to this scenario
- const fetchGroups = () => {
- useGet(`/api/group/scenario/${scenarioId}`, setScenarioGroupInfo);
- if (scenarioGroupInfo[0]) {
- groups = scenarioGroupInfo[0].users;
- } else {
- groups = [];
- }
+ const { reFetch } = useGet(
+ `/api/group/scenario/${scenarioId}`,
+ setScenarioGroupInfo
+ );
+ console.log(scenarioGroupInfo);
+ if (scenarioGroupInfo.length) {
+ // Iterate groups and flatten to user list
+ scenarioGroupInfo.forEach((group) => {
+ if (group) {
+ users.push(...group.users);
+ }
+ });
+ } else {
+ users = [];
+ }
+
+ const showToast = (text, type = "success") => {
+ setToastText(text);
+ setToastType(type);
+ setIsToastShowing(true);
};
- fetchGroups();
-
// File input is a hidden input element that is activated via a click handler
// This allows us to have an UI button that acts like a file element.
const fileInputRef = useRef(null);
@@ -88,12 +104,12 @@ export default function ManageGroupsPage() {
jsonData
);
+ reFetch();
console.log("CSV data uploaded to MongoDB:", response.status);
- // TODO: ESLINT ignore; change alerts so unexpected alerts error goes away
- // alert("CSV successfully uploaded and data stored in MongoDB!");
+ showToast("Successfully formed groups!");
} catch (error) {
console.error("Error uploading CSV data:", error);
- // alert("Error uploading CSV data.");
+ showToast("Error uploading CSV data!", "error");
}
},
});
@@ -131,7 +147,7 @@ export default function ManageGroupsPage() {
};
const download = () => {
- const csv = convertToCSV(groups);
+ const csv = convertToCSV(users);
const blob = new Blob([csv], { type: "text/csv" });
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
@@ -143,6 +159,14 @@ export default function ManageGroupsPage() {
window.URL.revokeObjectURL(url);
};
+ // Toast close handler
+ const handleToastDismiss = (_, reason) => {
+ if (reason === "clickaway") {
+ return;
+ }
+ setIsToastShowing(false);
+ };
+
return (
@@ -171,9 +195,21 @@ export default function ManageGroupsPage() {
-
+
+
+
+ {toastText}
+
+
);
}
-
-// export FileUpload;
diff --git a/frontend/src/containers/pages/PlayScenarioPage/PlayScenarioResolver.jsx b/frontend/src/containers/pages/PlayScenarioPage/PlayScenarioResolver.jsx
index e0a4cf94..6291f1e8 100644
--- a/frontend/src/containers/pages/PlayScenarioPage/PlayScenarioResolver.jsx
+++ b/frontend/src/containers/pages/PlayScenarioPage/PlayScenarioResolver.jsx
@@ -1,4 +1,5 @@
-import { useEffect, useContext, useState } from "react";
+import axios from "axios";
+import { useContext, useEffect, useState } from "react";
import {
Route,
Switch,
@@ -6,14 +7,14 @@ import {
useLocation,
useParams,
} from "react-router-dom";
-import axios from "axios";
import AuthenticationContext from "context/AuthenticationContext";
import useGraph from "hooks/useGraph";
+import DesyncPage from "../DesyncPage";
+import InvalidRolePage from "../InvalidRolePage";
import PlayScenarioPage from "./PlayScenarioPage";
import PlayScenarioPageMulti from "./PlayScenarioPageMulti";
-import DesyncPage from "../DesyncPage";
// TODO: move this somewhere else and add error handling
async function get(url, userIdToken) {
@@ -54,6 +55,9 @@ export default function PlayScenarioResolver() {
return (
+
+
+