From 63d67267a62a5716e77dfdaacfc5ca47b861f475 Mon Sep 17 00:00:00 2001 From: SKairinos Date: Thu, 13 Jun 2024 14:57:29 +0000 Subject: [PATCH] add login forms --- src/api/sso.ts | 2 +- src/app/schemas.ts | 2 +- src/app/store.ts | 2 + src/pages/login/Login.tsx | 12 ++-- src/pages/login/StudentForm.tsx | 37 ---------- src/pages/login/studentForms/Class.tsx | 47 +++++++++++++ src/pages/login/studentForms/FirstName.tsx | 80 ++++++++++++++++++++++ src/pages/login/studentForms/index.tsx | 4 ++ src/router/paths.ts | 2 +- src/router/routes/authentication.tsx | 11 ++- 10 files changed, 152 insertions(+), 47 deletions(-) delete mode 100644 src/pages/login/StudentForm.tsx create mode 100644 src/pages/login/studentForms/Class.tsx create mode 100644 src/pages/login/studentForms/FirstName.tsx create mode 100644 src/pages/login/studentForms/index.tsx diff --git a/src/api/sso.ts b/src/api/sso.ts index e4f48e2..200f9cc 100644 --- a/src/api/sso.ts +++ b/src/api/sso.ts @@ -20,7 +20,7 @@ const ssoApi = api.injectEndpoints({ body, }), }), - loginWithOtp: build.mutation({ + loginWithOtp: build.mutation({ query: body => ({ url: baseUrl + "login-with-otp/", method: "POST", diff --git a/src/app/schemas.ts b/src/app/schemas.ts index 5ab681e..647701f 100644 --- a/src/app/schemas.ts +++ b/src/app/schemas.ts @@ -1,6 +1,6 @@ import * as yup from "yup" -export const accessCodeSchema = yup +export const classIdSchema = yup .string() .matches(/^[A-Z0-9]{5}$/, "Invalid access code") diff --git a/src/app/store.ts b/src/app/store.ts index 6c8e48e..6435007 100644 --- a/src/app/store.ts +++ b/src/app/store.ts @@ -12,6 +12,8 @@ const reducer = combineSlices(api) // Infer the `RootState` type from the root reducer export type RootState = ReturnType +// TODO: create middleware for api errors. +// https://redux-toolkit.js.org/rtk-query/usage/error-handling#handling-errors-at-a-macro-level const store = makeStore({ reducer, middlewares: [api.middleware] }) export default store diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx index 8406b28..c075f03 100644 --- a/src/pages/login/Login.tsx +++ b/src/pages/login/Login.tsx @@ -6,15 +6,16 @@ import * as page from "codeforlife/components/page" // import { tryValidateSync } from "codeforlife/utils/schema" import IndyForm from "./IndyForm" -import StudentForm from "./StudentForm" +import * as studentForms from "./studentForms" import * as teacherForms from "./teacherForms" export interface LoginProps { form: - | "teacher-password" + | "teacher-email" | "teacher-otp" | "teacher-otp-bypass-token" - | "student" + | "student-class" + | "student-first-name" | "indy" } @@ -36,10 +37,11 @@ const Login: FC = ({ form }) => { { { - "teacher-password": , + "teacher-email": , "teacher-otp": , "teacher-otp-bypass-token": , - student: , + "student-class": , + "student-first-name": , indy: , }[form] } diff --git a/src/pages/login/StudentForm.tsx b/src/pages/login/StudentForm.tsx deleted file mode 100644 index f359427..0000000 --- a/src/pages/login/StudentForm.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Stack } from "@mui/material" -import type { FC } from "react" - -import * as form from "codeforlife/components/form" -import { useNavigate } from "codeforlife/hooks" -import { submitForm } from "codeforlife/utils/form" - -import { useLoginAsStudentMutation } from "../../api/sso" -import { paths } from "../../router" -import BaseForm from "./BaseForm" - -export interface StudentFormProps {} - -const StudentForm: FC = () => { - const [loginAsStudent] = useLoginAsStudentMutation() - const navigate = useNavigate() - - return ( - { - navigate(paths.indy.dashboard._) - }, - })} - > - - Log in - - - ) -} - -export default StudentForm diff --git a/src/pages/login/studentForms/Class.tsx b/src/pages/login/studentForms/Class.tsx new file mode 100644 index 0000000..85bb0e7 --- /dev/null +++ b/src/pages/login/studentForms/Class.tsx @@ -0,0 +1,47 @@ +import { ChevronRight as ChevronRightIcon } from "@mui/icons-material" +import { Stack, Typography } from "@mui/material" +import type { FC } from "react" +import { generatePath } from "react-router-dom" + +import * as form from "codeforlife/components/form" +import { useNavigate } from "codeforlife/hooks" + +import { classIdSchema } from "../../../app/schemas" +import { paths } from "../../../router" +import BaseForm from "../BaseForm" + +export interface ClassProps {} + +const Class: FC = () => { + const navigate = useNavigate() + + return ( + { + navigate(generatePath(paths.login.student.class._, { classId })) + }} + > + + + Forgotten your login details? Please check with your teacher. + + + }> + Next + + + + ) +} + +export default Class diff --git a/src/pages/login/studentForms/FirstName.tsx b/src/pages/login/studentForms/FirstName.tsx new file mode 100644 index 0000000..e816bdd --- /dev/null +++ b/src/pages/login/studentForms/FirstName.tsx @@ -0,0 +1,80 @@ +import { ChevronRight as ChevronRightIcon } from "@mui/icons-material" +import { Stack } from "@mui/material" +import { useEffect, type FC } from "react" +import { useParams } from "react-router-dom" +import * as yup from "yup" + +import * as form from "codeforlife/components/form" +import { useNavigate } from "codeforlife/hooks" +import { submitForm } from "codeforlife/utils/form" +import { tryValidateSync } from "codeforlife/utils/schema" + +import { useLoginAsStudentMutation } from "../../../api/sso" +import { classIdSchema } from "../../../app/schemas" +import { paths } from "../../../router" +import BaseForm from "../BaseForm" + +export interface FirstNameProps {} + +const FirstName: FC = () => { + const [loginAsStudent] = useLoginAsStudentMutation() + const navigate = useNavigate() + + const params = tryValidateSync( + useParams(), + yup.object({ classId: classIdSchema.required() }), + ) + + useEffect(() => { + if (!params) { + navigate(paths.login.student._, { + state: { + notifications: [ + { + props: { + error: true, + children: "Please provide a valid access code for your class.", + }, + }, + ], + }, + }) + } + }, [navigate, params]) + + return ( + <> + {params && ( + { + navigate(paths.student.dashboard._) + }, + })} + > + + + + }> + Log in + + + + )} + + ) +} + +export default FirstName diff --git a/src/pages/login/studentForms/index.tsx b/src/pages/login/studentForms/index.tsx new file mode 100644 index 0000000..662cdb3 --- /dev/null +++ b/src/pages/login/studentForms/index.tsx @@ -0,0 +1,4 @@ +import Class, { type ClassProps } from "./Class" +import FirstName, { type FirstNameProps } from "./FirstName" + +export { Class, FirstName, type ClassProps, type FirstNameProps } diff --git a/src/router/paths.ts b/src/router/paths.ts index f62edbf..327104d 100644 --- a/src/router/paths.ts +++ b/src/router/paths.ts @@ -8,7 +8,7 @@ const paths = _("", { }), }), student: _("/student", { - class: _("/:accessCode"), + class: _("/:classId"), }), independent: _("/independent"), }), diff --git a/src/router/routes/authentication.tsx b/src/router/routes/authentication.tsx index a118d44..df70e3b 100644 --- a/src/router/routes/authentication.tsx +++ b/src/router/routes/authentication.tsx @@ -24,7 +24,7 @@ const authentication = ( <> } + element={} /> } /> - } /> + } + /> + } + /> } /> )