From ce5f7d885e17a1c8789ed0eab41a21ab6ca1b78f Mon Sep 17 00:00:00 2001 From: larry kirschner Date: Wed, 25 Aug 2021 12:48:47 -0700 Subject: [PATCH] improvements for careerfair testing (#129) * increase max video-record time to 5 min (#110) * If setup is not complete, redirect to setup page from home page: (#96) * move curAnswer to state (#105) * thumbnail data in redux (#109) * tests for simple mentor change & switch functions * prompts user to upload video if leaving page, other small bug fix (#112) * visual indication when mentor isn't owned by user * Only admin can see mentor selection tools. * login query grabs default mentor id for user * fetchbyid uses findone query * must fix cypress tests * Mentor always fetched by ID, no me query in fetch * separate use[Active]Mentor (redux) from useMentorEdits (useState hook) (#120) Co-authored-by: Jim Alvarez * merges main back to integration branch (#123) Co-authored-by: kycarr Co-authored-by: Aaron shiel <57824522+aaronshiel@users.noreply.github.com> Co-authored-by: larry kirschner Co-authored-by: aaronshiel Co-authored-by: aaronshiel Co-authored-by: Jim Alvarez * impr: switches to mentorpal docker account from uscictdocker (#127) * fixes: lint error Co-authored-by: kycarr Co-authored-by: Aaron shiel <57824522+aaronshiel@users.noreply.github.com> Co-authored-by: Jim Alvarez Co-authored-by: Jaime Alvarez Co-authored-by: aaronshiel Co-authored-by: aaronshiel --- client/src/api.ts | 15 +- client/src/components/home/index.tsx | 101 +++++++++--- .../src/components/my-mentor-card/index.tsx | 38 +++-- .../components/my-mentor-card/mentor-info.tsx | 23 +++ .../recommended-action-button.tsx | 3 - .../use-with-recommended-action.tsx | 41 ++--- .../src/components/record/video-recorder.jsx | 2 - .../hooks/graphql/use-with-import-export.tsx | 42 ++--- .../hooks/graphql/use-with-record-state.tsx | 55 ++++--- .../graphql/use-with-review-answer-state.tsx | 28 ++-- client/src/hooks/graphql/use-with-setup.tsx | 29 ++-- client/src/hooks/graphql/use-with-subject.tsx | 4 +- .../src/hooks/graphql/use-with-thumbnail.ts | 2 +- client/src/hooks/task/use-with-train.tsx | 4 +- client/src/pages/author/subject.tsx | 14 +- client/src/pages/author/subjects.tsx | 11 +- client/src/pages/feedback.tsx | 41 ++--- client/src/pages/importexport.tsx | 11 +- client/src/pages/record.tsx | 27 ++-- client/src/pages/subjects.tsx | 21 +-- client/src/store/slices/mentor/index.ts | 77 +++++---- .../store/slices/mentor/useActiveMentor.ts | 89 +++++++++++ .../src/store/slices/mentor/useMentorEdits.ts | 88 ++++++++++ .../src/store/slices/mentor/useWithMentor.ts | 150 ------------------ cypress/cypress/fixtures/login.ts | 1 + cypress/cypress/integration/home.spec.ts | 11 -- cypress/cypress/integration/setup.spec.ts | 8 +- cypress/cypress/integration/subjects.spec.ts | 83 ++++++---- .../integration/switch-active-mentor.spec.ts | 92 +++++++++++ cypress/cypress/support/functions.ts | 10 +- cypress/cypress/support/types.ts | 1 + 31 files changed, 694 insertions(+), 428 deletions(-) create mode 100644 client/src/store/slices/mentor/useActiveMentor.ts create mode 100644 client/src/store/slices/mentor/useMentorEdits.ts delete mode 100644 client/src/store/slices/mentor/useWithMentor.ts create mode 100644 cypress/cypress/integration/switch-active-mentor.spec.ts diff --git a/client/src/api.ts b/client/src/api.ts index 1a635ff4..50a6ac9e 100644 --- a/client/src/api.ts +++ b/client/src/api.ts @@ -606,8 +606,9 @@ export async function updateUserQuestion( ); } -export async function fetchMentor( +export async function fetchMentorById( accessToken: string, + mentorId: string, subject?: string, topic?: string, status?: string @@ -615,9 +616,8 @@ export async function fetchMentor( return execGql( { query: ` - query Mentor($subject: ID!, $topic: ID!, $status: String!) { - me { - mentor { + query MentorFindOne($mentor: ID!, $subject: ID!, $topic: ID!, $status: String!) { + mentor (id: $mentor){ _id name firstName @@ -698,15 +698,15 @@ export async function fetchMentor( } } } - } `, variables: { + mentor: mentorId, subject: subject || "", topic: topic || "", status: status || "", }, }, - { dataPath: ["me", "mentor"], accessToken } + { dataPath: ["mentor"], accessToken } ); } @@ -908,6 +908,9 @@ export async function login(accessToken: string): Promise { _id name userRole + defaultMentor{ + _id + } } accessToken } diff --git a/client/src/components/home/index.tsx b/client/src/components/home/index.tsx index 017b0803..0a756e8a 100644 --- a/client/src/components/home/index.tsx +++ b/client/src/components/home/index.tsx @@ -19,6 +19,7 @@ import { ListItem, MenuItem, Select, + TextField, Toolbar, Typography, } from "@material-ui/core"; @@ -30,9 +31,12 @@ import withAuthorizationOnly from "hooks/wrap-with-authorization-only"; import { useWithReviewAnswerState } from "hooks/graphql/use-with-review-answer-state"; import { ErrorDialog, LoadingDialog } from "components/dialog"; import MyMentorCard from "components/my-mentor-card"; -import { User } from "types"; +import { Subject, User, UserRole } from "types"; import { launchMentor } from "helpers"; import { useWithSetup } from "hooks/graphql/use-with-setup"; +import useActiveMentor, { + useActiveMentorActions, +} from "store/slices/mentor/useActiveMentor"; const useStyles = makeStyles((theme) => ({ toolbar: theme.mixins.toolbar, @@ -78,7 +82,6 @@ function HomePage(props: { search: { subject?: string }; user: User; }): JSX.Element { - const classes = useStyles(); const { useMentor, isLoading, @@ -92,18 +95,33 @@ function HomePage(props: { saveChanges, startTraining, } = useWithReviewAnswerState(props.accessToken, props.search); - const { mentor, isMentorEdited } = useMentor; + const defaultMentor = props.user.defaultMentor._id; + + const mentorId = useActiveMentor((m) => m.data?._id || ""); + const { loadMentor } = useActiveMentorActions(); + const { isMentorEdited } = useMentor; const { setupStatus, navigateToMissingSetup } = useWithSetup(); const [showSetupAlert, setShowSetupAlert] = useState(true); - + const [activeMentorId, setActiveMentorId] = useState(defaultMentor); + const mentorOwnership = defaultMentor === mentorId; + const classes = useStyles(); + const mentorIsDirty = useActiveMentor((m) => Boolean(m.data?.isDirty)); + const mentorSubjectNamesById: Record = useActiveMentor((m) => + (m.data?.subjects || []).reduce( + (acc: Record, cur: Subject) => { + acc[cur._id] = cur.name; + return acc; + }, + {} + ) + ); React.useEffect(() => { if (!setupStatus || !showSetupAlert) { return; } setShowSetupAlert(!setupStatus.isSetupComplete); }, [setupStatus]); - - if (!mentor || !setupStatus) { + if (!(mentorId && setupStatus)) { return (
@@ -115,30 +133,75 @@ function HomePage(props: { navigate("/setup"); } + if (!setupStatus.isMentorInfoDone) { + navigate("/setup"); + } + const continueAction = () => - mentor.isDirty ? startTraining(mentor._id) : launchMentor(mentor._id); + mentorIsDirty ? startTraining(mentorId) : launchMentor(mentorId); return ( -
+
+ {props.user.userRole === UserRole.ADMIN && ( +
+ setActiveMentorId(e.target.value)} + /> + loadMentor(activeMentorId)} + className={classes.fab} + > + Switch Mentor + + { + setActiveMentorId(defaultMentor); + loadMentor(); + }} + className={classes.fab} + > + Default Mentor + +
+ )} + @@ -170,7 +233,7 @@ function HomePage(props: { ))} @@ -198,11 +261,11 @@ function HomePage(props: { data-cy="train-button" variant="extended" color="primary" - disabled={!mentor || isTraining || isLoading || isSaving} + disabled={!mentorId || isTraining || isLoading || isSaving} onClick={continueAction} className={classes.fab} > - {mentor.isDirty ? "Build Mentor" : "Preview Mentor"} + {mentorIsDirty ? "Build Mentor" : "Preview Mentor"} diff --git a/client/src/components/my-mentor-card/index.tsx b/client/src/components/my-mentor-card/index.tsx index 9c202441..0d9c1276 100644 --- a/client/src/components/my-mentor-card/index.tsx +++ b/client/src/components/my-mentor-card/index.tsx @@ -26,10 +26,14 @@ import { HelpOutline } from "@material-ui/icons"; import { useWithThumbnail } from "hooks/graphql/use-with-thumbnail"; import RecommendedActionButton from "./recommended-action-button"; import StageProgress from "./stage-progress"; -import parseMentor from "./mentor-info"; +import parseMentor, { defaultMentorInfo } from "./mentor-info"; import { ErrorDialog, LoadingDialog } from "components/dialog"; import { MentorType } from "types"; -import { UseWithMentor } from "store/slices/mentor/useWithMentor"; +import { UseMentorEdits } from "store/slices/mentor/useMentorEdits"; +import useActiveMentor, { + isActiveMentorLoading, + isActiveMentorSaving, +} from "store/slices/mentor/useActiveMentor"; const useStyles = makeStyles(() => ({ homeThumbnail: { @@ -50,23 +54,22 @@ const useStyles = makeStyles(() => ({ })); export default function MyMentorCard(props: { - accessToken: string; + editDisabled: boolean; continueAction: () => void; - useMentor: UseWithMentor; + useMentor: UseMentorEdits; }): JSX.Element { - const { - mentor, - isMentorLoading, - isMentorSaving, - mentorError, - editedMentor, - editMentor, - } = props.useMentor; + const mentorError = useActiveMentor((ms) => ms.error); + const isMentorLoading = isActiveMentorLoading(); + const isMentorSaving = isActiveMentorSaving(); + const { editedMentor, editMentor } = props.useMentor; + const mentorId = useActiveMentor((ms) => ms.data?._id || ""); - if (!mentor || !editedMentor) { + if (!mentorId || !editedMentor) { return
; } - const mentorInfo = parseMentor(mentor); + const mentorInfo = useActiveMentor((ms) => + ms.data ? parseMentor(ms.data) : defaultMentorInfo + ); const classes = useStyles(); const [thumbnail, updateThumbnail] = useWithThumbnail(); @@ -89,6 +92,7 @@ export default function MyMentorCard(props: { value={editedMentor.name} onChange={(e) => editMentor({ name: e.target.value })} className={classes.inputField} + disabled={props.editDisabled} /> editMentor({ title: e.target.value })} className={classes.inputField} + disabled={props.editDisabled} /> editMentor({ firstName: e.target.value })} className={classes.inputField} + disabled={props.editDisabled} /> editMentor({ email: e.target.value })} className={classes.inputField} + disabled={props.editDisabled} /> } label="Allow people to contact me" @@ -168,6 +176,7 @@ export default function MyMentorCard(props: {