codeforlife 2.8.3 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Countdown-DFI1RljW.js +28 -0
- package/dist/Countdown-DFI1RljW.js.map +1 -0
- package/dist/Countdown-zY3nMzmi.cjs +2 -0
- package/dist/Countdown-zY3nMzmi.cjs.map +1 -0
- package/dist/Image-D5jC9UoX.js +21 -0
- package/dist/Image-D5jC9UoX.js.map +1 -0
- package/dist/Image-mgT45r_B.cjs +2 -0
- package/dist/Image-mgT45r_B.cjs.map +1 -0
- package/dist/LinkButton-BYFkvL_O.cjs +2 -0
- package/dist/LinkButton-BYFkvL_O.cjs.map +1 -0
- package/dist/LinkButton-oK0RThqn.js +12 -0
- package/dist/LinkButton-oK0RThqn.js.map +1 -0
- package/dist/Navigate-Dq47aqC8.js +25 -0
- package/dist/Navigate-Dq47aqC8.js.map +1 -0
- package/dist/Navigate-dQocLhzN.cjs +2 -0
- package/dist/Navigate-dQocLhzN.cjs.map +1 -0
- package/dist/api/endpoints/index.cjs.js +2 -0
- package/dist/api/endpoints/index.cjs.js.map +1 -0
- package/dist/api/endpoints/index.d.ts +81 -0
- package/dist/api/endpoints/index.es.js +78 -0
- package/dist/api/endpoints/index.es.js.map +1 -0
- package/dist/api/index.cjs.js +4 -0
- package/dist/api/index.cjs.js.map +1 -0
- package/dist/api/index.d.ts +77 -0
- package/dist/api/index.es.js +541 -0
- package/dist/api/index.es.js.map +1 -0
- package/dist/api-Cbyt3rw0.js +92 -0
- package/dist/api-Cbyt3rw0.js.map +1 -0
- package/dist/api-CnMfjRk3.cjs +2 -0
- package/dist/api-CnMfjRk3.cjs.map +1 -0
- package/dist/api-Cs4Y-WeI.js +20 -0
- package/dist/api-Cs4Y-WeI.js.map +1 -0
- package/dist/api-DIgp_6Vr.cjs +2 -0
- package/dist/api-DIgp_6Vr.cjs.map +1 -0
- package/dist/api.d.ts +123 -0
- package/dist/auth-BPfUPjmM.js +237 -0
- package/dist/auth-BPfUPjmM.js.map +1 -0
- package/dist/auth-Vf1MgMci.cjs +2 -0
- package/dist/auth-Vf1MgMci.cjs.map +1 -0
- package/dist/auth.d.ts +40 -0
- package/dist/components/form/index.cjs.js +2 -0
- package/dist/components/form/index.cjs.js.map +1 -0
- package/dist/components/form/index.d.ts +86 -0
- package/dist/components/form/index.es.js +18 -0
- package/dist/components/form/index.es.js.map +1 -0
- package/dist/components/index.cjs.js +11 -0
- package/dist/components/index.cjs.js.map +1 -0
- package/dist/components/index.d.ts +90 -0
- package/dist/components/index.es.js +383 -0
- package/dist/components/index.es.js.map +1 -0
- package/dist/components/page/index.cjs.js +2 -0
- package/dist/components/page/index.cjs.js.map +1 -0
- package/dist/components/page/index.d.ts +77 -0
- package/dist/components/page/index.es.js +9 -0
- package/dist/components/page/index.es.js.map +1 -0
- package/dist/components/router/index.cjs.js +2 -0
- package/dist/components/router/index.cjs.js.map +1 -0
- package/dist/components/router/index.d.ts +78 -0
- package/dist/components/router/index.es.js +11 -0
- package/dist/components/router/index.es.js.map +1 -0
- package/dist/components/table/index.cjs.js +2 -0
- package/dist/components/table/index.cjs.js.map +1 -0
- package/dist/components/table/index.d.ts +75 -0
- package/dist/components/table/index.es.js +9 -0
- package/dist/components/table/index.es.js.map +1 -0
- package/dist/en-gb-B_rK7Jx1.js +20 -0
- package/dist/en-gb-B_rK7Jx1.js.map +1 -0
- package/dist/en-gb-CpyEkKq3.cjs +2 -0
- package/dist/en-gb-CpyEkKq3.cjs.map +1 -0
- package/dist/features/index.cjs.js +2 -0
- package/dist/features/index.cjs.js.map +1 -0
- package/dist/features/index.d.ts +76 -0
- package/dist/features/index.es.js +47 -0
- package/dist/features/index.es.js.map +1 -0
- package/dist/form.d.ts +40 -0
- package/dist/general-BPbbmkeX.cjs +2 -0
- package/dist/general-BPbbmkeX.cjs.map +1 -0
- package/dist/general-CtTJPCJn.js +58 -0
- package/dist/general-CtTJPCJn.js.map +1 -0
- package/dist/general.d.ts +53 -0
- package/dist/hooks/index.cjs.js +2 -0
- package/dist/hooks/index.cjs.js.map +1 -0
- package/dist/hooks/index.d.ts +77 -0
- package/dist/hooks/index.es.js +25 -0
- package/dist/hooks/index.es.js.map +1 -0
- package/dist/index-2W--_sNE.js +30 -0
- package/dist/index-2W--_sNE.js.map +1 -0
- package/dist/index-BUMdUVBH.cjs +5 -0
- package/dist/index-BUMdUVBH.cjs.map +1 -0
- package/dist/index-B_Zy_zwA.cjs +2 -0
- package/dist/index-B_Zy_zwA.cjs.map +1 -0
- package/dist/index-BgsynEGX.cjs +2 -0
- package/dist/index-BgsynEGX.cjs.map +1 -0
- package/dist/index-CA-ugBSa.cjs +2 -0
- package/dist/index-CA-ugBSa.cjs.map +1 -0
- package/dist/index-CNtOlJ49.js +572 -0
- package/dist/index-CNtOlJ49.js.map +1 -0
- package/dist/index-DkM_cG3a.js +237 -0
- package/dist/index-DkM_cG3a.js.map +1 -0
- package/dist/index-Dqp7dpn3.js +1111 -0
- package/dist/index-Dqp7dpn3.js.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.es.js +7 -0
- package/dist/index.es.js.map +1 -0
- package/dist/jsx-runtime-CeSfJrVB.cjs +31 -0
- package/dist/jsx-runtime-CeSfJrVB.cjs.map +1 -0
- package/dist/jsx-runtime-Dpn_P65e.js +634 -0
- package/dist/jsx-runtime-Dpn_P65e.js.map +1 -0
- package/dist/middlewares/index.cjs.js +2 -0
- package/dist/middlewares/index.cjs.js.map +1 -0
- package/dist/middlewares/index.d.ts +73 -0
- package/dist/middlewares/index.es.js +10 -0
- package/dist/middlewares/index.es.js.map +1 -0
- package/dist/palette-CE2mKYse.cjs +2 -0
- package/dist/palette-CE2mKYse.cjs.map +1 -0
- package/dist/palette-C_L0akN_.js +43 -0
- package/dist/palette-C_L0akN_.js.map +1 -0
- package/dist/router.d.ts +48 -0
- package/dist/rtk-query.modern-CjetfYPg.js +3038 -0
- package/dist/rtk-query.modern-CjetfYPg.js.map +1 -0
- package/dist/rtk-query.modern-PBCErCqb.cjs +15 -0
- package/dist/rtk-query.modern-PBCErCqb.cjs.map +1 -0
- package/dist/schema.d.ts +89 -0
- package/dist/schemas-BZbJpkD5.cjs +2 -0
- package/dist/schemas-BZbJpkD5.cjs.map +1 -0
- package/dist/schemas-DlOtf2vf.js +162 -0
- package/dist/schemas-DlOtf2vf.js.map +1 -0
- package/dist/server.cjs.js +6 -0
- package/dist/server.cjs.js.map +1 -0
- package/dist/server.d.ts +129 -0
- package/dist/server.es.js +127 -0
- package/dist/server.es.js.map +1 -0
- package/dist/session-CE2U7oL1.cjs +2 -0
- package/dist/session-CE2U7oL1.cjs.map +1 -0
- package/dist/session-CacrgFSv.cjs +2 -0
- package/dist/session-CacrgFSv.cjs.map +1 -0
- package/dist/session-D312kYKk.js +32 -0
- package/dist/session-D312kYKk.js.map +1 -0
- package/dist/session-oI-Ht2C8.js +30 -0
- package/dist/session-oI-Ht2C8.js.map +1 -0
- package/dist/settings/index.cjs.js +2 -0
- package/dist/settings/index.cjs.js.map +1 -0
- package/dist/settings/index.d.ts +76 -0
- package/dist/settings/index.es.js +17 -0
- package/dist/settings/index.es.js.map +1 -0
- package/dist/slices/index.cjs.js +2 -0
- package/dist/slices/index.cjs.js.map +1 -0
- package/dist/slices/index.d.ts +74 -0
- package/dist/slices/index.es.js +6 -0
- package/dist/slices/index.es.js.map +1 -0
- package/dist/store.d.ts +17 -0
- package/dist/style.css +1 -0
- package/dist/test.d.ts +75 -0
- package/dist/theme/components/index.cjs.js +2 -0
- package/dist/theme/components/index.cjs.js.map +1 -0
- package/dist/theme/components/index.d.ts +75 -0
- package/dist/theme/components/index.es.js +6 -0
- package/dist/theme/components/index.es.js.map +1 -0
- package/dist/theme/index.cjs.js +2 -0
- package/dist/theme/index.cjs.js.map +1 -0
- package/dist/theme/index.d.ts +79 -0
- package/dist/theme/index.es.js +222 -0
- package/dist/theme/index.es.js.map +1 -0
- package/dist/theme.d.ts +19 -0
- package/dist/urls-DtHr1d3H.js +14 -0
- package/dist/urls-DtHr1d3H.js.map +1 -0
- package/dist/urls-MaVXL_C2.cjs +2 -0
- package/dist/urls-MaVXL_C2.cjs.map +1 -0
- package/dist/utils/api.cjs.js +2 -0
- package/dist/utils/api.cjs.js.map +1 -0
- package/dist/utils/api.d.ts +144 -0
- package/dist/utils/api.es.js +16 -0
- package/dist/utils/api.es.js.map +1 -0
- package/dist/utils/auth.cjs.js +2 -0
- package/dist/utils/auth.cjs.js.map +1 -0
- package/dist/utils/auth.d.ts +100 -0
- package/dist/utils/auth.es.js +117 -0
- package/dist/utils/auth.es.js.map +1 -0
- package/dist/utils/form.cjs.js +2 -0
- package/dist/utils/form.cjs.js.map +1 -0
- package/dist/utils/form.d.ts +97 -0
- package/dist/utils/form.es.js +76 -0
- package/dist/utils/form.es.js.map +1 -0
- package/dist/utils/general.cjs.js +2 -0
- package/dist/utils/general.cjs.js.map +1 -0
- package/dist/utils/general.d.ts +102 -0
- package/{src/utils/general.ts → dist/utils/general.es.js} +87 -165
- package/dist/utils/general.es.js.map +1 -0
- package/dist/utils/router.cjs.js +2 -0
- package/dist/utils/router.cjs.js.map +1 -0
- package/dist/utils/router.d.ts +91 -0
- package/dist/utils/router.es.js +33 -0
- package/dist/utils/router.es.js.map +1 -0
- package/dist/utils/schema.cjs.js +2 -0
- package/dist/utils/schema.cjs.js.map +1 -0
- package/dist/utils/schema.d.ts +115 -0
- package/dist/utils/schema.es.js +123 -0
- package/dist/utils/schema.es.js.map +1 -0
- package/dist/utils/store.cjs.js +2 -0
- package/dist/utils/store.cjs.js.map +1 -0
- package/dist/utils/store.d.ts +82 -0
- package/dist/utils/store.es.js +20 -0
- package/dist/utils/store.es.js.map +1 -0
- package/dist/utils/test.cjs.js +2 -0
- package/dist/utils/test.cjs.js.map +1 -0
- package/dist/utils/test.d.ts +125 -0
- package/dist/utils/test.es.js +60 -0
- package/dist/utils/test.es.js.map +1 -0
- package/dist/utils/theme.cjs.js +2 -0
- package/dist/utils/theme.cjs.js.map +1 -0
- package/dist/utils/theme.d.ts +83 -0
- package/dist/utils/theme.es.js +12 -0
- package/dist/utils/theme.es.js.map +1 -0
- package/dist/utils/window.cjs.js +2 -0
- package/dist/utils/window.cjs.js.map +1 -0
- package/dist/utils/window.d.ts +74 -0
- package/dist/utils/window.es.js +11 -0
- package/dist/utils/window.es.js.map +1 -0
- package/dist/window.d.ts +5 -0
- package/package.json +142 -37
- package/.github/workflows/main.yml +0 -55
- package/.prettierignore +0 -1
- package/CHANGELOG.md +0 -2027
- package/CONTRIBUTING.md +0 -3
- package/eslint.config.js +0 -17
- package/src/api/createApi.ts +0 -91
- package/src/api/endpoints/authFactor.ts +0 -31
- package/src/api/endpoints/index.ts +0 -9
- package/src/api/endpoints/klass.ts +0 -87
- package/src/api/endpoints/school.ts +0 -34
- package/src/api/endpoints/session.ts +0 -47
- package/src/api/endpoints/user.ts +0 -70
- package/src/api/index.ts +0 -5
- package/src/api/models.ts +0 -145
- package/src/api/schemas.ts +0 -243
- package/src/api/tagTypes.ts +0 -12
- package/src/api/urls.ts +0 -13
- package/src/components/App.css +0 -38
- package/src/components/App.tsx +0 -152
- package/src/components/ClickableTooltip.tsx +0 -43
- package/src/components/CopyIconButton.test.tsx +0 -16
- package/src/components/CopyIconButton.tsx +0 -27
- package/src/components/Countdown.tsx +0 -42
- package/src/components/DownloadFileButton.tsx +0 -55
- package/src/components/ElevatedAppBar.tsx +0 -41
- package/src/components/Image.tsx +0 -41
- package/src/components/InputFileButton.tsx +0 -27
- package/src/components/ItemizedList.tsx +0 -63
- package/src/components/OrderedGrid.tsx +0 -92
- package/src/components/ScrollIntoViewLink.tsx +0 -22
- package/src/components/SyncError.tsx +0 -14
- package/src/components/TablePagination.tsx +0 -142
- package/src/components/YouTubeVideo.tsx +0 -26
- package/src/components/form/ApiAutocompleteField.tsx +0 -187
- package/src/components/form/AutocompleteField.tsx +0 -135
- package/src/components/form/CheckboxField.tsx +0 -86
- package/src/components/form/CountryField.tsx +0 -75
- package/src/components/form/DatePickerField.tsx +0 -126
- package/src/components/form/EmailField.tsx +0 -38
- package/src/components/form/FirstNameField.tsx +0 -40
- package/src/components/form/Form.tsx +0 -165
- package/src/components/form/OtpField.tsx +0 -28
- package/src/components/form/PasswordField.tsx +0 -71
- package/src/components/form/RepeatField.tsx +0 -123
- package/src/components/form/SubmitButton.tsx +0 -57
- package/src/components/form/TextField.tsx +0 -150
- package/src/components/form/UkCountyField.tsx +0 -68
- package/src/components/form/index.tsx +0 -35
- package/src/components/index.ts +0 -28
- package/src/components/page/Banner.tsx +0 -95
- package/src/components/page/Notification.tsx +0 -71
- package/src/components/page/Page.tsx +0 -73
- package/src/components/page/Section.tsx +0 -21
- package/src/components/page/TabBar.tsx +0 -131
- package/src/components/page/index.ts +0 -10
- package/src/components/router/Link.tsx +0 -23
- package/src/components/router/LinkButton.tsx +0 -22
- package/src/components/router/LinkIconButton.tsx +0 -22
- package/src/components/router/LinkListItem.tsx +0 -22
- package/src/components/router/LinkTab.tsx +0 -22
- package/src/components/router/Navigate.tsx +0 -33
- package/src/components/router/index.tsx +0 -9
- package/src/components/table/CellStack.tsx +0 -19
- package/src/components/table/Table.tsx +0 -55
- package/src/components/table/index.tsx +0 -8
- package/src/features/InactiveDialog.tsx +0 -40
- package/src/features/ScreenTimeDialog.tsx +0 -30
- package/src/features/index.ts +0 -4
- package/src/fonts/ttf/Inter-VariableFont_slnt,wght.ttf +0 -0
- package/src/fonts/ttf/SpaceGrotesk-VariableFont_wght.ttf +0 -0
- package/src/hooks/api.tsx +0 -39
- package/src/hooks/auth.tsx +0 -397
- package/src/hooks/form.tsx +0 -11
- package/src/hooks/general.tsx +0 -110
- package/src/hooks/index.ts +0 -5
- package/src/hooks/router.tsx +0 -168
- package/src/images/svg/brain.svg +0 -1
- package/src/index.ts +0 -2
- package/src/middlewares/index.ts +0 -1
- package/src/middlewares/session.ts +0 -21
- package/src/scripts/freshDesk.js +0 -473
- package/src/scripts/index.ts +0 -1
- package/src/server.js +0 -187
- package/src/settings/custom.ts +0 -22
- package/src/settings/index.ts +0 -7
- package/src/settings/vite.ts +0 -26
- package/src/setupTests.ts +0 -2
- package/src/slices/createSlice.ts +0 -8
- package/src/slices/index.ts +0 -2
- package/src/slices/session.ts +0 -32
- package/src/theme/ThemedBox.tsx +0 -265
- package/src/theme/colors.ts +0 -57
- package/src/theme/components/MuiAccordion.tsx +0 -13
- package/src/theme/components/MuiAutocomplete.tsx +0 -11
- package/src/theme/components/MuiButton.ts +0 -70
- package/src/theme/components/MuiCardActions.tsx +0 -12
- package/src/theme/components/MuiCheckbox.ts +0 -12
- package/src/theme/components/MuiContainer.ts +0 -19
- package/src/theme/components/MuiDialog.tsx +0 -16
- package/src/theme/components/MuiFormControlLabel.ts +0 -18
- package/src/theme/components/MuiFormHelperText.ts +0 -12
- package/src/theme/components/MuiGrid2.ts +0 -16
- package/src/theme/components/MuiInputBase.ts +0 -14
- package/src/theme/components/MuiLink.ts +0 -41
- package/src/theme/components/MuiList.ts +0 -12
- package/src/theme/components/MuiListItemText.ts +0 -18
- package/src/theme/components/MuiMenu.ts +0 -14
- package/src/theme/components/MuiMenuItem.ts +0 -15
- package/src/theme/components/MuiSelect.ts +0 -16
- package/src/theme/components/MuiTab.ts +0 -29
- package/src/theme/components/MuiTable.ts +0 -29
- package/src/theme/components/MuiTableBody.ts +0 -15
- package/src/theme/components/MuiTableHead.ts +0 -26
- package/src/theme/components/MuiTabs.ts +0 -26
- package/src/theme/components/MuiTextField.ts +0 -86
- package/src/theme/components/MuiToolbar.ts +0 -11
- package/src/theme/components/MuiTypography.ts +0 -12
- package/src/theme/components/_components.ts +0 -95
- package/src/theme/components/index.ts +0 -57
- package/src/theme/index.ts +0 -25
- package/src/theme/palette.ts +0 -98
- package/src/theme/spacing.ts +0 -8
- package/src/theme/typography.ts +0 -101
- package/src/utils/api.test.ts +0 -19
- package/src/utils/api.tsx +0 -339
- package/src/utils/auth.ts +0 -78
- package/src/utils/form.test.ts +0 -50
- package/src/utils/form.ts +0 -193
- package/src/utils/general.test.ts +0 -55
- package/src/utils/router.test.ts +0 -156
- package/src/utils/router.ts +0 -67
- package/src/utils/schema.ts +0 -290
- package/src/utils/store.ts +0 -31
- package/src/utils/test.tsx +0 -82
- package/src/utils/theme.tsx +0 -83
- package/src/utils/window.ts +0 -11
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.app.json +0 -4
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -4
- package/types/fixes.d.ts +0 -18
- package/vite.config.ts +0 -23
package/src/api/schemas.ts
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import * as yup from "yup"
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
AdminSchoolTeacher,
|
|
5
|
-
AdminSchoolTeacherUser,
|
|
6
|
-
AuthFactor,
|
|
7
|
-
Class,
|
|
8
|
-
IndependentUser,
|
|
9
|
-
NonAdminSchoolTeacher,
|
|
10
|
-
NonAdminSchoolTeacherUser,
|
|
11
|
-
NonSchoolTeacher,
|
|
12
|
-
NonSchoolTeacherUser,
|
|
13
|
-
OtpBypassToken,
|
|
14
|
-
School,
|
|
15
|
-
SchoolTeacher,
|
|
16
|
-
SchoolTeacherUser,
|
|
17
|
-
Student,
|
|
18
|
-
StudentUser,
|
|
19
|
-
Teacher,
|
|
20
|
-
TeacherUser,
|
|
21
|
-
User,
|
|
22
|
-
} from "./models"
|
|
23
|
-
import { COUNTRY_ISO_CODES, UK_COUNTIES } from "../utils/general"
|
|
24
|
-
import {
|
|
25
|
-
lowercaseAsciiAlphanumericString,
|
|
26
|
-
numericId,
|
|
27
|
-
unicodeAlphanumericString,
|
|
28
|
-
uppercaseAsciiAlphanumericString,
|
|
29
|
-
} from "../utils/schema"
|
|
30
|
-
import { type Schemas } from "../utils/api"
|
|
31
|
-
|
|
32
|
-
// NOTE: do not use .required() here.
|
|
33
|
-
const id = {
|
|
34
|
-
user: numericId(),
|
|
35
|
-
teacher: numericId(),
|
|
36
|
-
student: numericId(),
|
|
37
|
-
school: numericId(),
|
|
38
|
-
klass: uppercaseAsciiAlphanumericString().length(5),
|
|
39
|
-
authFactor: numericId(),
|
|
40
|
-
otpBypassToken: numericId(),
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// -----------------------------------------------------------------------------
|
|
44
|
-
// User Schemas
|
|
45
|
-
// -----------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
const _userTeacher: Omit<Schemas<Teacher>, "user"> = {
|
|
48
|
-
id: id.teacher.required(),
|
|
49
|
-
school: id.school,
|
|
50
|
-
is_admin: yup.bool().required(),
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const _userStudent: Omit<Schemas<Student>, "user"> = {
|
|
54
|
-
id: id.student.required(),
|
|
55
|
-
school: id.school.required(),
|
|
56
|
-
klass: id.klass.required(),
|
|
57
|
-
auto_gen_password: yup.string().required(),
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const user: Schemas<User> = {
|
|
61
|
-
id: id.user.required(),
|
|
62
|
-
requesting_to_join_class: id.klass,
|
|
63
|
-
first_name: unicodeAlphanumericString({
|
|
64
|
-
spaces: true,
|
|
65
|
-
specialChars: "-'",
|
|
66
|
-
})
|
|
67
|
-
.required()
|
|
68
|
-
.max(150),
|
|
69
|
-
last_name: unicodeAlphanumericString({
|
|
70
|
-
spaces: true,
|
|
71
|
-
specialChars: "-'",
|
|
72
|
-
}).max(150),
|
|
73
|
-
last_login: yup.date(),
|
|
74
|
-
email: yup.string().email(),
|
|
75
|
-
password: yup.string().required(),
|
|
76
|
-
is_staff: yup.bool().required(),
|
|
77
|
-
is_active: yup.bool().required(),
|
|
78
|
-
date_joined: yup.date().required(),
|
|
79
|
-
teacher: yup.object(_userTeacher).optional(),
|
|
80
|
-
student: yup.object(_userStudent).optional(),
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const teacherUser: Schemas<TeacherUser> = {
|
|
84
|
-
...user,
|
|
85
|
-
password: user.password
|
|
86
|
-
.min(10, "must be at least 10 characters long")
|
|
87
|
-
.matches(/[A-Z]/, "must contain at least one uppercase letter")
|
|
88
|
-
.matches(/[a-z]/, "must contain at least one lowercase letter")
|
|
89
|
-
.matches(/[0-9]/, "must contain at least one digit")
|
|
90
|
-
.matches(
|
|
91
|
-
/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/,
|
|
92
|
-
"must contain at least one special character",
|
|
93
|
-
),
|
|
94
|
-
email: user.email.required(),
|
|
95
|
-
last_name: user.last_name.required(),
|
|
96
|
-
teacher: user.teacher.required(),
|
|
97
|
-
student: yup.string().oneOf([undefined]),
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const _userSchoolTeacher: Omit<Schemas<SchoolTeacher>, "user"> = {
|
|
101
|
-
..._userTeacher,
|
|
102
|
-
school: _userTeacher.school.required(),
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export const schoolTeacherUser: Schemas<SchoolTeacherUser> = {
|
|
106
|
-
...teacherUser,
|
|
107
|
-
teacher: yup.object(_userSchoolTeacher),
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const _userAdminSchoolTeacher: Omit<Schemas<AdminSchoolTeacher>, "user"> = {
|
|
111
|
-
..._userSchoolTeacher,
|
|
112
|
-
is_admin: _userSchoolTeacher.is_admin.isTrue(),
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export const adminSchoolTeacherUser: Schemas<AdminSchoolTeacherUser> = {
|
|
116
|
-
...schoolTeacherUser,
|
|
117
|
-
teacher: yup.object(_userAdminSchoolTeacher),
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const _userNonAdminSchoolTeacher: Omit<
|
|
121
|
-
Schemas<NonAdminSchoolTeacher>,
|
|
122
|
-
"user"
|
|
123
|
-
> = {
|
|
124
|
-
..._userSchoolTeacher,
|
|
125
|
-
is_admin: _userSchoolTeacher.is_admin.isFalse(),
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export const nonAdminSchoolTeacherUser: Schemas<NonAdminSchoolTeacherUser> = {
|
|
129
|
-
...schoolTeacherUser,
|
|
130
|
-
teacher: yup.object(_userNonAdminSchoolTeacher),
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const _userNonSchoolTeacher: Omit<Schemas<NonSchoolTeacher>, "user"> = {
|
|
134
|
-
..._userTeacher,
|
|
135
|
-
school: yup.string().oneOf([undefined]),
|
|
136
|
-
is_admin: _userTeacher.is_admin.isFalse(),
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export const nonSchoolTeacherUser: Schemas<NonSchoolTeacherUser> = {
|
|
140
|
-
...teacherUser,
|
|
141
|
-
teacher: yup.object(_userNonSchoolTeacher),
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const studentUser: Schemas<StudentUser> = {
|
|
145
|
-
...user,
|
|
146
|
-
password: user.password.min(6, "must be at least 6 characters long"),
|
|
147
|
-
email: user.email.oneOf([undefined]),
|
|
148
|
-
last_name: user.last_name.oneOf([undefined]),
|
|
149
|
-
teacher: yup.string().oneOf([undefined]),
|
|
150
|
-
student: user.student.required(),
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export const indyUser: Schemas<IndependentUser> = {
|
|
154
|
-
...user,
|
|
155
|
-
password: user.password
|
|
156
|
-
.min(8, "must be at least 8 characters long")
|
|
157
|
-
.matches(/[A-Z]/, "must contain at least one uppercase letter")
|
|
158
|
-
.matches(/[a-z]/, "must contain at least one lowercase letter")
|
|
159
|
-
.matches(/[0-9]/, "must contain at least one digit"),
|
|
160
|
-
email: user.email.required(),
|
|
161
|
-
last_name: user.last_name.required(),
|
|
162
|
-
teacher: yup.string().oneOf([undefined]),
|
|
163
|
-
student: yup.string().oneOf([undefined]),
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// -----------------------------------------------------------------------------
|
|
167
|
-
// Teacher Schemas
|
|
168
|
-
// -----------------------------------------------------------------------------
|
|
169
|
-
|
|
170
|
-
export const teacher: Schemas<Teacher> = {
|
|
171
|
-
..._userTeacher,
|
|
172
|
-
user: id.user.required(),
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export const schoolTeacher: Schemas<SchoolTeacher> = {
|
|
176
|
-
..._userSchoolTeacher,
|
|
177
|
-
user: id.user.required(),
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export const adminSchoolTeacher: Schemas<AdminSchoolTeacher> = {
|
|
181
|
-
..._userAdminSchoolTeacher,
|
|
182
|
-
user: id.user.required(),
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export const nonAdminSchoolTeacher: Schemas<NonAdminSchoolTeacher> = {
|
|
186
|
-
..._userNonAdminSchoolTeacher,
|
|
187
|
-
user: id.user.required(),
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export const nonSchoolTeacher: Schemas<NonSchoolTeacher> = {
|
|
191
|
-
..._userNonSchoolTeacher,
|
|
192
|
-
user: id.user.required(),
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// -----------------------------------------------------------------------------
|
|
196
|
-
// Other Schemas
|
|
197
|
-
// -----------------------------------------------------------------------------
|
|
198
|
-
|
|
199
|
-
export const student: Schemas<Student> = {
|
|
200
|
-
..._userStudent,
|
|
201
|
-
user: id.user.required(),
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export const school: Schemas<School> = {
|
|
205
|
-
id: id.school.required(),
|
|
206
|
-
name: unicodeAlphanumericString({
|
|
207
|
-
spaces: true,
|
|
208
|
-
specialChars: "'.",
|
|
209
|
-
})
|
|
210
|
-
.required()
|
|
211
|
-
.max(200),
|
|
212
|
-
country: yup.string().oneOf(COUNTRY_ISO_CODES),
|
|
213
|
-
uk_county: yup.string().oneOf(UK_COUNTIES),
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export const klass: Schemas<Class> = {
|
|
217
|
-
id: id.klass.required(),
|
|
218
|
-
teacher: id.teacher.required(),
|
|
219
|
-
school: id.school.required(),
|
|
220
|
-
name: unicodeAlphanumericString({
|
|
221
|
-
spaces: true,
|
|
222
|
-
specialChars: "-_",
|
|
223
|
-
})
|
|
224
|
-
.required()
|
|
225
|
-
.max(200),
|
|
226
|
-
read_classmates_data: yup.bool().required(),
|
|
227
|
-
receive_requests_until: yup.date(),
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export const authFactor: Schemas<AuthFactor> = {
|
|
231
|
-
id: id.authFactor.required(),
|
|
232
|
-
user: id.user.required(),
|
|
233
|
-
type: yup
|
|
234
|
-
.string()
|
|
235
|
-
.oneOf(["otp"] as const)
|
|
236
|
-
.required(),
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export const otpBypassToken: Schemas<OtpBypassToken> = {
|
|
240
|
-
id: id.otpBypassToken.required(),
|
|
241
|
-
user: id.user.required(),
|
|
242
|
-
token: lowercaseAsciiAlphanumericString().required().length(8),
|
|
243
|
-
}
|
package/src/api/tagTypes.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const tagTypes = [
|
|
2
|
-
// These are the tags for the common models used throughout our system.
|
|
3
|
-
// https://github.com/ocadotechnology/codeforlife-package-python/tree/main/codeforlife/user/models
|
|
4
|
-
// NOTE: Don't use the "Teacher" and "Student" tags. Use "User" instead.
|
|
5
|
-
"User",
|
|
6
|
-
"School",
|
|
7
|
-
"Class",
|
|
8
|
-
"AuthFactor",
|
|
9
|
-
] as const
|
|
10
|
-
|
|
11
|
-
export default tagTypes
|
|
12
|
-
export type TagTypes = (typeof tagTypes)[number]
|
package/src/api/urls.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { modelUrls } from "../utils/api"
|
|
2
|
-
|
|
3
|
-
const urls = {
|
|
4
|
-
user: modelUrls("users/", "users/<id>/"),
|
|
5
|
-
teacher: modelUrls("users/teachers/", "users/teachers/<id>/"),
|
|
6
|
-
student: modelUrls("users/students/", "users/students/<id>/"),
|
|
7
|
-
school: modelUrls("schools/", "schools/<id>/"),
|
|
8
|
-
class: modelUrls("classes/", "classes/<id>/"),
|
|
9
|
-
otpBypassToken: modelUrls("otp-bypass-tokens/", "otp-bypass-tokens/<id>/"),
|
|
10
|
-
authFactor: modelUrls("auth-factors/", "auth-factors/<id>/"),
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default urls
|
package/src/components/App.css
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
@font-face {
|
|
2
|
-
font-family: "SpaceGrotesk";
|
|
3
|
-
src:
|
|
4
|
-
local("SpaceGrotesk"),
|
|
5
|
-
url("../fonts/ttf/SpaceGrotesk-VariableFont_wght.ttf") format("truetype");
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
@font-face {
|
|
9
|
-
font-family: "Inter";
|
|
10
|
-
src:
|
|
11
|
-
local("Inter"),
|
|
12
|
-
url("../fonts/ttf/Inter-VariableFont_slnt,wght.ttf") format("truetype");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
html,
|
|
16
|
-
body {
|
|
17
|
-
box-sizing: border-box;
|
|
18
|
-
height: 100%;
|
|
19
|
-
padding: 0;
|
|
20
|
-
margin: 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
#root {
|
|
24
|
-
box-sizing: border-box;
|
|
25
|
-
min-height: 100%;
|
|
26
|
-
display: flex;
|
|
27
|
-
flex-direction: column;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#header,
|
|
31
|
-
#footer {
|
|
32
|
-
flex-grow: 0;
|
|
33
|
-
flex-shrink: 0;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
#body {
|
|
37
|
-
flex-grow: 1;
|
|
38
|
-
}
|
package/src/components/App.tsx
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { BrowserRouter, Routes as RouterRoutes } from "react-router-dom"
|
|
2
|
-
import { CssBaseline, ThemeProvider } from "@mui/material"
|
|
3
|
-
import { type FC, type JSX, type ReactNode } from "react"
|
|
4
|
-
import { Provider, type ProviderProps } from "react-redux"
|
|
5
|
-
import { type Action } from "redux"
|
|
6
|
-
import { StaticRouter } from "react-router-dom/server"
|
|
7
|
-
import { type ThemeProviderProps } from "@mui/material/styles/ThemeProvider"
|
|
8
|
-
|
|
9
|
-
import "./App.css"
|
|
10
|
-
import { SSR } from "../settings"
|
|
11
|
-
import { useLocation } from "../hooks"
|
|
12
|
-
// import { InactiveDialog, ScreenTimeDialog } from "../features"
|
|
13
|
-
// import { useCountdown, useEventListener } from "../hooks"
|
|
14
|
-
// import "../scripts"
|
|
15
|
-
// import {
|
|
16
|
-
// configureFreshworksWidget,
|
|
17
|
-
// toggleOneTrustInfoDisplay,
|
|
18
|
-
// } from "../utils/window"
|
|
19
|
-
|
|
20
|
-
export interface AppProps<A extends Action = Action, S = unknown> {
|
|
21
|
-
path?: string
|
|
22
|
-
theme: ThemeProviderProps["theme"]
|
|
23
|
-
store: ProviderProps<A, S>["store"]
|
|
24
|
-
routes: ReactNode
|
|
25
|
-
header?: ReactNode
|
|
26
|
-
footer?: ReactNode
|
|
27
|
-
headerExcludePaths?: string[]
|
|
28
|
-
footerExcludePaths?: string[]
|
|
29
|
-
maxIdleSeconds?: number
|
|
30
|
-
maxTotalSeconds?: number
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type BaseRoutesProps = Pick<
|
|
34
|
-
AppProps,
|
|
35
|
-
"routes" | "header" | "footer" | "headerExcludePaths" | "footerExcludePaths"
|
|
36
|
-
>
|
|
37
|
-
|
|
38
|
-
const Routes: FC<BaseRoutesProps & { path: string }> = ({
|
|
39
|
-
path,
|
|
40
|
-
routes,
|
|
41
|
-
header = <></>, // TODO: "header = <Header />"
|
|
42
|
-
footer = <></>, // TODO: "footer = <Footer />"
|
|
43
|
-
headerExcludePaths = [],
|
|
44
|
-
footerExcludePaths = [],
|
|
45
|
-
}) => (
|
|
46
|
-
<>
|
|
47
|
-
{!headerExcludePaths.includes(path) && header}
|
|
48
|
-
<RouterRoutes>{routes}</RouterRoutes>
|
|
49
|
-
{!footerExcludePaths.includes(path) && footer}
|
|
50
|
-
</>
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
const BrowserRoutes: FC<BaseRoutesProps> = props => {
|
|
54
|
-
const { pathname } = useLocation()
|
|
55
|
-
|
|
56
|
-
return <Routes path={pathname} {...props} />
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const App = <A extends Action = Action, S = unknown>({
|
|
60
|
-
path,
|
|
61
|
-
theme,
|
|
62
|
-
store,
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
64
|
-
maxIdleSeconds = 60 * 60,
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
66
|
-
maxTotalSeconds = 60 * 60,
|
|
67
|
-
...routesProps
|
|
68
|
-
}: AppProps<A, S>): JSX.Element => {
|
|
69
|
-
// TODO: cannot use document during SSR
|
|
70
|
-
// const root = document.getElementById("root") as HTMLElement
|
|
71
|
-
|
|
72
|
-
// const [idleSeconds, setIdleSeconds] = useCountdown(maxIdleSeconds)
|
|
73
|
-
// const [totalSeconds, setTotalSeconds] = useCountdown(maxTotalSeconds)
|
|
74
|
-
// const resetIdleSeconds = useCallback(() => {
|
|
75
|
-
// setIdleSeconds(maxIdleSeconds)
|
|
76
|
-
// }, [setIdleSeconds, maxIdleSeconds])
|
|
77
|
-
|
|
78
|
-
// const isIdle = idleSeconds === 0
|
|
79
|
-
// const tooMuchScreenTime = totalSeconds === 0
|
|
80
|
-
|
|
81
|
-
// useEventListener(root, "mousemove", resetIdleSeconds)
|
|
82
|
-
// useEventListener(root, "keypress", resetIdleSeconds)
|
|
83
|
-
|
|
84
|
-
// React.useEffect(() => {
|
|
85
|
-
// configureFreshworksWidget("hide")
|
|
86
|
-
// }, [])
|
|
87
|
-
|
|
88
|
-
// if (import.meta.env.PROD) {
|
|
89
|
-
// toggleOneTrustInfoDisplay()
|
|
90
|
-
// }
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<ThemeProvider theme={theme}>
|
|
94
|
-
<CssBaseline />
|
|
95
|
-
<Provider store={store}>
|
|
96
|
-
{/* <InactiveDialog open={isIdle} onClose={resetIdleSeconds} />
|
|
97
|
-
<ScreenTimeDialog
|
|
98
|
-
open={!isIdle && tooMuchScreenTime}
|
|
99
|
-
onClose={() => {
|
|
100
|
-
setTotalSeconds(maxTotalSeconds)
|
|
101
|
-
}}
|
|
102
|
-
/> */}
|
|
103
|
-
{SSR ? (
|
|
104
|
-
<StaticRouter location={path as string}>
|
|
105
|
-
<Routes path={path as string} {...routesProps} />
|
|
106
|
-
</StaticRouter>
|
|
107
|
-
) : (
|
|
108
|
-
<BrowserRouter>
|
|
109
|
-
<BrowserRoutes {...routesProps} />
|
|
110
|
-
</BrowserRouter>
|
|
111
|
-
)}
|
|
112
|
-
</Provider>
|
|
113
|
-
</ThemeProvider>
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export default App
|
|
118
|
-
|
|
119
|
-
// TODO: figure out what to do with this
|
|
120
|
-
// function useOneTrustScripts(): void {
|
|
121
|
-
// const oneTrustEventTypes = [
|
|
122
|
-
// useExternalScript({
|
|
123
|
-
// props: {
|
|
124
|
-
// src: "https://cdn-ukwest.onetrust.com/consent/5da42396-cb12-4493-8d04-5179033cfbad/OtAutoBlock.js",
|
|
125
|
-
// type: "text/javascript",
|
|
126
|
-
// },
|
|
127
|
-
// eventTypes: ["load", "error"],
|
|
128
|
-
// }),
|
|
129
|
-
// useExternalScript({
|
|
130
|
-
// props: {
|
|
131
|
-
// src: "https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js",
|
|
132
|
-
// type: "text/javascript",
|
|
133
|
-
// charset: "UTF-8",
|
|
134
|
-
// },
|
|
135
|
-
// attrs: {
|
|
136
|
-
// "data-domain-script": "5da42396-cb12-4493-8d04-5179033cfbad",
|
|
137
|
-
// },
|
|
138
|
-
// eventTypes: ["load", "error"],
|
|
139
|
-
// }),
|
|
140
|
-
// useExternalScript({
|
|
141
|
-
// props: {
|
|
142
|
-
// src: "https://cdn-ukwest.onetrust.com/scripttemplates/202302.1.0/otBannerSdk.js",
|
|
143
|
-
// async: true,
|
|
144
|
-
// type: "text/javascript",
|
|
145
|
-
// },
|
|
146
|
-
// eventTypes: ["load", "error"],
|
|
147
|
-
// }),
|
|
148
|
-
// ]
|
|
149
|
-
// if (oneTrustEventTypes.some(t => t === "error")) {
|
|
150
|
-
// alert("OneTrust failed to load!")
|
|
151
|
-
// }
|
|
152
|
-
// }
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Tooltip, type TooltipProps } from "@mui/material"
|
|
2
|
-
import React from "react"
|
|
3
|
-
|
|
4
|
-
import { wrap } from "../utils/general"
|
|
5
|
-
|
|
6
|
-
export interface ClickableTooltipProps extends TooltipProps {}
|
|
7
|
-
|
|
8
|
-
const ClickableTooltip: React.FC<ClickableTooltipProps> = ({
|
|
9
|
-
open = false,
|
|
10
|
-
onClick,
|
|
11
|
-
...otherTooltipProps
|
|
12
|
-
}) => {
|
|
13
|
-
const [_open, _setOpen] = React.useState(open)
|
|
14
|
-
|
|
15
|
-
React.useEffect(() => {
|
|
16
|
-
_setOpen(open)
|
|
17
|
-
}, [open])
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<Tooltip
|
|
21
|
-
open={_open}
|
|
22
|
-
onMouseOver={() => {
|
|
23
|
-
if (!_open) {
|
|
24
|
-
_setOpen(true)
|
|
25
|
-
}
|
|
26
|
-
}}
|
|
27
|
-
onMouseLeave={() => {
|
|
28
|
-
_setOpen(false)
|
|
29
|
-
}}
|
|
30
|
-
onClick={wrap(
|
|
31
|
-
{
|
|
32
|
-
after: () => {
|
|
33
|
-
_setOpen(!_open)
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
onClick,
|
|
37
|
-
)}
|
|
38
|
-
{...otherTooltipProps}
|
|
39
|
-
/>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default ClickableTooltip
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { screen } from "@testing-library/react"
|
|
2
|
-
|
|
3
|
-
import CopyIconButton from "./CopyIconButton"
|
|
4
|
-
import { renderWithUser } from "../utils/test"
|
|
5
|
-
|
|
6
|
-
test("Clicking button should copy content", async () => {
|
|
7
|
-
const content = "Example string to be copied."
|
|
8
|
-
|
|
9
|
-
const { user } = renderWithUser(<CopyIconButton content={content} />)
|
|
10
|
-
|
|
11
|
-
expect(await navigator.clipboard.readText()).toEqual("")
|
|
12
|
-
|
|
13
|
-
await user.click(screen.getByTestId("copy-icon-button"))
|
|
14
|
-
|
|
15
|
-
expect(await navigator.clipboard.readText()).toEqual(content)
|
|
16
|
-
})
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { IconButton, type IconButtonProps } from "@mui/material"
|
|
2
|
-
import { ContentCopy as ContentCopyIcon } from "@mui/icons-material"
|
|
3
|
-
import type { FC } from "react"
|
|
4
|
-
|
|
5
|
-
export interface CopyIconButtonProps extends Omit<IconButtonProps, "onClick"> {
|
|
6
|
-
content: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const CopyIconButton: FC<CopyIconButtonProps> = ({
|
|
10
|
-
content,
|
|
11
|
-
children = <ContentCopyIcon />,
|
|
12
|
-
...otherIconButtonProps
|
|
13
|
-
}) => {
|
|
14
|
-
return (
|
|
15
|
-
<IconButton
|
|
16
|
-
data-testid="copy-icon-button"
|
|
17
|
-
onClick={() => {
|
|
18
|
-
void navigator.clipboard.writeText(content)
|
|
19
|
-
}}
|
|
20
|
-
{...otherIconButtonProps}
|
|
21
|
-
>
|
|
22
|
-
{children}
|
|
23
|
-
</IconButton>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default CopyIconButton
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { type FC, useState } from "react"
|
|
2
|
-
import { Typography, type TypographyProps } from "@mui/material"
|
|
3
|
-
|
|
4
|
-
import { useCountdown } from "../hooks"
|
|
5
|
-
|
|
6
|
-
export interface CountdownProps extends Omit<TypographyProps, "children"> {
|
|
7
|
-
seconds: number
|
|
8
|
-
start?: boolean
|
|
9
|
-
onEnd: () => void
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const Countdown: FC<CountdownProps> = ({
|
|
13
|
-
seconds,
|
|
14
|
-
start = true,
|
|
15
|
-
onEnd,
|
|
16
|
-
...typographyProps
|
|
17
|
-
}) => {
|
|
18
|
-
seconds = Math.floor(seconds)
|
|
19
|
-
const _seconds = useCountdown(seconds)[0]
|
|
20
|
-
const [end, setEnd] = useState(!start)
|
|
21
|
-
|
|
22
|
-
if (_seconds === 0 && !end) {
|
|
23
|
-
setEnd(true)
|
|
24
|
-
onEnd()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
seconds = Math.floor(_seconds % 60)
|
|
28
|
-
const minutes = Math.floor(_seconds / 60)
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<>
|
|
32
|
-
{_seconds > 0 && (
|
|
33
|
-
<Typography {...typographyProps}>
|
|
34
|
-
{minutes > 0 && `${minutes} ${minutes > 1 ? "mins" : "min"} `}
|
|
35
|
-
{seconds > 0 && `${seconds} ${seconds > 1 ? "secs" : "sec"}`}
|
|
36
|
-
</Typography>
|
|
37
|
-
)}
|
|
38
|
-
</>
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default Countdown
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Button, type ButtonProps } from "@mui/material"
|
|
2
|
-
import { type FC, useEffect } from "react"
|
|
3
|
-
import { Download as DownloadIcon } from "@mui/icons-material"
|
|
4
|
-
|
|
5
|
-
export type DownloadFileButtonProps = ButtonProps & {
|
|
6
|
-
file:
|
|
7
|
-
| Blob
|
|
8
|
-
| MediaSource
|
|
9
|
-
| {
|
|
10
|
-
text: string
|
|
11
|
-
mimeType: "plain" | "csv"
|
|
12
|
-
name: string
|
|
13
|
-
charset?: string
|
|
14
|
-
extension?: string
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const DownloadFileButton: FC<DownloadFileButtonProps> = ({
|
|
19
|
-
children = "Download",
|
|
20
|
-
endIcon = <DownloadIcon />,
|
|
21
|
-
file,
|
|
22
|
-
...otherButtonProps
|
|
23
|
-
}) => {
|
|
24
|
-
let url: undefined | string = undefined
|
|
25
|
-
let anchorProps: undefined | { download?: string; href: string } = undefined
|
|
26
|
-
if ("mimeType" in file) {
|
|
27
|
-
const { text, mimeType, name, charset = "utf-8" } = file
|
|
28
|
-
let { extension } = file
|
|
29
|
-
|
|
30
|
-
if (!extension) extension = "." + { plain: "txt", csv: "csv" }[mimeType]
|
|
31
|
-
|
|
32
|
-
anchorProps = {
|
|
33
|
-
download: name + extension,
|
|
34
|
-
href: `data:text/${mimeType};charset=${charset},${encodeURIComponent(text)}`,
|
|
35
|
-
}
|
|
36
|
-
} else {
|
|
37
|
-
url = URL.createObjectURL(file)
|
|
38
|
-
|
|
39
|
-
anchorProps = { href: url }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
return () => {
|
|
44
|
-
if (url) URL.revokeObjectURL(url)
|
|
45
|
-
}
|
|
46
|
-
}, [url])
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<Button endIcon={endIcon} {...otherButtonProps} {...anchorProps}>
|
|
50
|
-
{children}
|
|
51
|
-
</Button>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default DownloadFileButton
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AppBar,
|
|
3
|
-
type AppBarProps,
|
|
4
|
-
Container,
|
|
5
|
-
type ContainerProps,
|
|
6
|
-
Toolbar,
|
|
7
|
-
type ToolbarProps,
|
|
8
|
-
useScrollTrigger,
|
|
9
|
-
} from "@mui/material"
|
|
10
|
-
import { type FC, cloneElement } from "react"
|
|
11
|
-
|
|
12
|
-
export interface ElevatedAppBarProps extends Omit<AppBarProps, "position"> {
|
|
13
|
-
containerProps: ContainerProps
|
|
14
|
-
toolbarProps?: ToolbarProps
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const ElevatedAppBar: FC<ElevatedAppBarProps> = ({
|
|
18
|
-
containerProps,
|
|
19
|
-
toolbarProps,
|
|
20
|
-
elevation = 4,
|
|
21
|
-
children,
|
|
22
|
-
...otherProps
|
|
23
|
-
}) => {
|
|
24
|
-
const trigger = useScrollTrigger({
|
|
25
|
-
disableHysteresis: true,
|
|
26
|
-
threshold: 0,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
return cloneElement(
|
|
30
|
-
<AppBar elevation={elevation} {...otherProps}>
|
|
31
|
-
<Container {...containerProps}>
|
|
32
|
-
<Toolbar {...toolbarProps}>{children}</Toolbar>
|
|
33
|
-
</Container>
|
|
34
|
-
</AppBar>,
|
|
35
|
-
{
|
|
36
|
-
position: trigger ? "fixed" : "sticky",
|
|
37
|
-
},
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default ElevatedAppBar
|