codeforlife 2.6.1

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.
Files changed (147) hide show
  1. package/.eslintrc.json +47 -0
  2. package/.github/workflows/contributing.yaml +8 -0
  3. package/.github/workflows/main.yml +36 -0
  4. package/.prettierignore +5 -0
  5. package/.prettierrc.json +4 -0
  6. package/.vscode/launch.json +22 -0
  7. package/.vscode/settings.json +30 -0
  8. package/CHANGELOG.md +1864 -0
  9. package/CONTRIBUTING.md +3 -0
  10. package/LICENSE.md +3 -0
  11. package/README.md +94 -0
  12. package/codecov.yml +11 -0
  13. package/package.json +139 -0
  14. package/src/api/createApi.ts +84 -0
  15. package/src/api/endpoints/authFactor.ts +31 -0
  16. package/src/api/endpoints/index.ts +9 -0
  17. package/src/api/endpoints/klass.ts +87 -0
  18. package/src/api/endpoints/school.ts +34 -0
  19. package/src/api/endpoints/session.ts +40 -0
  20. package/src/api/endpoints/user.ts +70 -0
  21. package/src/api/index.ts +4 -0
  22. package/src/api/models.ts +144 -0
  23. package/src/api/tagTypes.ts +12 -0
  24. package/src/api/urls.ts +13 -0
  25. package/src/components/App.css +38 -0
  26. package/src/components/App.tsx +150 -0
  27. package/src/components/ClickableTooltip.tsx +43 -0
  28. package/src/components/CopyIconButton.test.tsx +16 -0
  29. package/src/components/CopyIconButton.tsx +27 -0
  30. package/src/components/Countdown.tsx +42 -0
  31. package/src/components/ElevatedAppBar.tsx +41 -0
  32. package/src/components/Image.tsx +41 -0
  33. package/src/components/InputFileButton.tsx +27 -0
  34. package/src/components/ItemizedList.tsx +61 -0
  35. package/src/components/OrderedGrid.tsx +92 -0
  36. package/src/components/ScrollIntoViewLink.tsx +23 -0
  37. package/src/components/SyncError.tsx +14 -0
  38. package/src/components/TablePagination.tsx +132 -0
  39. package/src/components/YouTubeVideo.tsx +26 -0
  40. package/src/components/form/ApiAutocompleteField.tsx +180 -0
  41. package/src/components/form/AutocompleteField.tsx +124 -0
  42. package/src/components/form/CheckboxField.tsx +81 -0
  43. package/src/components/form/CountryField.tsx +68 -0
  44. package/src/components/form/DatePickerField.tsx +119 -0
  45. package/src/components/form/EmailField.tsx +38 -0
  46. package/src/components/form/FirstNameField.tsx +40 -0
  47. package/src/components/form/Form.tsx +82 -0
  48. package/src/components/form/OtpField.tsx +28 -0
  49. package/src/components/form/PasswordField.tsx +71 -0
  50. package/src/components/form/RepeatField.tsx +115 -0
  51. package/src/components/form/SubmitButton.tsx +47 -0
  52. package/src/components/form/TextField.tsx +103 -0
  53. package/src/components/form/UkCountyField.tsx +67 -0
  54. package/src/components/form/index.tsx +28 -0
  55. package/src/components/index.ts +26 -0
  56. package/src/components/page/Banner.tsx +84 -0
  57. package/src/components/page/Notification.tsx +71 -0
  58. package/src/components/page/Page.tsx +73 -0
  59. package/src/components/page/Section.tsx +21 -0
  60. package/src/components/page/TabBar.tsx +131 -0
  61. package/src/components/page/index.ts +10 -0
  62. package/src/components/router/Link.tsx +22 -0
  63. package/src/components/router/LinkButton.tsx +21 -0
  64. package/src/components/router/LinkIconButton.tsx +21 -0
  65. package/src/components/router/LinkListItem.tsx +21 -0
  66. package/src/components/router/LinkTab.tsx +21 -0
  67. package/src/components/router/Navigate.tsx +33 -0
  68. package/src/components/router/index.tsx +12 -0
  69. package/src/components/table/CellStack.tsx +19 -0
  70. package/src/components/table/Table.tsx +55 -0
  71. package/src/components/table/index.tsx +10 -0
  72. package/src/features/InactiveDialog.tsx +40 -0
  73. package/src/features/ScreenTimeDialog.tsx +33 -0
  74. package/src/features/index.ts +4 -0
  75. package/src/fonts/Inter-VariableFont_slnt,wght.ttf +0 -0
  76. package/src/fonts/SpaceGrotesk-VariableFont_wght.ttf +0 -0
  77. package/src/hooks/api.tsx +37 -0
  78. package/src/hooks/auth.tsx +87 -0
  79. package/src/hooks/general.ts +110 -0
  80. package/src/hooks/index.ts +4 -0
  81. package/src/hooks/router.tsx +168 -0
  82. package/src/index.ts +2 -0
  83. package/src/middlewares/index.ts +1 -0
  84. package/src/middlewares/session.ts +16 -0
  85. package/src/public/images/brain.svg +1 -0
  86. package/src/schemas/user.ts +4 -0
  87. package/src/scripts/freshDesk.js +473 -0
  88. package/src/scripts/index.ts +1 -0
  89. package/src/server.js +181 -0
  90. package/src/settings/custom.ts +22 -0
  91. package/src/settings/index.ts +5 -0
  92. package/src/settings/vite.ts +26 -0
  93. package/src/setupTests.ts +1 -0
  94. package/src/slices/createSlice.ts +8 -0
  95. package/src/slices/index.ts +2 -0
  96. package/src/slices/session.ts +32 -0
  97. package/src/theme/ThemedBox.tsx +265 -0
  98. package/src/theme/colors.ts +57 -0
  99. package/src/theme/components/MuiAccordion.tsx +13 -0
  100. package/src/theme/components/MuiAutocomplete.tsx +11 -0
  101. package/src/theme/components/MuiButton.ts +70 -0
  102. package/src/theme/components/MuiCardActions.tsx +12 -0
  103. package/src/theme/components/MuiCheckbox.ts +12 -0
  104. package/src/theme/components/MuiContainer.ts +19 -0
  105. package/src/theme/components/MuiDialog.tsx +16 -0
  106. package/src/theme/components/MuiFormControlLabel.ts +18 -0
  107. package/src/theme/components/MuiFormHelperText.ts +12 -0
  108. package/src/theme/components/MuiGrid2.ts +16 -0
  109. package/src/theme/components/MuiInputBase.ts +14 -0
  110. package/src/theme/components/MuiLink.ts +41 -0
  111. package/src/theme/components/MuiList.ts +12 -0
  112. package/src/theme/components/MuiListItemText.ts +18 -0
  113. package/src/theme/components/MuiMenu.ts +14 -0
  114. package/src/theme/components/MuiMenuItem.ts +15 -0
  115. package/src/theme/components/MuiSelect.ts +16 -0
  116. package/src/theme/components/MuiTab.ts +29 -0
  117. package/src/theme/components/MuiTable.ts +29 -0
  118. package/src/theme/components/MuiTableBody.ts +15 -0
  119. package/src/theme/components/MuiTableHead.ts +26 -0
  120. package/src/theme/components/MuiTabs.ts +26 -0
  121. package/src/theme/components/MuiTextField.ts +86 -0
  122. package/src/theme/components/MuiToolbar.ts +11 -0
  123. package/src/theme/components/MuiTypography.ts +12 -0
  124. package/src/theme/components/_components.ts +93 -0
  125. package/src/theme/components/index.ts +57 -0
  126. package/src/theme/index.ts +25 -0
  127. package/src/theme/palette.ts +98 -0
  128. package/src/theme/spacing.ts +8 -0
  129. package/src/theme/typography.ts +101 -0
  130. package/src/utils/api.test.ts +19 -0
  131. package/src/utils/api.tsx +327 -0
  132. package/src/utils/auth.ts +17 -0
  133. package/src/utils/form.ts +153 -0
  134. package/src/utils/general.test.ts +42 -0
  135. package/src/utils/general.ts +498 -0
  136. package/src/utils/router.test.ts +156 -0
  137. package/src/utils/router.ts +67 -0
  138. package/src/utils/schema.ts +80 -0
  139. package/src/utils/store.ts +31 -0
  140. package/src/utils/test.tsx +82 -0
  141. package/src/utils/theme.tsx +82 -0
  142. package/src/utils/window.ts +9 -0
  143. package/src/vite-env.d.ts +1 -0
  144. package/tsconfig.json +31 -0
  145. package/tsconfig.node.json +11 -0
  146. package/types/fixes.d.ts +18 -0
  147. package/vite.config.ts +21 -0
@@ -0,0 +1,3 @@
1
+ # Contributing
2
+
3
+ Find our contribution agreement [here](https://github.com/ocadotechnology/codeforlife-workspace/blob/main/CONTRIBUTING.md).
package/LICENSE.md ADDED
@@ -0,0 +1,3 @@
1
+ # License
2
+
3
+ Find our license [here](https://github.com/ocadotechnology/codeforlife-workspace/blob/main/LICENSE.md).
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # codeforlife-package-javascript
2
+
3
+ This repo hosts Code for Life's Node.js package. This package contains all
4
+ reusable frontend code, meant to be installed across CFL's various frontend
5
+ services.
6
+
7
+ ## LICENCE
8
+ In accordance with the [Terms of Use](https://www.codeforlife.education/terms#terms)
9
+ of the Code for Life website, all copyright, trademarks, and other
10
+ intellectual property rights in and relating to Code for Life (including all
11
+ content of the Code for Life website, the Rapid Router application, the
12
+ Kurono application, related software (including any drawn and/or animated
13
+ avatars, whether or not such avatars have any modifications) and any other
14
+ games, applications or any other content that we make available from time to
15
+ time) are owned by Ocado Innovation Limited.
16
+
17
+ The source code of the Code for Life portal, the Rapid Router application
18
+ and the Kurono/aimmo application are [licensed under the GNU Affero General
19
+ Public License](https://github.com/ocadotechnology/codeforlife-workspace/blob/main/LICENSE.md).
20
+ All other assets including images, logos, sounds etc., are not covered by
21
+ this licence and no-one may copy, modify, distribute, show in public or
22
+ create any derivative work from these assets.
23
+
24
+ ## Installation
25
+
26
+ To install this package, do one of the following options.
27
+
28
+ *Remember to replace the version number ("0.0.0") with your
29
+ [desired version](https://github.com/ocadotechnology/codeforlife-package-javascript/releases).*
30
+
31
+ **Option 1:** Run `yarn install` command:
32
+
33
+ ```bash
34
+ yarn install git+https://github.com/ocadotechnology/codeforlife-package-javascript.git#v0.0.0
35
+ ```
36
+
37
+ **Option 2:** add the following to `package.json`:
38
+
39
+ ```json
40
+ {
41
+ "dependencies": {
42
+ "codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v0.0.0"
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Making Changes
48
+
49
+ To make changes, you must:
50
+
51
+ 1. Branch off of main.
52
+ 1. Push your changes on your branch.
53
+ 1. Ensure the pipeline runs successfully on your branch.
54
+ 1. Have your changes reviewed and approved by a peer.
55
+ 1. Merge your branch into the `main` branch.
56
+ 1. [Manually trigger](https://github.com/ocadotechnology/codeforlife-package-javascript/actions/workflows/main.yml)
57
+ the `Main` pipeline for the `main` branch.
58
+
59
+ ### Installing your branch
60
+
61
+ You may wish to install and integrate your changes into a CFL frontend before
62
+ it's been peer-reviewed.
63
+
64
+ *Remember to replace the branch name ("my-branch") with your
65
+ [branch](https://github.com/ocadotechnology/codeforlife-package-javascript/branches)*.
66
+
67
+ ```json
68
+ {
69
+ "dependencies": {
70
+ "codeforlife": "github:ocadotechnology/codeforlife-package-javascript#my-branch"
71
+ }
72
+ }
73
+ ```
74
+
75
+ ## Pipeline
76
+
77
+ When pushing to any branch, the pipeline will:
78
+
79
+ 1. Check the code for linting errors.
80
+ 1. Run tests on the React components.
81
+ 1. Build the package.
82
+ 1. Save the build to the `lib` directory.
83
+
84
+ When merging to the `main` branch, the pipeline will:
85
+
86
+ 1. Update the package version in
87
+ [package.json](https://github.com/ocadotechnology/codeforlife-package-javascript/blob/main/package.json).
88
+ 1. Update
89
+ [CHANGELOG.md](https://github.com/ocadotechnology/codeforlife-package-javascript/blob/main/CHANGELOG.md)
90
+ with latest commit messages.
91
+ 1. Determine the next version number from the commit messages using
92
+ [semantic versioning](https://semver.org/).
93
+ 1. Release a new version
94
+ [on GitHub](https://github.com/ocadotechnology/codeforlife-package-javascript/releases).
package/codecov.yml ADDED
@@ -0,0 +1,11 @@
1
+ coverage: # https://docs.codecov.com/docs/codecov-yaml
2
+ precision: 2
3
+ round: down
4
+ range: 90...90
5
+ status: # https://docs.codecov.com/docs/commit-status
6
+ project:
7
+ default:
8
+ target: 90%
9
+ threshold: 0%
10
+
11
+ comment: false
package/package.json ADDED
@@ -0,0 +1,139 @@
1
+ {
2
+ "//": [
3
+ "Based off of:",
4
+ "https://github.com/vitejs/vite/blob/main/packages/create-vite/template-react-ts/package.json",
5
+ "Dependency rules:",
6
+ "`peerDependencies` should contain everything required to build and test a",
7
+ "service's front end.",
8
+ "TODO: make devDependencies the same as peerDependencies"
9
+ ],
10
+ "name": "codeforlife",
11
+ "description": "Common frontend code",
12
+ "private": false,
13
+ "version": "2.6.1",
14
+ "type": "module",
15
+ "scripts": {
16
+ "dev": "vite",
17
+ "start": "serve -s dist",
18
+ "build": "tsc && vite build",
19
+ "preview": "vite preview",
20
+ "test": "vitest run",
21
+ "test:coverage": "vitest run --coverage",
22
+ "test:verbose": "vitest run --reporter=verbose --coverage.thresholds.lines=90 --coverage.thresholds.functions=90 --coverage.thresholds.branches=90 --coverage.thresholds.statements=90",
23
+ "test:ui": "vitest --ui",
24
+ "format": "prettier --write .",
25
+ "format:check": "prettier --check --write=false .",
26
+ "lint": "eslint --max-warnings=0 .",
27
+ "lint:fix": "eslint --fix .",
28
+ "type-check": "tsc --noEmit"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/ocadotechnology/codeforlife-package-javascript.git"
33
+ },
34
+ "author": "Ocado",
35
+ "license": "ISC",
36
+ "bugs": {
37
+ "url": "https://github.com/ocadotechnology/codeforlife-package-javascript/issues"
38
+ },
39
+ "homepage": "https://github.com/ocadotechnology/codeforlife-package-javascript#readme",
40
+ "dependencies": {
41
+ "@emotion/react": "^11.10.6",
42
+ "@emotion/styled": "^11.10.6",
43
+ "@mui/icons-material": "^5.11.11",
44
+ "@mui/material": "^5.11.12",
45
+ "@mui/x-date-pickers": "^7.7.1",
46
+ "@reduxjs/toolkit": "^2.0.1",
47
+ "compression": "^1.7.5",
48
+ "dayjs": "^1.11.11",
49
+ "express": "^4.21.2",
50
+ "formik": "^2.2.9",
51
+ "js-cookie": "^3.0.5",
52
+ "memory-cache": "^0.2.0",
53
+ "qs": "^6.11.2",
54
+ "react": "^18.2.0",
55
+ "react-dom": "^18.2.0",
56
+ "react-redux": "^9.1.0",
57
+ "react-router-dom": "^6.23.1",
58
+ "serve": "^14.2.3",
59
+ "sirv": "^3.0.0",
60
+ "yup": "^1.1.1"
61
+ },
62
+ "devDependencies": {
63
+ "@testing-library/dom": "^9.3.4",
64
+ "@testing-library/jest-dom": "^6.2.0",
65
+ "@testing-library/react": "^14.1.2",
66
+ "@testing-library/user-event": "^14.5.2",
67
+ "@types/express": "^5.0.0",
68
+ "@types/js-cookie": "^3.0.3",
69
+ "@types/node": "^20.14.2",
70
+ "@types/qs": "^6.9.7",
71
+ "@types/react": "^18.2.47",
72
+ "@types/react-dom": "^18.2.18",
73
+ "@vitejs/plugin-react": "^4.2.1",
74
+ "@vitest/coverage-istanbul": "^1.6.0",
75
+ "@vitest/ui": "^1.6.0",
76
+ "eslint": "^8.56.0",
77
+ "eslint-config-prettier": "^9.1.0",
78
+ "eslint-config-react-app": "^7.0.1",
79
+ "eslint-plugin-prettier": "^5.1.3",
80
+ "jsdom": "^23.2.0",
81
+ "prettier": "^3.2.1",
82
+ "typescript": "^5.3.3",
83
+ "vite": "^5.0.11",
84
+ "vitest": "^1.2.0"
85
+ },
86
+ "peerDependencies": {
87
+ "@eslint/js": "^9.9.0",
88
+ "@testing-library/dom": "^9.3.4",
89
+ "@testing-library/jest-dom": "^6.2.0",
90
+ "@testing-library/react": "^14.1.2",
91
+ "@testing-library/user-event": "^14.5.2",
92
+ "@types/express": "^5.0.0",
93
+ "@types/jest": "^29.5.12",
94
+ "@types/js-cookie": "^3.0.3",
95
+ "@types/node": "^20.14.2",
96
+ "@types/qs": "^6.9.7",
97
+ "@types/react": "^18.2.47",
98
+ "@types/react-dom": "^18.2.18",
99
+ "@vitejs/plugin-react": "^4.2.1",
100
+ "@vitest/coverage-istanbul": "^1.6.0",
101
+ "@vitest/ui": "^1.6.0",
102
+ "eslint": "^8.56.0",
103
+ "eslint-config-prettier": "^9.1.0",
104
+ "eslint-config-react-app": "^7.0.1",
105
+ "eslint-plugin-prettier": "^5.1.3",
106
+ "eslint-plugin-react": "^7.35.0",
107
+ "eslint-plugin-react-hooks": "^4.6.2",
108
+ "eslint-plugin-react-refresh": "^0.4.9",
109
+ "globals": "^15.9.0",
110
+ "jsdom": "^23.2.0",
111
+ "prettier": "^3.2.1",
112
+ "typescript": "^5.3.3",
113
+ "typescript-eslint": "^8.1.0",
114
+ "vite": "^5.0.11",
115
+ "vitest": "^1.2.0"
116
+ },
117
+ "release": {
118
+ "branches": [
119
+ "main"
120
+ ],
121
+ "plugins": [
122
+ "@semantic-release/commit-analyzer",
123
+ "@semantic-release/release-notes-generator",
124
+ "@semantic-release/changelog",
125
+ "@semantic-release/npm",
126
+ [
127
+ "@semantic-release/git",
128
+ {
129
+ "assets": [
130
+ "package.json",
131
+ "CHANGELOG.md"
132
+ ],
133
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
134
+ }
135
+ ],
136
+ "@semantic-release/github"
137
+ ]
138
+ }
139
+ }
@@ -0,0 +1,84 @@
1
+ import {
2
+ createApi as _createApi,
3
+ fetchBaseQuery,
4
+ } from "@reduxjs/toolkit/query/react"
5
+
6
+ import { SERVICE_API_URL } from "../settings"
7
+ import defaultTagTypes from "./tagTypes"
8
+ import { buildLogoutEndpoint } from "./endpoints/session"
9
+ import { getCsrfCookie } from "../utils/auth"
10
+
11
+ // TODO: decide if we want to keep any of this.
12
+ // export function handleResponseError(error: FetchBaseQueryError): void {
13
+ // if (
14
+ // error.status === 400 &&
15
+ // typeof error.data === "object" &&
16
+ // error.data !== null
17
+ // ) {
18
+ // // Parse the error's data from snake_case to camelCase.
19
+ // snakeCaseToCamelCase(error.data)
20
+ // } else if (error.status === 401) {
21
+ // // TODO: redirect to appropriate login page based on user type.
22
+ // window.location.href = `${PORTAL_BASE_URL}/login/teacher`
23
+ // } else {
24
+ // // Catch-all error pages by status-code.
25
+ // window.location.href = `${PORTAL_BASE_URL}/error/${
26
+ // [403, 404].includes(error.status as number) ? error.status : 500
27
+ // }`
28
+ // }
29
+ // }
30
+
31
+ export default function createApi<TagTypes extends string = never>({
32
+ tagTypes = [],
33
+ }: {
34
+ tagTypes?: readonly TagTypes[]
35
+ } = {}) {
36
+ const fetch = fetchBaseQuery({
37
+ baseUrl: `${SERVICE_API_URL}/`,
38
+ credentials: "include",
39
+ prepareHeaders: (headers, { type }) => {
40
+ if (type === "mutation") {
41
+ let csrfToken = getCsrfCookie()
42
+ if (csrfToken) headers.set("x-csrftoken", csrfToken)
43
+ }
44
+
45
+ return headers
46
+ },
47
+ })
48
+
49
+ const api = _createApi({
50
+ // https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#implementing-a-custom-basequery
51
+ baseQuery: async (args, api, extraOptions) => {
52
+ if (api.type === "mutation" && getCsrfCookie() === undefined) {
53
+ // Get the CSRF token.
54
+ const { error } = await fetch(
55
+ { url: "/csrf/cookie", method: "GET" },
56
+ api,
57
+ {},
58
+ )
59
+
60
+ // Validate we got the CSRF token.
61
+ if (error !== undefined) {
62
+ console.error(error)
63
+ // TODO
64
+ // window.location.href = `${PORTAL_BASE_URL}/error/500`
65
+ }
66
+ if (getCsrfCookie() === undefined) {
67
+ // TODO
68
+ // window.location.href = `${PORTAL_BASE_URL}/error/500`
69
+ }
70
+ }
71
+
72
+ // Send the HTTP request and fetch the response.
73
+ return await fetch(args, api, extraOptions)
74
+ },
75
+ tagTypes: [...defaultTagTypes, ...tagTypes],
76
+ endpoints: () => ({}),
77
+ })
78
+
79
+ return api.injectEndpoints({
80
+ endpoints: build => ({
81
+ logout: buildLogoutEndpoint<null, null>(api, build),
82
+ }),
83
+ })
84
+ }
@@ -0,0 +1,31 @@
1
+ import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
2
+
3
+ import {
4
+ buildUrl,
5
+ tagData,
6
+ type ListArg as _ListArg,
7
+ type ListResult as _ListResult,
8
+ } from "../../utils/api"
9
+ import type { AuthFactor } from "../models"
10
+ import { type TagTypes } from "../tagTypes"
11
+ import urls from "../urls"
12
+
13
+ export const AUTH_FACTOR_TAG: TagTypes = "AuthFactor"
14
+
15
+ export type ListAuthFactorsResult = _ListResult<AuthFactor, "type">
16
+ export type ListAuthFactorsArg = _ListArg
17
+
18
+ export default function getReadAuthFactorEndpoints<
19
+ ListResult extends _ListResult<AuthFactor> = ListAuthFactorsResult,
20
+ ListArg extends _ListArg<AuthFactor> = ListAuthFactorsArg,
21
+ >(build: EndpointBuilder<any, any, any>) {
22
+ return {
23
+ listAuthFactors: build.query<ListResult, ListArg>({
24
+ query: search => ({
25
+ url: buildUrl(urls.authFactor.list, { search }),
26
+ method: "GET",
27
+ }),
28
+ providesTags: tagData(AUTH_FACTOR_TAG, { includeListTag: true }),
29
+ }),
30
+ }
31
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./authFactor"
2
+ export { default as getReadAuthFactorEndpoints } from "./authFactor"
3
+ export * from "./klass"
4
+ export { default as getReadClassEndpoints } from "./klass"
5
+ export * from "./school"
6
+ export { default as getReadSchoolEndpoints } from "./school"
7
+ export * from "./session"
8
+ export * from "./user"
9
+ export { default as getReadUserEndpoints } from "./user"
@@ -0,0 +1,87 @@
1
+ import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
2
+
3
+ import {
4
+ buildUrl,
5
+ tagData,
6
+ type ListArg as _ListArg,
7
+ type ListResult as _ListResult,
8
+ type RetrieveArg as _RetrieveArg,
9
+ type RetrieveResult as _RetrieveResult,
10
+ } from "../../utils/api"
11
+ import type {
12
+ Class,
13
+ Teacher,
14
+ SchoolTeacher,
15
+ SchoolTeacherUser,
16
+ } from "../models"
17
+ import { type TagTypes } from "../tagTypes"
18
+ import urls from "../urls"
19
+
20
+ export const CLASS_TAG: TagTypes = "Class"
21
+
22
+ export type RetrieveClassResult = _RetrieveResult<
23
+ Class,
24
+ "name" | "read_classmates_data" | "receive_requests_until" | "school"
25
+ > & {
26
+ teacher: SchoolTeacher & {
27
+ user: Pick<
28
+ SchoolTeacherUser,
29
+ | "id"
30
+ | "first_name"
31
+ | "last_name"
32
+ | "email"
33
+ | "is_active"
34
+ | "date_joined"
35
+ | "requesting_to_join_class"
36
+ >
37
+ }
38
+ }
39
+ export type RetrieveClassArg = _RetrieveArg<Class>
40
+
41
+ export type ListClassesResult = _ListResult<
42
+ Class,
43
+ "name" | "read_classmates_data" | "receive_requests_until" | "school",
44
+ {
45
+ teacher: SchoolTeacher & {
46
+ user: Pick<
47
+ SchoolTeacherUser,
48
+ | "id"
49
+ | "first_name"
50
+ | "last_name"
51
+ | "email"
52
+ | "is_active"
53
+ | "date_joined"
54
+ | "requesting_to_join_class"
55
+ >
56
+ }
57
+ }
58
+ >
59
+ export type ListClassesArg = _ListArg<{
60
+ teacher: Teacher["id"]
61
+ _id: Class["id"] | Class["id"][]
62
+ id_or_name: string
63
+ }>
64
+
65
+ export default function getReadClassEndpoints<
66
+ RetrieveResult extends _RetrieveResult<Class> = RetrieveClassResult,
67
+ RetrieveArg extends _RetrieveArg<Class> = RetrieveClassArg,
68
+ ListResult extends _ListResult<Class> = ListClassesResult,
69
+ ListArg extends _ListArg<Class> = ListClassesArg,
70
+ >(build: EndpointBuilder<any, any, any>) {
71
+ return {
72
+ retrieveClass: build.query<RetrieveResult, RetrieveArg>({
73
+ query: id => ({
74
+ url: buildUrl(urls.class.detail, { url: { id } }),
75
+ method: "GET",
76
+ }),
77
+ providesTags: tagData(CLASS_TAG),
78
+ }),
79
+ listClasses: build.query<ListResult, ListArg>({
80
+ query: search => ({
81
+ url: buildUrl(urls.class.list, { search }),
82
+ method: "GET",
83
+ }),
84
+ providesTags: tagData(CLASS_TAG, { includeListTag: true }),
85
+ }),
86
+ }
87
+ }
@@ -0,0 +1,34 @@
1
+ import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
2
+
3
+ import {
4
+ buildUrl,
5
+ tagData,
6
+ type RetrieveArg as _RetrieveArg,
7
+ type RetrieveResult as _RetrieveResult,
8
+ } from "../../utils/api"
9
+ import type { School } from "../models"
10
+ import { type TagTypes } from "../tagTypes"
11
+ import urls from "../urls"
12
+
13
+ export const SCHOOL_TAG: TagTypes = "School"
14
+
15
+ export type RetrieveSchoolResult = _RetrieveResult<
16
+ School,
17
+ "name" | "country" | "uk_county"
18
+ >
19
+ export type RetrieveSchoolArg = _RetrieveArg<School>
20
+
21
+ export default function getReadSchoolEndpoints<
22
+ RetrieveResult extends _RetrieveResult<School> = RetrieveSchoolResult,
23
+ RetrieveArg extends _RetrieveArg<School> = RetrieveSchoolArg,
24
+ >(build: EndpointBuilder<any, any, any>) {
25
+ return {
26
+ retrieveSchool: build.query<RetrieveResult, RetrieveArg>({
27
+ query: id => ({
28
+ url: buildUrl(urls.school.detail, { url: { id } }),
29
+ method: "GET",
30
+ }),
31
+ providesTags: tagData(SCHOOL_TAG),
32
+ }),
33
+ }
34
+ }
@@ -0,0 +1,40 @@
1
+ import { type EndpointBuilder, type Api } from "@reduxjs/toolkit/query/react"
2
+
3
+ import { login, logout } from "../../slices/session"
4
+
5
+ export function buildLoginEndpoint<ResultType, QueryArg>(
6
+ build: EndpointBuilder<any, any, any>,
7
+ url: string = "session/login/",
8
+ ) {
9
+ return build.mutation<ResultType, QueryArg>({
10
+ query: body => ({ url, method: "POST", body }),
11
+ async onQueryStarted(_, { dispatch, queryFulfilled }) {
12
+ try {
13
+ await queryFulfilled
14
+ dispatch(login())
15
+ } catch (error) {
16
+ console.error("Failed to call login endpoint...", error)
17
+ }
18
+ },
19
+ })
20
+ }
21
+
22
+ export function buildLogoutEndpoint<ResultType, QueryArg>(
23
+ api: Api<any, any, any, any, any>,
24
+ build: EndpointBuilder<any, any, any>,
25
+ url: string = "session/logout/",
26
+ ) {
27
+ return build.mutation<ResultType, QueryArg>({
28
+ query: () => ({ url, method: "POST" }),
29
+ async onQueryStarted(_, { dispatch, queryFulfilled }) {
30
+ try {
31
+ await queryFulfilled
32
+ } catch (error) {
33
+ console.error("Failed to call logout endpoint...", error)
34
+ } finally {
35
+ dispatch(logout())
36
+ dispatch(api.util.resetApiState())
37
+ }
38
+ },
39
+ })
40
+ }
@@ -0,0 +1,70 @@
1
+ import { type EndpointBuilder } from "@reduxjs/toolkit/query/react"
2
+
3
+ import {
4
+ buildUrl,
5
+ tagData,
6
+ type ListArg as _ListArg,
7
+ type ListResult as _ListResult,
8
+ type RetrieveArg as _RetrieveArg,
9
+ type RetrieveResult as _RetrieveResult,
10
+ } from "../../utils/api"
11
+ import type { Class, User } from "../models"
12
+ import { type TagTypes } from "../tagTypes"
13
+ import urls from "../urls"
14
+
15
+ export const USER_TAG: TagTypes = "User"
16
+
17
+ export type RetrieveUserResult = _RetrieveResult<
18
+ User,
19
+ | "first_name"
20
+ | "last_name"
21
+ | "email"
22
+ | "is_active"
23
+ | "date_joined"
24
+ | "requesting_to_join_class"
25
+ | "student"
26
+ | "teacher"
27
+ >
28
+ export type RetrieveUserArg = _RetrieveArg<User>
29
+
30
+ export type ListUsersResult = _ListResult<
31
+ User,
32
+ | "first_name"
33
+ | "last_name"
34
+ | "email"
35
+ | "is_active"
36
+ | "date_joined"
37
+ | "requesting_to_join_class"
38
+ | "student"
39
+ | "teacher"
40
+ >
41
+ export type ListUsersArg = _ListArg<{
42
+ students_in_class: Class["id"]
43
+ _id: User["id"] | User["id"][]
44
+ name: string
45
+ type: "teacher" | "student" | "independent" | "indy"
46
+ }>
47
+
48
+ export default function getReadUserEndpoints<
49
+ RetrieveResult extends _RetrieveResult<User> = RetrieveUserResult,
50
+ RetrieveArg extends _RetrieveArg<User> = RetrieveUserArg,
51
+ ListResult extends _ListResult<User> = ListUsersResult,
52
+ ListArg extends _ListArg<User> = ListUsersArg,
53
+ >(build: EndpointBuilder<any, any, any>) {
54
+ return {
55
+ retrieveUser: build.query<RetrieveResult, RetrieveArg>({
56
+ query: id => ({
57
+ url: buildUrl(urls.user.detail, { url: { id } }),
58
+ method: "GET",
59
+ }),
60
+ providesTags: tagData(USER_TAG),
61
+ }),
62
+ listUsers: build.query<ListResult, ListArg>({
63
+ query: search => ({
64
+ url: buildUrl(urls.user.list, { search }),
65
+ method: "GET",
66
+ }),
67
+ providesTags: tagData(USER_TAG, { includeListTag: true }),
68
+ }),
69
+ }
70
+ }
@@ -0,0 +1,4 @@
1
+ export { default as createApi } from "./createApi"
2
+ export * from "./models"
3
+ export { default as tagTypes } from "./tagTypes"
4
+ export { default as urls } from "./urls"