codeforlife 2.7.1 → 2.8.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/.github/workflows/main.yml +0 -3
- package/CHANGELOG.md +14 -0
- package/eslint.config.js +17 -0
- package/package.json +45 -24
- package/src/api/createApi.ts +4 -4
- package/src/api/endpoints/authFactor.ts +2 -2
- package/src/api/endpoints/klass.ts +8 -8
- package/src/api/endpoints/school.ts +2 -2
- package/src/api/endpoints/session.ts +2 -1
- package/src/api/endpoints/user.ts +3 -3
- package/src/api/models.ts +1 -1
- package/src/api/schemas.ts +16 -16
- package/src/components/App.tsx +7 -5
- package/src/components/CopyIconButton.test.tsx +1 -1
- package/src/components/CopyIconButton.tsx +2 -2
- package/src/components/Countdown.tsx +3 -3
- package/src/components/DownloadFileButton.tsx +2 -1
- package/src/components/ElevatedAppBar.tsx +5 -5
- package/src/components/Image.tsx +7 -7
- package/src/components/InputFileButton.tsx +2 -2
- package/src/components/ItemizedList.tsx +4 -4
- package/src/components/OrderedGrid.tsx +3 -3
- package/src/components/ScrollIntoViewLink.tsx +1 -2
- package/src/components/SyncError.tsx +1 -1
- package/src/components/TablePagination.tsx +19 -9
- package/src/components/YouTubeVideo.tsx +2 -2
- package/src/components/form/ApiAutocompleteField.tsx +48 -41
- package/src/components/form/AutocompleteField.tsx +22 -11
- package/src/components/form/CheckboxField.tsx +14 -9
- package/src/components/form/CountryField.tsx +5 -4
- package/src/components/form/DatePickerField.tsx +18 -11
- package/src/components/form/EmailField.tsx +1 -1
- package/src/components/form/FirstNameField.tsx +2 -2
- package/src/components/form/Form.tsx +13 -12
- package/src/components/form/PasswordField.tsx +2 -2
- package/src/components/form/RepeatField.tsx +18 -10
- package/src/components/form/SubmitButton.tsx +14 -10
- package/src/components/form/TextField.tsx +17 -11
- package/src/components/form/UkCountyField.tsx +3 -2
- package/src/components/form/index.tsx +35 -28
- package/src/components/page/Banner.tsx +3 -3
- package/src/components/page/Notification.tsx +3 -3
- package/src/components/page/Page.tsx +5 -5
- package/src/components/page/Section.tsx +1 -1
- package/src/components/page/TabBar.tsx +5 -5
- package/src/components/router/Link.tsx +2 -1
- package/src/components/router/LinkButton.tsx +1 -0
- package/src/components/router/LinkIconButton.tsx +1 -0
- package/src/components/router/LinkListItem.tsx +1 -0
- package/src/components/router/LinkTab.tsx +1 -0
- package/src/components/router/Navigate.tsx +2 -2
- package/src/components/router/index.tsx +9 -12
- package/src/components/table/CellStack.tsx +2 -2
- package/src/components/table/index.tsx +2 -4
- package/src/features/InactiveDialog.tsx +2 -2
- package/src/features/ScreenTimeDialog.tsx +3 -6
- package/src/hooks/api.tsx +4 -2
- package/src/hooks/auth.tsx +29 -16
- package/src/hooks/{general.ts → general.tsx} +3 -3
- package/src/hooks/router.tsx +9 -9
- package/src/middlewares/session.ts +15 -10
- package/src/settings/index.ts +3 -6
- package/src/setupTests.ts +1 -0
- package/src/theme/ThemedBox.tsx +9 -9
- package/src/theme/components/MuiButton.ts +1 -1
- package/src/theme/components/MuiCardActions.tsx +1 -1
- package/src/theme/components/MuiContainer.ts +1 -1
- package/src/theme/components/MuiFormControlLabel.ts +1 -1
- package/src/theme/components/MuiFormHelperText.ts +1 -1
- package/src/theme/components/MuiInputBase.ts +1 -1
- package/src/theme/components/MuiLink.ts +1 -1
- package/src/theme/components/MuiListItemText.ts +1 -1
- package/src/theme/components/MuiMenuItem.ts +1 -1
- package/src/theme/components/MuiSelect.ts +2 -2
- package/src/theme/components/MuiTable.ts +1 -1
- package/src/theme/components/MuiTableBody.ts +1 -1
- package/src/theme/components/MuiTableHead.ts +2 -2
- package/src/theme/components/MuiTextField.ts +3 -3
- package/src/theme/components/_components.ts +4 -2
- package/src/theme/palette.ts +2 -2
- package/src/theme/typography.ts +1 -1
- package/src/utils/api.tsx +6 -4
- package/src/utils/auth.ts +1 -1
- package/src/utils/form.test.ts +1 -1
- package/src/utils/form.ts +14 -9
- package/src/utils/general.test.ts +7 -7
- package/src/utils/general.ts +10 -12
- package/src/utils/router.test.ts +1 -1
- package/src/utils/router.ts +2 -2
- package/src/utils/schema.ts +11 -11
- package/src/utils/test.tsx +2 -2
- package/src/utils/theme.tsx +7 -6
- package/src/utils/window.ts +2 -0
- package/tsconfig.app.json +4 -0
- package/tsconfig.json +4 -28
- package/tsconfig.node.json +3 -10
- package/vite.config.ts +1 -1
- package/.eslintrc.json +0 -47
- package/src/vite.config.ts +0 -49
- /package/src/{public/images → images/svg}/brain.svg +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [2.8.0](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.7.2...v2.8.0) (2025-08-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* type fixes ([#89](https://github.com/ocadotechnology/codeforlife-package-javascript/issues/89)) ([386f6e3](https://github.com/ocadotechnology/codeforlife-package-javascript/commit/386f6e3fe135d59480a18034741ff5d33a7a76ac))
|
|
7
|
+
|
|
8
|
+
## [2.7.2](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.7.1...v2.7.2) (2025-08-15)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* comment ([1364251](https://github.com/ocadotechnology/codeforlife-package-javascript/commit/13642516aea7a89d7c3e24e7813391686587447f))
|
|
14
|
+
|
|
1
15
|
## [2.7.1](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.7.0...v2.7.1) (2025-08-15)
|
|
2
16
|
|
|
3
17
|
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import workspaceConfig from "@codeforlife/workspace/eslint.config.js"
|
|
2
|
+
import ts from "typescript-eslint"
|
|
3
|
+
|
|
4
|
+
export default ts.config(
|
|
5
|
+
...workspaceConfig,
|
|
6
|
+
{
|
|
7
|
+
ignores: [
|
|
8
|
+
"src/scripts/*",
|
|
9
|
+
"src/server.js", // TODO: convert to src/server.ts and remove this ignore
|
|
10
|
+
],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
parserOptions: { tsconfigRootDir: import.meta.dirname },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
)
|
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"name": "codeforlife",
|
|
3
3
|
"description": "Common frontend code",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.8.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"cli": "
|
|
8
|
+
"cli": "../scripts/frontend $@"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -17,6 +17,48 @@
|
|
|
17
17
|
"url": "https://github.com/ocadotechnology/codeforlife-package-javascript/issues"
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://github.com/ocadotechnology/codeforlife-package-javascript#readme",
|
|
20
|
+
"//": [
|
|
21
|
+
"Export rules:",
|
|
22
|
+
"🚫 Don't export anything not contained in the src directory.",
|
|
23
|
+
"",
|
|
24
|
+
"Dependency rules:",
|
|
25
|
+
"✅ Do add `dependencies` that are required to use this package.",
|
|
26
|
+
"✅ Do add `dependencies` that are shared across all services.",
|
|
27
|
+
"🚫 Don't add `devDependencies` that are inherited from the CFL workspace.",
|
|
28
|
+
"✅ Do add `devDependencies` that are unique to this package."
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
".": "./src/index.ts",
|
|
32
|
+
"./api": "./src/api/index.ts",
|
|
33
|
+
"./api/endpoints": "./src/api/endpoints/index.ts",
|
|
34
|
+
"./api/*": "./src/api/*.ts",
|
|
35
|
+
"./components": "./src/components/index.ts",
|
|
36
|
+
"./components/form": "./src/components/form/index.tsx",
|
|
37
|
+
"./components/page": "./src/components/page/index.ts",
|
|
38
|
+
"./components/router": "./src/components/router/index.tsx",
|
|
39
|
+
"./components/table": "./src/components/table/index.tsx",
|
|
40
|
+
"./components/*": "./src/components/*.tsx",
|
|
41
|
+
"./features": "./src/features/index.ts",
|
|
42
|
+
"./features/*": "./src/features/*.tsx",
|
|
43
|
+
"./fonts/*": "./src/fonts/*.ttf",
|
|
44
|
+
"./hooks": "./src/hooks/index.ts",
|
|
45
|
+
"./hooks/*": "./src/hooks/*.tsx",
|
|
46
|
+
"./images/svg/*": "./src/images/svg/*.svg",
|
|
47
|
+
"./middlewares": "./src/middlewares/index.ts",
|
|
48
|
+
"./middlewares/*": "./src/middlewares/*.ts",
|
|
49
|
+
"./settings": "./src/settings/index.ts",
|
|
50
|
+
"./settings/*": "./src/settings/*.ts",
|
|
51
|
+
"./slices": "./src/slices/index.ts",
|
|
52
|
+
"./slices/*": "./src/slices/*.ts",
|
|
53
|
+
"./theme": "./src/theme/index.ts",
|
|
54
|
+
"./theme/components": "./src/theme/components/index.ts",
|
|
55
|
+
"./theme/*": "./src/theme/*.ts",
|
|
56
|
+
"./utils/api": "./src/utils/api.tsx",
|
|
57
|
+
"./utils/test": "./src/utils/test.tsx",
|
|
58
|
+
"./utils/theme": "./src/utils/theme.tsx",
|
|
59
|
+
"./utils/*": "./src/utils/*.ts",
|
|
60
|
+
"./server": "./src/server.js"
|
|
61
|
+
},
|
|
20
62
|
"dependencies": {
|
|
21
63
|
"@emotion/react": "^11.10.6",
|
|
22
64
|
"@emotion/styled": "^11.10.6",
|
|
@@ -39,28 +81,7 @@
|
|
|
39
81
|
"yup": "^1.1.1"
|
|
40
82
|
},
|
|
41
83
|
"devDependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@testing-library/jest-dom": "^6.2.0",
|
|
44
|
-
"@testing-library/react": "^14.1.2",
|
|
45
|
-
"@testing-library/user-event": "^14.5.2",
|
|
46
|
-
"@types/express": "^5.0.0",
|
|
47
|
-
"@types/js-cookie": "^3.0.3",
|
|
48
|
-
"@types/node": "^22.14.1",
|
|
49
|
-
"@types/qs": "^6.9.7",
|
|
50
|
-
"@types/react": "^18.2.47",
|
|
51
|
-
"@types/react-dom": "^18.2.18",
|
|
52
|
-
"@vitejs/plugin-react": "^4.2.1",
|
|
53
|
-
"@vitest/coverage-istanbul": "^1.6.0",
|
|
54
|
-
"@vitest/ui": "^1.6.0",
|
|
55
|
-
"eslint": "^8.56.0",
|
|
56
|
-
"eslint-config-prettier": "^9.1.0",
|
|
57
|
-
"eslint-config-react-app": "^7.0.1",
|
|
58
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
59
|
-
"jsdom": "^23.2.0",
|
|
60
|
-
"prettier": "^3.2.1",
|
|
61
|
-
"typescript": "^5.3.3",
|
|
62
|
-
"vite": "^5.0.11",
|
|
63
|
-
"vitest": "^1.2.0"
|
|
84
|
+
"@codeforlife/workspace": "link:../configs/frontend"
|
|
64
85
|
},
|
|
65
86
|
"release": {
|
|
66
87
|
"branches": [
|
package/src/api/createApi.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type FetchArgs,
|
|
2
3
|
createApi as _createApi,
|
|
3
4
|
fetchBaseQuery,
|
|
4
|
-
type FetchArgs,
|
|
5
5
|
} from "@reduxjs/toolkit/query/react"
|
|
6
6
|
|
|
7
7
|
import { SERVICE_API_URL } from "../settings"
|
|
8
|
-
import defaultTagTypes from "./tagTypes"
|
|
9
8
|
import { buildLogoutEndpoint } from "./endpoints/session"
|
|
9
|
+
import defaultTagTypes from "./tagTypes"
|
|
10
10
|
import { getCsrfCookie } from "../utils/auth"
|
|
11
11
|
import { isSafeHttpMethod } from "../utils/api"
|
|
12
12
|
|
|
@@ -45,7 +45,7 @@ export default function createApi<TagTypes extends string = never>({
|
|
|
45
45
|
const method = typeof arg === "string" ? "GET" : arg.method || "GET"
|
|
46
46
|
|
|
47
47
|
if (type === "mutation" || !isSafeHttpMethod(method)) {
|
|
48
|
-
|
|
48
|
+
const csrfToken = getCsrfCookie()
|
|
49
49
|
if (csrfToken) headers.set("x-csrftoken", csrfToken)
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ export default function createApi<TagTypes extends string = never>({
|
|
|
55
55
|
|
|
56
56
|
const api = _createApi({
|
|
57
57
|
// https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#implementing-a-custom-basequery
|
|
58
|
-
baseQuery: async (args, api, extraOptions) => {
|
|
58
|
+
baseQuery: async (args: string | FetchArgs, api, extraOptions) => {
|
|
59
59
|
if (api.type === "mutation" && getCsrfCookie() === undefined) {
|
|
60
60
|
// Get the CSRF token.
|
|
61
61
|
const { error } = await fetch(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
buildUrl,
|
|
5
|
-
tagData,
|
|
6
4
|
type ListArg as _ListArg,
|
|
7
5
|
type ListResult as _ListResult,
|
|
6
|
+
buildUrl,
|
|
7
|
+
tagData,
|
|
8
8
|
} from "../../utils/api"
|
|
9
9
|
import type { AuthFactor } from "../models"
|
|
10
10
|
import { type TagTypes } from "../tagTypes"
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
|
|
2
2
|
|
|
3
|
+
import type {
|
|
4
|
+
Class,
|
|
5
|
+
SchoolTeacher,
|
|
6
|
+
SchoolTeacherUser,
|
|
7
|
+
Teacher,
|
|
8
|
+
} from "../models"
|
|
3
9
|
import {
|
|
4
|
-
buildUrl,
|
|
5
|
-
tagData,
|
|
6
10
|
type ListArg as _ListArg,
|
|
7
11
|
type ListResult as _ListResult,
|
|
8
12
|
type RetrieveArg as _RetrieveArg,
|
|
9
13
|
type RetrieveResult as _RetrieveResult,
|
|
14
|
+
buildUrl,
|
|
15
|
+
tagData,
|
|
10
16
|
} from "../../utils/api"
|
|
11
|
-
import type {
|
|
12
|
-
Class,
|
|
13
|
-
Teacher,
|
|
14
|
-
SchoolTeacher,
|
|
15
|
-
SchoolTeacherUser,
|
|
16
|
-
} from "../models"
|
|
17
17
|
import { type TagTypes } from "../tagTypes"
|
|
18
18
|
import urls from "../urls"
|
|
19
19
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
buildUrl,
|
|
5
|
-
tagData,
|
|
6
4
|
type RetrieveArg as _RetrieveArg,
|
|
7
5
|
type RetrieveResult as _RetrieveResult,
|
|
6
|
+
buildUrl,
|
|
7
|
+
tagData,
|
|
8
8
|
} from "../../utils/api"
|
|
9
9
|
import type { School } from "../models"
|
|
10
10
|
import { type TagTypes } from "../tagTypes"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Api, type EndpointBuilder } from "@reduxjs/toolkit/query/react"
|
|
2
2
|
|
|
3
3
|
import { login, logout } from "../../slices/session"
|
|
4
4
|
|
|
@@ -39,6 +39,7 @@ export function buildLogoutEndpoint<ResultType, QueryArg>(
|
|
|
39
39
|
console.error("Failed to call logout endpoint...", error)
|
|
40
40
|
} finally {
|
|
41
41
|
dispatch(logout())
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
|
42
43
|
dispatch(api.util.resetApiState())
|
|
43
44
|
}
|
|
44
45
|
},
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
|
|
2
2
|
|
|
3
|
+
import type { Class, User } from "../models"
|
|
3
4
|
import {
|
|
4
|
-
buildUrl,
|
|
5
|
-
tagData,
|
|
6
5
|
type ListArg as _ListArg,
|
|
7
6
|
type ListResult as _ListResult,
|
|
8
7
|
type RetrieveArg as _RetrieveArg,
|
|
9
8
|
type RetrieveResult as _RetrieveResult,
|
|
9
|
+
buildUrl,
|
|
10
|
+
tagData,
|
|
10
11
|
} from "../../utils/api"
|
|
11
|
-
import type { Class, User } from "../models"
|
|
12
12
|
import { type TagTypes } from "../tagTypes"
|
|
13
13
|
import urls from "../urls"
|
|
14
14
|
|
package/src/api/models.ts
CHANGED
package/src/api/schemas.ts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import * as yup from "yup"
|
|
2
2
|
|
|
3
|
-
import { UK_COUNTIES, COUNTRY_ISO_CODES } from "../utils/general"
|
|
4
3
|
import type {
|
|
5
|
-
|
|
6
|
-
TeacherUser,
|
|
7
|
-
SchoolTeacherUser,
|
|
4
|
+
AdminSchoolTeacher,
|
|
8
5
|
AdminSchoolTeacherUser,
|
|
9
|
-
NonAdminSchoolTeacherUser,
|
|
10
|
-
NonSchoolTeacherUser,
|
|
11
|
-
Teacher,
|
|
12
|
-
Student,
|
|
13
|
-
Class,
|
|
14
|
-
School,
|
|
15
6
|
AuthFactor,
|
|
16
|
-
|
|
17
|
-
StudentUser,
|
|
7
|
+
Class,
|
|
18
8
|
IndependentUser,
|
|
19
|
-
SchoolTeacher,
|
|
20
|
-
AdminSchoolTeacher,
|
|
21
9
|
NonAdminSchoolTeacher,
|
|
10
|
+
NonAdminSchoolTeacherUser,
|
|
22
11
|
NonSchoolTeacher,
|
|
12
|
+
NonSchoolTeacherUser,
|
|
13
|
+
OtpBypassToken,
|
|
14
|
+
School,
|
|
15
|
+
SchoolTeacher,
|
|
16
|
+
SchoolTeacherUser,
|
|
17
|
+
Student,
|
|
18
|
+
StudentUser,
|
|
19
|
+
Teacher,
|
|
20
|
+
TeacherUser,
|
|
21
|
+
User,
|
|
23
22
|
} from "./models"
|
|
23
|
+
import { COUNTRY_ISO_CODES, UK_COUNTIES } from "../utils/general"
|
|
24
24
|
import {
|
|
25
|
-
unicodeAlphanumericString,
|
|
26
|
-
uppercaseAsciiAlphanumericString,
|
|
27
25
|
lowercaseAsciiAlphanumericString,
|
|
28
26
|
numericId,
|
|
27
|
+
unicodeAlphanumericString,
|
|
28
|
+
uppercaseAsciiAlphanumericString,
|
|
29
29
|
} from "../utils/schema"
|
|
30
30
|
import { type Schemas } from "../utils/api"
|
|
31
31
|
|
package/src/components/App.tsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { BrowserRouter, Routes as RouterRoutes } from "react-router-dom"
|
|
1
2
|
import { CssBaseline, ThemeProvider } from "@mui/material"
|
|
2
|
-
import { type
|
|
3
|
-
import { type FC, type ReactNode } from "react"
|
|
3
|
+
import { type FC, type JSX, type ReactNode } from "react"
|
|
4
4
|
import { Provider, type ProviderProps } from "react-redux"
|
|
5
|
-
import { BrowserRouter, Routes as RouterRoutes } from "react-router-dom"
|
|
6
|
-
import { StaticRouter } from "react-router-dom/server"
|
|
7
5
|
import { type Action } from "redux"
|
|
6
|
+
import { StaticRouter } from "react-router-dom/server"
|
|
7
|
+
import { type ThemeProviderProps } from "@mui/material/styles/ThemeProvider"
|
|
8
8
|
|
|
9
9
|
import "./App.css"
|
|
10
|
-
import { useLocation } from "../hooks"
|
|
11
10
|
import { SSR } from "../settings"
|
|
11
|
+
import { useLocation } from "../hooks"
|
|
12
12
|
// import { InactiveDialog, ScreenTimeDialog } from "../features"
|
|
13
13
|
// import { useCountdown, useEventListener } from "../hooks"
|
|
14
14
|
// import "../scripts"
|
|
@@ -60,7 +60,9 @@ const App = <A extends Action = Action, S = unknown>({
|
|
|
60
60
|
path,
|
|
61
61
|
theme,
|
|
62
62
|
store,
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
63
64
|
maxIdleSeconds = 60 * 60,
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
64
66
|
maxTotalSeconds = 60 * 60,
|
|
65
67
|
...routesProps
|
|
66
68
|
}: AppProps<A, S>): JSX.Element => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { screen } from "@testing-library/react"
|
|
2
2
|
|
|
3
|
-
import { renderWithUser } from "../utils/test"
|
|
4
3
|
import CopyIconButton from "./CopyIconButton"
|
|
4
|
+
import { renderWithUser } from "../utils/test"
|
|
5
5
|
|
|
6
6
|
test("Clicking button should copy content", async () => {
|
|
7
7
|
const content = "Example string to be copied."
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ContentCopy as ContentCopyIcon } from "@mui/icons-material"
|
|
2
1
|
import { IconButton, type IconButtonProps } from "@mui/material"
|
|
2
|
+
import { ContentCopy as ContentCopyIcon } from "@mui/icons-material"
|
|
3
3
|
import type { FC } from "react"
|
|
4
4
|
|
|
5
5
|
export interface CopyIconButtonProps extends Omit<IconButtonProps, "onClick"> {
|
|
@@ -15,7 +15,7 @@ const CopyIconButton: FC<CopyIconButtonProps> = ({
|
|
|
15
15
|
<IconButton
|
|
16
16
|
data-testid="copy-icon-button"
|
|
17
17
|
onClick={() => {
|
|
18
|
-
navigator.clipboard.writeText(content)
|
|
18
|
+
void navigator.clipboard.writeText(content)
|
|
19
19
|
}}
|
|
20
20
|
{...otherIconButtonProps}
|
|
21
21
|
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type FC, useState } from "react"
|
|
2
2
|
import { Typography, type TypographyProps } from "@mui/material"
|
|
3
3
|
|
|
4
4
|
import { useCountdown } from "../hooks"
|
|
@@ -9,7 +9,7 @@ export interface CountdownProps extends Omit<TypographyProps, "children"> {
|
|
|
9
9
|
onEnd: () => void
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
const Countdown:
|
|
12
|
+
const Countdown: FC<CountdownProps> = ({
|
|
13
13
|
seconds,
|
|
14
14
|
start = true,
|
|
15
15
|
onEnd,
|
|
@@ -17,7 +17,7 @@ const Countdown: React.FC<CountdownProps> = ({
|
|
|
17
17
|
}) => {
|
|
18
18
|
seconds = Math.floor(seconds)
|
|
19
19
|
const _seconds = useCountdown(seconds)[0]
|
|
20
|
-
const [end, setEnd] =
|
|
20
|
+
const [end, setEnd] = useState(!start)
|
|
21
21
|
|
|
22
22
|
if (_seconds === 0 && !end) {
|
|
23
23
|
setEnd(true)
|
|
@@ -24,7 +24,8 @@ const DownloadFileButton: FC<DownloadFileButtonProps> = ({
|
|
|
24
24
|
let url: undefined | string = undefined
|
|
25
25
|
let anchorProps: undefined | { download?: string; href: string } = undefined
|
|
26
26
|
if ("mimeType" in file) {
|
|
27
|
-
|
|
27
|
+
const { text, mimeType, name, charset = "utf-8" } = file
|
|
28
|
+
let { extension } = file
|
|
28
29
|
|
|
29
30
|
if (!extension) extension = "." + { plain: "txt", csv: "csv" }[mimeType]
|
|
30
31
|
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import React from "react"
|
|
2
1
|
import {
|
|
3
2
|
AppBar,
|
|
4
3
|
type AppBarProps,
|
|
4
|
+
Container,
|
|
5
|
+
type ContainerProps,
|
|
5
6
|
Toolbar,
|
|
6
7
|
type ToolbarProps,
|
|
7
8
|
useScrollTrigger,
|
|
8
|
-
Container,
|
|
9
|
-
type ContainerProps,
|
|
10
9
|
} from "@mui/material"
|
|
10
|
+
import { type FC, cloneElement } from "react"
|
|
11
11
|
|
|
12
12
|
export interface ElevatedAppBarProps extends Omit<AppBarProps, "position"> {
|
|
13
13
|
containerProps: ContainerProps
|
|
14
14
|
toolbarProps?: ToolbarProps
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const ElevatedAppBar:
|
|
17
|
+
const ElevatedAppBar: FC<ElevatedAppBarProps> = ({
|
|
18
18
|
containerProps,
|
|
19
19
|
toolbarProps,
|
|
20
20
|
elevation = 4,
|
|
@@ -26,7 +26,7 @@ const ElevatedAppBar: React.FC<ElevatedAppBarProps> = ({
|
|
|
26
26
|
threshold: 0,
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
-
return
|
|
29
|
+
return cloneElement(
|
|
30
30
|
<AppBar elevation={elevation} {...otherProps}>
|
|
31
31
|
<Container {...containerProps}>
|
|
32
32
|
<Toolbar {...toolbarProps}>{children}</Toolbar>
|
package/src/components/Image.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Box, type BoxProps } from "@mui/material"
|
|
2
|
-
import type
|
|
2
|
+
import { type FC } from "react"
|
|
3
3
|
|
|
4
4
|
import { openInNewTab } from "../utils/general"
|
|
5
5
|
|
|
@@ -10,12 +10,12 @@ export interface ImageProps extends Omit<BoxProps, "component"> {
|
|
|
10
10
|
hrefInNewTab?: boolean
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const Image:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
const Image: FC<ImageProps> = ({ href, hrefInNewTab = false, ...props }) => {
|
|
14
|
+
let {
|
|
15
|
+
onClick,
|
|
16
|
+
style = {},
|
|
17
|
+
...otherProps // eslint-disable-line prefer-const
|
|
18
|
+
} = props
|
|
19
19
|
|
|
20
20
|
if (style.width === undefined) {
|
|
21
21
|
style.width = "100%"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { Button, type ButtonProps } from "@mui/material"
|
|
1
2
|
import {
|
|
2
|
-
type FC,
|
|
3
3
|
type DetailedHTMLProps,
|
|
4
|
+
type FC,
|
|
4
5
|
type InputHTMLAttributes,
|
|
5
6
|
} from "react"
|
|
6
|
-
import { Button, type ButtonProps } from "@mui/material"
|
|
7
7
|
|
|
8
8
|
export interface InputFileButtonProps
|
|
9
9
|
extends Omit<ButtonProps<"label">, "component"> {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FC, type ReactElement } from "react"
|
|
2
2
|
import {
|
|
3
3
|
List,
|
|
4
|
-
type ListProps,
|
|
5
4
|
type ListItem,
|
|
6
5
|
type ListItemText,
|
|
6
|
+
type ListProps,
|
|
7
7
|
} from "@mui/material"
|
|
8
8
|
|
|
9
|
-
type ListItemElement =
|
|
9
|
+
type ListItemElement = ReactElement<typeof ListItem | typeof ListItemText>
|
|
10
10
|
|
|
11
11
|
export interface ItemizedListProps {
|
|
12
12
|
styleType:
|
|
@@ -33,7 +33,7 @@ export interface ItemizedListProps {
|
|
|
33
33
|
children: ListItemElement | ListItemElement[]
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const ItemizedList:
|
|
36
|
+
const ItemizedList: FC<ItemizedListProps> = ({
|
|
37
37
|
styleType,
|
|
38
38
|
listProps = {},
|
|
39
39
|
pl = 4,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FC, type ReactElement } from "react"
|
|
2
2
|
import { Unstable_Grid2 as Grid, type Grid2Props } from "@mui/material"
|
|
3
3
|
|
|
4
4
|
interface ItemProps
|
|
@@ -29,7 +29,7 @@ interface GlobalItemProps extends ItemProps {
|
|
|
29
29
|
export interface OrderedGridProps {
|
|
30
30
|
rows: Array<
|
|
31
31
|
Array<{
|
|
32
|
-
element:
|
|
32
|
+
element: ReactElement
|
|
33
33
|
itemProps?: ItemProps
|
|
34
34
|
}>
|
|
35
35
|
>
|
|
@@ -37,7 +37,7 @@ export interface OrderedGridProps {
|
|
|
37
37
|
globalItemProps: GlobalItemProps
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const OrderedGrid:
|
|
40
|
+
const OrderedGrid: FC<OrderedGridProps> = ({
|
|
41
41
|
rows,
|
|
42
42
|
containerProps = {},
|
|
43
43
|
globalItemProps,
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ElementType,
|
|
3
|
+
type JSX,
|
|
4
|
+
type JSXElementConstructor,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
useEffect,
|
|
7
|
+
} from "react"
|
|
1
8
|
import {
|
|
2
9
|
TablePagination as MuiTablePagination,
|
|
3
10
|
type TablePaginationProps as MuiTablePaginationProps,
|
|
@@ -6,15 +13,9 @@ import {
|
|
|
6
13
|
type TablePaginationBaseProps,
|
|
7
14
|
} from "@mui/material"
|
|
8
15
|
import type { TypedUseLazyQuery } from "@reduxjs/toolkit/query/react"
|
|
9
|
-
import {
|
|
10
|
-
type ElementType,
|
|
11
|
-
type JSXElementConstructor,
|
|
12
|
-
type ReactNode,
|
|
13
|
-
useEffect,
|
|
14
|
-
} from "react"
|
|
15
16
|
|
|
16
|
-
import { type Pagination, usePagination } from "../hooks/api"
|
|
17
17
|
import { type ListArg, type ListResult, handleResultState } from "../utils/api"
|
|
18
|
+
import { type Pagination, usePagination } from "../hooks/api"
|
|
18
19
|
|
|
19
20
|
export type TablePaginationProps<
|
|
20
21
|
QueryArg extends ListArg,
|
|
@@ -83,10 +84,17 @@ const TablePagination = <
|
|
|
83
84
|
|
|
84
85
|
useEffect(
|
|
85
86
|
() => {
|
|
86
|
-
trigger({ limit, offset, ...filters } as QueryArg, preferCacheValue)
|
|
87
|
+
void trigger({ limit, offset, ...filters } as QueryArg, preferCacheValue)
|
|
87
88
|
},
|
|
88
89
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
89
|
-
[
|
|
90
|
+
[
|
|
91
|
+
trigger,
|
|
92
|
+
limit,
|
|
93
|
+
offset,
|
|
94
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps,@typescript-eslint/no-unsafe-assignment
|
|
95
|
+
...Object.values(filters || {}),
|
|
96
|
+
preferCacheValue,
|
|
97
|
+
],
|
|
90
98
|
)
|
|
91
99
|
|
|
92
100
|
const { count, max_limit } = result.data || {}
|
|
@@ -114,11 +122,13 @@ const TablePagination = <
|
|
|
114
122
|
rowsPerPage={limit}
|
|
115
123
|
onRowsPerPageChange={event => {
|
|
116
124
|
setPagination({ limit: parseInt(event.target.value), page: 0 })
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
117
126
|
if (onRowsPerPageChange) onRowsPerPageChange(event)
|
|
118
127
|
}}
|
|
119
128
|
page={page}
|
|
120
129
|
onPageChange={(event, page) => {
|
|
121
130
|
setPagination(({ limit }) => ({ limit, page }))
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
122
132
|
if (onPageChange) onPageChange(event, page)
|
|
123
133
|
}}
|
|
124
134
|
// ascending order
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type React from "react"
|
|
2
1
|
import { Box, type BoxProps } from "@mui/material"
|
|
2
|
+
import { type FC } from "react"
|
|
3
3
|
|
|
4
4
|
export interface YouTubeVideoProps extends Omit<BoxProps, "component"> {
|
|
5
5
|
src: string
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
const YouTubeVideo:
|
|
8
|
+
const YouTubeVideo: FC<YouTubeVideoProps> = ({
|
|
9
9
|
src,
|
|
10
10
|
style = {},
|
|
11
11
|
...otherProps
|