Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preview assessment from teacher dashboard #605

Open
wants to merge 5 commits into
base: joyce/preview
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/src/assets/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,8 @@ export const SaveOutlineIcon = (): React.ReactElement => (
</Icon>
);

export const EyeOutlineIcon = (): React.ReactElement => (
<Icon viewBox="0 0 24 24">
export const EyeOutlineIcon = (props: IconProps): React.ReactElement => (
<Icon viewBox="0 0 24 24" {...props}>
<rect height="24" opacity="0" width="24" />
<path
d="M21.87 11.5c-.64-1.11-4.16-6.68-10.14-6.5-5.53.14-8.73 5-9.6 6.5a1 1 0 0 0 0 1c.63 1.09 4 6.5 9.89 6.5h.25c5.53-.14 8.74-5 9.6-6.5a1 1 0 0 0 0-1zM12.22 17c-4.31.1-7.12-3.59-8-5 1-1.61 3.61-4.9 7.61-5 4.29-.11 7.11 3.59 8 5-1.03 1.61-3.61 4.9-7.61 5z"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const AssessmentEditorHeader = ({
const onPreview = () => {
validateForm();
disableEditorPrompt(history.push)(
Routes.ASSESSMENT_PREVIEW_PAGE({
Routes.ADMIN_ASSESSMENT_PREVIEW_PAGE({
assessmentId,
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const PreviewButton = ({
onClick={async () => {
if (data) {
history.push({
pathname: Routes.ASSESSMENT_PREVIEW_PAGE({ assessmentId }),
pathname: Routes.ADMIN_ASSESSMENT_PREVIEW_PAGE({ assessmentId }),
state: data.test,
});
} else {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/pages/admin/AdminRouting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import type Page from "../../../types/PageTypes";
import PrivateRoute from "../../auth/PrivateRoute";
import RedirectTo from "../../auth/RedirectTo";
import Navbar from "../../common/navigation/Navbar";
import AssessmentPreviewPage from "../common/AssessmentPreviewPage";
import NotFound from "../NotFound";

import AssessmentEditorPage from "./AssessmentEditorPage";
import AssessmentPreviewPage from "./AssessmentPreviewPage";
import DisplayAssessmentsPage from "./DisplayAssessmentsPage";
import UsersPage from "./UsersPage";

Expand All @@ -36,7 +36,7 @@ const AdminRouting = (): React.ReactElement => {
/>
<PrivateRoute
component={AssessmentPreviewPage}
path={Routes.ASSESSMENT_PREVIEW_PAGE({
path={Routes.ADMIN_ASSESSMENT_PREVIEW_PAGE({
assessmentId: ":assessmentId",
})}
roles={["Admin"]}
Expand Down
99 changes: 53 additions & 46 deletions frontend/src/components/pages/teacher/TeacherRouting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type Page from "../../../types/PageTypes";
import PrivateRoute from "../../auth/PrivateRoute";
import RedirectTo from "../../auth/RedirectTo";
import Navbar from "../../common/navigation/Navbar";
import AssessmentPreviewPage from "../common/AssessmentPreviewPage";
import NotFound from "../NotFound";

import ClassroomsPage from "./ClassroomsPage";
Expand All @@ -27,56 +28,62 @@ const TeacherRouting = (): React.ReactElement => {
<VStack align="left" flex="1" height="100vh">
<Switch>
<Route path={Routes.DISPLAY_ASSESSMENT_RESULTS_PAGE()} />
<Route
component={AssessmentPreviewPage}
path={Routes.TEACHER_ASSESSMENT_PREVIEW_PAGE({
assessmentId: ":assessmentId",
})}
/>
<Route path="*">
<Navbar pages={pages} />
<Flex flex="1" flexDirection="column" padding="1.5em 2em 2em 2em">
<Switch>
<PrivateRoute
component={DisplayAssessmentResults}
path={Routes.DISPLAY_ASSESSMENT_RESULTS_PAGE()}
roles={["Teacher"]}
title="Assessment Results"
/>
<PrivateRoute
component={TeacherDashboardPage}
exact
path={Routes.TEACHER_DASHBOARD_PAGE}
roles={["Teacher"]}
title="Dashboard"
/>
<PrivateRoute
component={DistributeAssessmentPage}
exact
path={Routes.DISTRIBUTE_ASSESSMENT_PAGE}
roles={["Teacher"]}
title="Distribute Assessment"
/>
<PrivateRoute
component={DisplayAssessmentsPage}
path={Routes.DISPLAY_ASSESSMENTS_PAGE}
roles={["Teacher"]}
title="Assessments"
/>
<PrivateRoute
component={ClassroomsPage}
exact
path={Routes.CLASSROOMS_PAGE}
roles={["Teacher"]}
title="Classrooms"
/>
<PrivateRoute
component={DisplayClassroomPage}
path={Routes.DISPLAY_CLASSROOM_PAGE()}
roles={["Teacher"]}
/>
<Route exact path={Routes.TEACHER_LANDING_PAGE}>
<RedirectTo pathname={Routes.TEACHER_DASHBOARD_PAGE} />
</Route>
<Route component={NotFound} exact path="*" />
</Switch>
</Flex>
</Route>
jfdoming marked this conversation as resolved.
Show resolved Hide resolved
</Switch>
<Flex flex="1" flexDirection="column" padding="1.5em 2em 2em 2em">
<Switch>
<PrivateRoute
component={DisplayAssessmentResults}
path={Routes.DISPLAY_ASSESSMENT_RESULTS_PAGE()}
roles={["Teacher"]}
title="Assessment Results"
/>
<PrivateRoute
component={TeacherDashboardPage}
exact
path={Routes.TEACHER_DASHBOARD_PAGE}
roles={["Teacher"]}
title="Dashboard"
/>
<PrivateRoute
component={DistributeAssessmentPage}
exact
path={Routes.DISTRIBUTE_ASSESSMENT_PAGE}
roles={["Teacher"]}
title="Distribute Assessment"
/>
<PrivateRoute
component={DisplayAssessmentsPage}
path={Routes.DISPLAY_ASSESSMENTS_PAGE}
roles={["Teacher"]}
title="Assessments"
/>
<PrivateRoute
component={ClassroomsPage}
exact
path={Routes.CLASSROOMS_PAGE}
roles={["Teacher"]}
title="Classrooms"
/>
<PrivateRoute
component={DisplayClassroomPage}
path={Routes.DISPLAY_CLASSROOM_PAGE()}
roles={["Teacher"]}
/>
<Route exact path={Routes.TEACHER_LANDING_PAGE}>
<RedirectTo pathname={Routes.TEACHER_DASHBOARD_PAGE} />
</Route>
<Route component={NotFound} exact path="*" />
</Switch>
</Flex>
</VStack>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from "react";
import { useHistory } from "react-router-dom";
import { useLazyQuery } from "@apollo/client";
import { Radio, RadioGroup, Text } from "@chakra-ui/react";

import { GET_TEST } from "../../../APIClients/queries/TestQueries";
import type { TestResponse } from "../../../APIClients/types/TestClientTypes";
import type { Grade } from "../../../APIClients/types/UserClientTypes";
import { EyeOutlineIcon } from "../../../assets/icons";
import * as Routes from "../../../constants/Routes";
import type { UseCase } from "../../../types/AssessmentTypes";
import { removeUnderscore, titleCase } from "../../../utils/GeneralUtils";
import ActionButton from "../../common/form/ActionButton";
import useToast from "../../common/info/useToast";
import type { TableRow } from "../../common/table/Table";
import { Table } from "../../common/table/Table";

Expand Down Expand Up @@ -31,6 +39,33 @@ const AssessmentsTable = ({
setTestName,
isDisabled = false,
}: AssessmentsTableProps): React.ReactElement => {
const history = useHistory();
const { showToast } = useToast();

const [previewAssessmentQuery] = useLazyQuery<{
test: TestResponse;
}>(GET_TEST);

const previewAssessment = async (assessmentId: string) => {
const { data } = await previewAssessmentQuery({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: instead of checking for nullish data, we should catch exceptions here, since awaited Apollo lazy queries throw any error instead of returning it

variables: { id: assessmentId },
});
if (data) {
history.push({
pathname: Routes.TEACHER_ASSESSMENT_PREVIEW_PAGE({
assessmentId,
}),
state: data.test,
});
} else {
showToast({
message:
"This assessment cannot be previewed at this time. Please try again.",
status: "error",
});
}
};

const headers = ["", "Name", "Grade", "Type", "Country", "Region"];
const rows: TableRow[] = assessments.map((assessment, i) => ({
id: assessment.id,
Expand All @@ -49,6 +84,15 @@ const AssessmentsTable = ({
assessment.curriculumCountry,
assessment.curriculumRegion,
],
menu: (
<ActionButton
aria-label="preview-assessment"
leftIcon={<EyeOutlineIcon boxSize={5} />}
onClick={() => previewAssessment(assessment.id)}
showDefaultToasts={false}
size="sm"
/>
),
onClick: () => {
setTestId(assessment.id);
if (setTestName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { type ReactElement } from "react";
import { useHistory } from "react-router-dom";
import { useMutation } from "@apollo/client";
import { useLazyQuery, useMutation } from "@apollo/client";
import { Divider, useDisclosure, VStack } from "@chakra-ui/react";

import { DELETE_TEST_SESSION } from "../../../APIClients/mutations/TestSessionMutations";
import { GET_TEST } from "../../../APIClients/queries/TestQueries";
import { GET_TEST_SESSIONS_BY_TEACHER_ID } from "../../../APIClients/queries/TestSessionQueries";
import type { TestResponse } from "../../../APIClients/types/TestClientTypes";
import * as Routes from "../../../constants/Routes";
import { TestSessionStatus } from "../../../types/TestSessionTypes";
import { getQueryName } from "../../../utils/GeneralUtils";
import DeleteAssessmentModal from "../../admin/assessment-status/EditStatusModals/DeleteAssessmentModal";
import useToast from "../../common/info/useToast";
import Popover from "../../common/popover/Popover";
import PopoverButton from "../../common/popover/PopoverButton";

Expand All @@ -26,8 +29,8 @@ const TestSessionListItemPopover = ({
onOpen: openDeleteModal,
onClose: onDeleteModalClose,
} = useDisclosure();

const history = useHistory();
const { showToast } = useToast();

const [deleteTestSession] = useMutation(DELETE_TEST_SESSION, {
variables: { id: session.testSessionId },
Expand All @@ -38,12 +41,40 @@ const TestSessionListItemPopover = ({
history.push(Routes.DISTRIBUTE_ASSESSMENT_PAGE, session);
};

const [previewTest] = useLazyQuery<{
test: TestResponse;
}>(GET_TEST);

const onPreviewTest = async () => {
const { data } = await previewTest({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment!

variables: { id: session.testId },
});
if (data) {
history.push({
pathname: Routes.TEACHER_ASSESSMENT_PREVIEW_PAGE({
assessmentId: session.testId,
}),
state: data.test,
});
} else {
showToast({
message:
"This assessment cannot be previewed at this time. Please try again.",
status: "error",
});
}
};

return (
<Popover>
<VStack divider={<Divider />} spacing={0}>
<PopoverButton name="Edit" onClick={onEditTestSession} />
{session.status !== TestSessionStatus.PAST && (
<PopoverButton name="Delete" onClick={openDeleteModal} />
<>
<PopoverButton name="Delete" onClick={openDeleteModal} />
<Divider />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the extra divider here? I think VStack with the divider prop should automatically handle it, provided you remove the extra fragment (<>). (If we want to hide the whole popover for past sessions, it would make more sense IMO to either conditionally return null from this component, or (better) conditionally render the entire TestSessionListItemPopover component in the parent TestSessionListItem or wherever else this component is used.)

<PopoverButton name="Preview" onClick={onPreviewTest} />
</>
)}
</VStack>
<DeleteAssessmentModal
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/constants/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const ASSESSMENT_EDITOR_QUESTION_PREVIEW_PAGE = ({
ASSESSMENT_EDITOR_QUESTION_EDITOR_BASE({ assessmentId, questionIndex }) +
"/preview";

export const ASSESSMENT_PREVIEW_PAGE = ({
export const ADMIN_ASSESSMENT_PREVIEW_PAGE = ({
assessmentId,
}: {
assessmentId?: string;
Expand Down Expand Up @@ -81,6 +81,11 @@ export const DISPLAY_CLASSROOM_ASSESSMENTS_PAGE = ({
export const DISPLAY_CLASSROOM_STUDENTS_PAGE = ({
classroomId = ":classroomId",
} = {}) => `/teacher/classrooms/${classroomId}/students`;
export const TEACHER_ASSESSMENT_PREVIEW_PAGE = ({
assessmentId,
}: {
assessmentId?: string;
}) => "/teacher/assessment-preview/" + assessmentId;

// Private Student Routes
export const STUDENT_LANDING_PAGE = "/student";
Expand Down