Skip to content

Commit

Permalink
feat: 35 teachers onboarding (ocadotechnology#36)
Browse files Browse the repository at this point in the history
* cleanup  search params logic

* Reset password forms

* skeleton

* fix stepper style

* complete school form

* complete class form

* one based indexing

* new cfl package

* new cfl package

* fix theme inheritance

* complete students form

* new cfl package

* quick save

* new cfl package

* quick save

* fix formatting

* fix styling

* add todo

* add todos

* fix multiple value validation

* fix style issues

* fix height issues

* rename formik folder to form

* make components reusable

* fix regex

* merge from main

* use new CFL package

* fix path

* first round of feedback

* tidy up url paths

* tidy up url path pt.2
  • Loading branch information
SKairinos authored Jun 2, 2023
1 parent 9e330de commit 3f9213b
Show file tree
Hide file tree
Showing 42 changed files with 1,073 additions and 268 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@mui/icons-material": "^5.11.11",
"@mui/material": "^5.11.12",
"@reduxjs/toolkit": "^1.9.3",
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v1.10.17",
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v1.14.2",
"country-list": "^2.3.0",
"formik": "^2.2.9",
"react": "^18.2.0",
Expand Down
54 changes: 35 additions & 19 deletions frontend/src/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import BackupTokens from '../pages/teacherDashboard/account/2fa/BackupTokens';
import EmailVerification from '../pages/emailVerification/EmailVerification';
import ResetPassword from '../pages/resetPassword/ResetPassword';
import StudentsDashboard from '../pages/studentsDashboard/StudentsDashboard';
import TeacherOnboarding from '../pages/teacherOnboarding/TeacherOnboarding';

export const paths = {
home: '/',
Expand All @@ -42,13 +43,29 @@ export const paths = {
teacher: '/reset-password?userType=teacher',
independent: '/reset-password?userType=independent'
},
teachers: '/teachers',
students: {
_: '/students',
teacher: {
_: '/teacher',
onboarding: '/teacher/onboarding',
dashboard: {
_: '/students/dashboard',
dependent: '/students/dashboard?userType=dependent',
independent: '/students/dashboard?userType=independent'
_: '/teacher/dashboard',
school: '/teacher/dashboard/school',
classes: '/teacher/dashboard/classes',
account: {
_: '/teacher/dashboard/account',
twoFA: {
_: '/teacher/dashboard/account/2fa',
setup: '/teacher/dashboard/account/2fa/setup',
backupTokens: '/teacher/dashboard/account/2fa/backup-tokens'
}
}
}
},
student: {
_: '/student',
dashboard: {
_: '/student/dashboard',
dependent: '/student/dashboard?userType=dependent',
independent: '/student/dashboard?userType=independent'
}
},
register: '/register',
Expand All @@ -68,11 +85,6 @@ export const paths = {
pageNotFound: '/error/page-not-found',
internalServerError: '/error/internal-server-error',
rapidRouter: '/rapid-router',
teacherSchool: '/teacher/school',
teacherClasses: '/teacher/classes',
teacherAccount: '/teacher/account',
setup2fa: '/teacher/account/2fa/setup',
backupTokens: '/teacher/account/2fa/backup-tokens',
kurono: '/kurono'
};

Expand All @@ -86,15 +98,19 @@ const router = createBrowserRouter([
element: <Login />
},
{
path: paths.teachers,
path: paths.teacher._,
element: <Teachers />
},
{
path: paths.students._,
path: paths.teacher.onboarding,
element: <TeacherOnboarding />
},
{
path: paths.student._,
element: <Students />
},
{
path: paths.students.dashboard._,
path: paths.student.dashboard._,
element: <StudentsDashboard />
},
{
Expand Down Expand Up @@ -142,23 +158,23 @@ const router = createBrowserRouter([
element: <InternalServerError />
},
{
path: paths.teacherSchool,
path: paths.teacher.dashboard.school,
element: <TeacherSchool />
},
{
path: paths.teacherClasses,
path: paths.teacher.dashboard.classes,
element: <TeacherClasses />
},
{
path: paths.teacherAccount,
path: paths.teacher.dashboard.account._,
element: <TeacherAccount />
},
{
path: paths.setup2fa,
path: paths.teacher.dashboard.account.twoFA.setup,
element: <Setup2fa />
},
{
path: paths.backupTokens,
path: paths.teacher.dashboard.account.twoFA.backupTokens,
element: <BackupTokens />
},
{
Expand Down
37 changes: 21 additions & 16 deletions frontend/src/app/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '@mui/material';

import { theme as cflTheme } from 'codeforlife';
import { getStyleOverrides } from 'codeforlife/lib/esm/helpers';

const typography: ThemeOptions['typography'] = {
h1: {
Expand Down Expand Up @@ -69,20 +70,22 @@ const components: ThemeOptions['components'] = {
color: 'tertiary'
},
styleOverrides: {
root: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiButton'),
textTransform: 'none',
color: 'black',
padding: '5px 20px',
width: 'fit-content',
'&:hover': {
backgroundColor: 'inherit'
}
}
})
}
},
MuiTabs: {
styleOverrides: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiTabs'),
...([undefined, 'horizontal'].includes(ownerState.orientation) && {
[`.${tabClasses.root}:not(:last-of-type)`]: {
marginRight: '30px'
Expand All @@ -97,6 +100,7 @@ const components: ThemeOptions['components'] = {
MuiTab: {
styleOverrides: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiTab'),
textTransform: 'none',
fontSize: typography.body2?.fontSize,
color: 'white',
Expand Down Expand Up @@ -126,17 +130,18 @@ const components: ThemeOptions['components'] = {
},
MuiInputBase: {
styleOverrides: {
root: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiInputBase'),
background: 'white',
margin: 0
}
})
}
},
MuiLink: {
styleOverrides: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiLink'),
...(ownerState.className === 'body' && {
...(cflTheme.components?.MuiLink?.styleOverrides?.root as object),
color: 'black',
textDecorationColor: 'black',
textDecoration: 'underline',
Expand All @@ -150,47 +155,47 @@ const components: ThemeOptions['components'] = {
MuiContainer: {
styleOverrides: {
root: ({ ownerState }) => ({
// @ts-expect-error root is defined in the CFL package.
...cflTheme.components?.MuiContainer?.styleOverrides?.root({ ownerState }),
...getStyleOverrides(ownerState, 'MuiContainer'),
padding: 0
})
}
},
MuiFormHelperText: {
styleOverrides: {
root: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiFormHelperText'),
...formStyleOverrides,
marginTop: 4,
marginLeft: 4
}
})
}
},
MuiCheckbox: {
styleOverrides: {
root: {
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiCheckbox'),
color: 'white'
}
})
}
},
MuiTextField: {
defaultProps: {
size: 'small'
},
styleOverrides: {
root: {
...(cflTheme.components?.MuiTextField?.styleOverrides?.root as object),
root: ({ ownerState }) => ({
...getStyleOverrides(ownerState, 'MuiTextField'),
backgroundColor: 'transparent',
'& .MuiOutlinedInput-root.Mui-focused > fieldset': {
borderColor: '#000'
}
}
})
}
},
MuiTable: {
styleOverrides: {
root: ({ ownerState }) => ({
// @ts-expect-error root is defined in the CFL package.
...cflTheme.components?.MuiTable?.styleOverrides?.root({ ownerState }),
...getStyleOverrides(ownerState, 'MuiTable'),
marginBottom: typography.body1?.marginBottom
})
}
Expand Down
45 changes: 21 additions & 24 deletions frontend/src/components/CflPasswordFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,41 @@ import {
NewPasswordField
} from 'codeforlife/lib/esm/components/form';

function isStrongPassword(
password: string,
{ forTeacher }: { forTeacher: boolean }
): boolean {
return (forTeacher)
? (password.length >= 10 &&
!(
password.search(/[A-Z]/) === -1 ||
password.search(/[a-z]/) === -1 ||
password.search(/[0-9]/) === -1 ||
password.search(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/) === -1
))
: (password.length >= 8 &&
!(
password.search(/[A-Z]/) === -1 ||
password.search(/[a-z]/) === -1 ||
password.search(/[0-9]/) === -1
));
}

export interface CflPasswordFieldsProps {
forTeacher: boolean
userType: 'teacher' | 'independent'
}

const CflPasswordFields: React.FC<CflPasswordFieldsProps> = ({
forTeacher
userType
}) => {
const [password, setPassword] = React.useState('');

// TODO: Load from central storage.
const mostUsed = ['Abcd1234', 'Password1', 'Qwerty123'];

function isStrongPassword(password: string): boolean {
return (userType === 'teacher')
? (password.length >= 10 &&
!(
password.search(/[A-Z]/) === -1 ||
password.search(/[a-z]/) === -1 ||
password.search(/[0-9]/) === -1 ||
password.search(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/) === -1
))
: (password.length >= 8 &&
!(
password.search(/[A-Z]/) === -1 ||
password.search(/[a-z]/) === -1 ||
password.search(/[0-9]/) === -1
));
}

let status: { name: string, color: string };
if (password === '') {
status = { name: 'No password!', color: '#FF0000' };
} else if (mostUsed.includes(password)) {
status = { name: 'Password too common!', color: '#DBA901' };
} else if (isStrongPassword(password, { forTeacher })) {
} else if (isStrongPassword(password)) {
status = { name: 'Strong password!', color: '#088A08' };
} else {
status = { name: 'Password too weak!', color: '#DBA901' };
Expand All @@ -68,7 +65,7 @@ const CflPasswordFields: React.FC<CflPasswordFieldsProps> = ({
'Invalid password',
(password) => {
setPassword(password);
return isStrongPassword(password, { forTeacher });
return isStrongPassword(password);
}
)
}}
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/PageBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import PageSection from './PageSection';

export interface PageBannerProps {
text: { title: string, content: string };
textAlign?: 'start' | 'center'
notification?: React.ReactElement;
img?: ImageProps;
btn?: ButtonProps;
Expand All @@ -26,6 +27,7 @@ export interface PageBannerProps {

const PageBanner: React.FC<PageBannerProps> = ({
text,
textAlign = 'start',
notification,
img,
btn,
Expand All @@ -44,14 +46,15 @@ const PageBanner: React.FC<PageBannerProps> = ({
<Stack
direction='row'
alignItems='center'
justifyContent={textAlign}
gap={2}
>
<Stack
py={{
xs: 8,
md: img !== undefined ? 0 : 10
}}
textAlign={img !== undefined ? 'start' : 'center'}
textAlign={textAlign}
>
<Typography
variant='h2'
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/components/PageTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import {

import PageSection from './PageSection';

import {
getSearchParams,
valueInOptions
} from 'codeforlife/lib/esm/helpers';
import { SearchParams } from 'codeforlife/lib/esm/helpers';

const PageTabBar: React.FC<{
title: string
Expand All @@ -20,8 +17,8 @@ const PageTabBar: React.FC<{
const theme = useTheme();

const labels = tabs.map(tab => tab.label);
const params = getSearchParams<{ tab: string }>({
tab: { validate: valueInOptions(labels) }
const params = SearchParams.get<{ tab: string }>({
tab: { validate: SearchParams.validate.inOptions(labels) }
});

const [value, setValue] = React.useState(
Expand Down
File renamed without changes.
Loading

0 comments on commit 3f9213b

Please sign in to comment.