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: added 3 tabs on teachers dashboard page #29

Merged
merged 26 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
08bf715
feat: added 3 tabs on teachers dashboard page
KamilPawel May 5, 2023
951ef56
feat: teacher dashboard
KamilPawel May 11, 2023
772e8b4
feat fixed the forms with cfltextfields
KamilPawel May 11, 2023
2808095
updated the country field
KamilPawel May 15, 2023
36f381b
remove package.json
KamilPawel May 15, 2023
b168cdc
re-locked
KamilPawel May 15, 2023
2b1af0a
resolve conflicts
KamilPawel May 16, 2023
77dc932
addressed comments
KamilPawel May 17, 2023
e1d2342
addressed comments
KamilPawel May 19, 2023
1a28a96
fix: addressing comments
KamilPawel May 22, 2023
a924398
merge main
KamilPawel May 22, 2023
c306864
merge main
KamilPawel May 22, 2023
efd8802
fix: resolving missing cfl field
KamilPawel May 23, 2023
ee41904
fix: resolving cfl field not found
KamilPawel May 23, 2023
5786550
fix: finish the comments and merge branch 'main' into teacher_dashboard
KamilPawel May 23, 2023
be9b153
header updated to h4
KamilPawel May 23, 2023
b06a52d
fix: your account header
KamilPawel May 23, 2023
86d5b9e
fix: variant deletion revert
KamilPawel May 23, 2023
d6bfd34
adressed further comments
KamilPawel May 23, 2023
e3c89d4
more comments responed
KamilPawel May 23, 2023
5cc6108
added 2FA
KamilPawel May 24, 2023
77b0bf6
merge production
KamilPawel May 24, 2023
18bb901
added the right icon
KamilPawel May 24, 2023
85ee108
added the right icon
KamilPawel May 24, 2023
5df8155
remove logic for invites
KamilPawel May 24, 2023
19ea741
Merge branch 'main' into teacher_dashboard
KamilPawel May 24, 2023
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
6 changes: 5 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
"@mui/material": "^5.11.12",
"@reduxjs/toolkit": "^1.9.3",
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v1.10.14",
"country-list": "^2.3.0",
"formik": "^2.2.9",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.2",
Expand All @@ -42,9 +44,11 @@
"devDependencies": {
"@cypress/code-coverage": "^3.10.0",
"@cypress/instrument-cra": "^1.4.0",
"@types/country-list": "^2.1.1",
"@types/node": "^17.0.45",
"@types/parcel-bundler": "^1.12.5",
"@types/react": "^18.0.28",
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"cypress": "^12.8.1",
Expand All @@ -62,4 +66,4 @@
"nyc": {
"exclude": []
}
}
}
12 changes: 12 additions & 0 deletions frontend/src/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import Newsletter from '../pages/newsletter/Newsletter';
import Forbidden from '../pages/forbidden/Forbidden';
import PageNotFound from '../pages/pageNotFound/PageNotFound';
import InternalServerError from '../pages/internalServerError/InternalServerError';
import TeacherSchool from '../pages/teacherDashboard/TeacherSchool';
import TeacherClasses from '../pages/teacherDashboard/TeacherClasses';
import TeacherAccount from '../pages/teacherDashboard/TeacherAccount';
import EmailVerification from '../pages/emailVerification/EmailVerification';
import ResetPassword from '../pages/resetPassword/ResetPassword';
import StudentsDashboard from '../pages/studentsDashboard/StudentsDashboard';
Expand Down Expand Up @@ -55,6 +58,9 @@ 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',
kurono: '/kurono'
};

Expand Down Expand Up @@ -123,6 +129,12 @@ const router = createBrowserRouter([
path: paths.internalServerError,
element: <InternalServerError />
},
{
path: paths.teacherSchool,
element: <TeacherSchool />
},
{ path: paths.teacherClasses, element: <TeacherClasses /> },
{ path: paths.teacherAccount, element: <TeacherAccount /> },
{
path: paths.emailVerification,
element: <EmailVerification />
Expand Down
95 changes: 95 additions & 0 deletions frontend/src/components/CflTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react';
import { styled } from '@mui/material/styles';
import {
TableCell,
TableRow,
TableContainer,
Table,
TableHead,
TableBody,
Stack,
StackProps
} from '@mui/material';
import { tableCellClasses } from '@mui/material/TableCell';

export const TableCellElementStyled = styled(TableCell)(({ theme }) => ({
outline: `1px solid ${theme.palette.common.white}`,
[`&.${tableCellClasses.head}`]: {
background: theme.palette.info.dark,
color: theme.palette.common.white
}
}));

export interface CflTableCellProps {
children: React.ReactNode;
alignItems?: StackProps['alignItems'];
justifyContent?: StackProps['justifyContent'];
direction?: StackProps['direction'];
}
export const CflTableCellElement: React.FC<CflTableCellProps> = ({
children,
alignItems = 'center',
justifyContent = 'flex-start',
direction = 'row'
}) => {
return (
<TableCellElementStyled>
<Stack
alignItems={alignItems}
justifyContent={justifyContent}
direction={direction}
columnGap={3}
>
{children}
</Stack>
</TableCellElementStyled>
);
};

export const TableRowStyled = styled(TableRow)(({ theme }) => ({
backgroundColor: theme.palette.action.hover,
// hide last border
'&:last-child td, &:last-child th': {
border: 0
}
}));

export const CflTableBody: React.FC<{
children: React.ReactNode;
}> = ({ children }): JSX.Element => {
return (
<TableRowStyled>
{React.Children.map(children, (child) => (
<>{child}</>
))}
</TableRowStyled>
);
};

interface CflTableProps {
titles: string[];
children: React.ReactNode;
}
const CflTable: React.FC<CflTableProps> = ({
titles,
children
}): JSX.Element => {
return (
<TableContainer>
<Table>
<TableHead>
<TableRowStyled>
{titles.map((title) => (
<CflTableCellElement key={`table-title-${title}`}>
{title}
</CflTableCellElement>
))}
</TableRowStyled>
</TableHead>
<TableBody>{children}</TableBody>
</Table>
</TableContainer>
);
};

export default CflTable;
35 changes: 35 additions & 0 deletions frontend/src/components/CopyToClipboardIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ContentCopy } from '@mui/icons-material';
import React from 'react';
import { styled } from '@mui/material/styles';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { Tooltip } from '@mui/material';

const CopyContentIconStyled = styled(ContentCopy)(({ theme }) => ({
color: theme.palette.info.dark,
transition: `${theme.transitions.duration.standard}ms`,
cursor: 'pointer',
'&:hover': {
color: theme.palette.common.black
}
}));

const CopyToClipboardIcon: React.FC<{
accessCode: string;
}> = ({ accessCode }) => {
const [copiedMessage, setCopiedMessage] = React.useState('Copy to clipboard');
const handleCopy: () => void = () => {
setCopiedMessage('Copied to clipboard!');
};
const resetMessage: () => void = () => {
setCopiedMessage('Copy to clipboard');
};
return (
<CopyToClipboard text={accessCode} onCopy={handleCopy}>
<Tooltip title={copiedMessage} placement="bottom">
<CopyContentIconStyled onMouseEnter={resetMessage} />
</Tooltip>
</CopyToClipboard>
);
};

export default CopyToClipboardIcon;
88 changes: 88 additions & 0 deletions frontend/src/components/formik/CflForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import {
Grid,
Stack,
StackProps,
Typography,
GridProps,
ButtonProps
} from '@mui/material';
import { Formik, FormikValues, FormikConfig, FormikProps, Form } from 'formik';

export interface CflHorizontalFormProps<Values> extends FormikConfig<Values> {
header?: string;
subheader?: string;
subheaderBold?: string;
children?: JSX.Element[];
gridProps?: GridProps;
submitButton: React.ReactElement<ButtonProps>;
}

export const CflHorizontalForm = <Values extends FormikValues = FormikValues>({
children,
gridProps = { container: true, columnSpacing: 3 },
header,
subheader,
subheaderBold,
submitButton,
...formikProps
}: CflHorizontalFormProps<Values>): JSX.Element => {
return (
<Formik {...formikProps}>
{(formik) => (
<React.Fragment>
{header && (
<Typography variant="h5" sx={{ mb: 2 }}>
{header}
</Typography>
)}
{subheader && <Typography>{subheader}</Typography>}
{subheaderBold && (
<Typography fontWeight="bold">{subheaderBold}</Typography>
)}
<Form>
<Grid {...gridProps}>
{React.Children.map(children, (child, index) => {
// Allow last child components such as checkboxes to take up the full width
const isLastChild = children && index === children?.length - 1;
return (
<Grid xs={12} sm={isLastChild ? true : 4} item>
{child}
</Grid>
);
})}
<Grid item xs={12}>
{React.cloneElement(submitButton, {
disabled: !(formik.isValid && formik.dirty)
})}
</Grid>
</Grid>
</Form>
</React.Fragment>
)}
</Formik>
);
};

export interface CflFormProps<Values> extends FormikConfig<Values> {
children: (formik: FormikProps<Values>) => React.ReactNode;
stackProps?: StackProps;
}

const CflForm = <Values extends FormikValues = FormikValues>({
children,
stackProps = { gap: 1 },
...formikProps
}: CflFormProps<Values>): JSX.Element => {
return (
<Formik {...formikProps}>
{(formik) => (
<Form>
<Stack {...stackProps}>{children(formik)}</Stack>
</Form>
)}
</Formik>
);
};

export default CflForm;
10 changes: 6 additions & 4 deletions frontend/src/pages/emailVerification/EmailVerification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const EmailVerification: React.FC = () => {
return (
<BasePage>
<PageSection maxWidth="md" className="flex-center">
{params.success
? <Status
{params.success ? (
<Status
userType={params.userType}
header="We need to verify your email address"
body={[
Expand All @@ -62,7 +62,8 @@ const EmailVerification: React.FC = () => {
src: PaperPlaneImg
}}
/>
: <Status
) : (
<Status
userType={params.userType}
header="Your email address verification failed"
body={[
Expand All @@ -73,7 +74,8 @@ const EmailVerification: React.FC = () => {
alt: 'SadFace',
src: SadFaceImg
}}
/>}
/>
)}
</PageSection>
</BasePage>
);
Expand Down
Loading