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.
Files changed (100) hide show
  1. package/.github/workflows/main.yml +0 -3
  2. package/CHANGELOG.md +14 -0
  3. package/eslint.config.js +17 -0
  4. package/package.json +45 -24
  5. package/src/api/createApi.ts +4 -4
  6. package/src/api/endpoints/authFactor.ts +2 -2
  7. package/src/api/endpoints/klass.ts +8 -8
  8. package/src/api/endpoints/school.ts +2 -2
  9. package/src/api/endpoints/session.ts +2 -1
  10. package/src/api/endpoints/user.ts +3 -3
  11. package/src/api/models.ts +1 -1
  12. package/src/api/schemas.ts +16 -16
  13. package/src/components/App.tsx +7 -5
  14. package/src/components/CopyIconButton.test.tsx +1 -1
  15. package/src/components/CopyIconButton.tsx +2 -2
  16. package/src/components/Countdown.tsx +3 -3
  17. package/src/components/DownloadFileButton.tsx +2 -1
  18. package/src/components/ElevatedAppBar.tsx +5 -5
  19. package/src/components/Image.tsx +7 -7
  20. package/src/components/InputFileButton.tsx +2 -2
  21. package/src/components/ItemizedList.tsx +4 -4
  22. package/src/components/OrderedGrid.tsx +3 -3
  23. package/src/components/ScrollIntoViewLink.tsx +1 -2
  24. package/src/components/SyncError.tsx +1 -1
  25. package/src/components/TablePagination.tsx +19 -9
  26. package/src/components/YouTubeVideo.tsx +2 -2
  27. package/src/components/form/ApiAutocompleteField.tsx +48 -41
  28. package/src/components/form/AutocompleteField.tsx +22 -11
  29. package/src/components/form/CheckboxField.tsx +14 -9
  30. package/src/components/form/CountryField.tsx +5 -4
  31. package/src/components/form/DatePickerField.tsx +18 -11
  32. package/src/components/form/EmailField.tsx +1 -1
  33. package/src/components/form/FirstNameField.tsx +2 -2
  34. package/src/components/form/Form.tsx +13 -12
  35. package/src/components/form/PasswordField.tsx +2 -2
  36. package/src/components/form/RepeatField.tsx +18 -10
  37. package/src/components/form/SubmitButton.tsx +14 -10
  38. package/src/components/form/TextField.tsx +17 -11
  39. package/src/components/form/UkCountyField.tsx +3 -2
  40. package/src/components/form/index.tsx +35 -28
  41. package/src/components/page/Banner.tsx +3 -3
  42. package/src/components/page/Notification.tsx +3 -3
  43. package/src/components/page/Page.tsx +5 -5
  44. package/src/components/page/Section.tsx +1 -1
  45. package/src/components/page/TabBar.tsx +5 -5
  46. package/src/components/router/Link.tsx +2 -1
  47. package/src/components/router/LinkButton.tsx +1 -0
  48. package/src/components/router/LinkIconButton.tsx +1 -0
  49. package/src/components/router/LinkListItem.tsx +1 -0
  50. package/src/components/router/LinkTab.tsx +1 -0
  51. package/src/components/router/Navigate.tsx +2 -2
  52. package/src/components/router/index.tsx +9 -12
  53. package/src/components/table/CellStack.tsx +2 -2
  54. package/src/components/table/index.tsx +2 -4
  55. package/src/features/InactiveDialog.tsx +2 -2
  56. package/src/features/ScreenTimeDialog.tsx +3 -6
  57. package/src/hooks/api.tsx +4 -2
  58. package/src/hooks/auth.tsx +29 -16
  59. package/src/hooks/{general.ts → general.tsx} +3 -3
  60. package/src/hooks/router.tsx +9 -9
  61. package/src/middlewares/session.ts +15 -10
  62. package/src/settings/index.ts +3 -6
  63. package/src/setupTests.ts +1 -0
  64. package/src/theme/ThemedBox.tsx +9 -9
  65. package/src/theme/components/MuiButton.ts +1 -1
  66. package/src/theme/components/MuiCardActions.tsx +1 -1
  67. package/src/theme/components/MuiContainer.ts +1 -1
  68. package/src/theme/components/MuiFormControlLabel.ts +1 -1
  69. package/src/theme/components/MuiFormHelperText.ts +1 -1
  70. package/src/theme/components/MuiInputBase.ts +1 -1
  71. package/src/theme/components/MuiLink.ts +1 -1
  72. package/src/theme/components/MuiListItemText.ts +1 -1
  73. package/src/theme/components/MuiMenuItem.ts +1 -1
  74. package/src/theme/components/MuiSelect.ts +2 -2
  75. package/src/theme/components/MuiTable.ts +1 -1
  76. package/src/theme/components/MuiTableBody.ts +1 -1
  77. package/src/theme/components/MuiTableHead.ts +2 -2
  78. package/src/theme/components/MuiTextField.ts +3 -3
  79. package/src/theme/components/_components.ts +4 -2
  80. package/src/theme/palette.ts +2 -2
  81. package/src/theme/typography.ts +1 -1
  82. package/src/utils/api.tsx +6 -4
  83. package/src/utils/auth.ts +1 -1
  84. package/src/utils/form.test.ts +1 -1
  85. package/src/utils/form.ts +14 -9
  86. package/src/utils/general.test.ts +7 -7
  87. package/src/utils/general.ts +10 -12
  88. package/src/utils/router.test.ts +1 -1
  89. package/src/utils/router.ts +2 -2
  90. package/src/utils/schema.ts +11 -11
  91. package/src/utils/test.tsx +2 -2
  92. package/src/utils/theme.tsx +7 -6
  93. package/src/utils/window.ts +2 -0
  94. package/tsconfig.app.json +4 -0
  95. package/tsconfig.json +4 -28
  96. package/tsconfig.node.json +3 -10
  97. package/vite.config.ts +1 -1
  98. package/.eslintrc.json +0 -47
  99. package/src/vite.config.ts +0 -49
  100. /package/src/{public/images → images/svg}/brain.svg +0 -0
@@ -1,20 +1,23 @@
1
- import { Button, CircularProgress, type ChipTypeMap } from "@mui/material"
2
- import type { TypedUseLazyQuery } from "@reduxjs/toolkit/query/react"
1
+ import { Button, type ChipTypeMap, CircularProgress } from "@mui/material"
3
2
  import {
4
3
  Children,
4
+ type ElementType,
5
+ type ForwardRefRenderFunction,
6
+ type HTMLAttributes,
7
+ type JSX,
5
8
  forwardRef,
6
9
  useEffect,
7
10
  useState,
8
- type ElementType,
9
11
  } from "react"
12
+ import type { TypedUseLazyQuery } from "@reduxjs/toolkit/query/react"
10
13
 
11
14
  import {
12
15
  AutocompleteField,
13
16
  type AutocompleteFieldProps,
14
17
  } from "../../components/form"
15
- import { usePagination } from "../../hooks/api"
16
18
  import type { ListArg, ListResult, ModelId } from "../../utils/api"
17
19
  import SyncError from "../SyncError"
20
+ import { usePagination } from "../../hooks/api"
18
21
 
19
22
  export interface ApiAutocompleteFieldProps<
20
23
  SearchKey extends keyof Omit<QueryArg, "limit" | "offset">,
@@ -62,7 +65,7 @@ const ApiAutocompleteField = <
62
65
  useLazyListQuery,
63
66
  filterOptions,
64
67
  getOptionLabel,
65
- getOptionKey = result => result.id,
68
+ getOptionKey = result => result.id as ModelId,
66
69
  searchKey,
67
70
  ...otherAutocompleteFieldProps
68
71
  }: ApiAutocompleteFieldProps<
@@ -88,7 +91,7 @@ const ApiAutocompleteField = <
88
91
  useEffect(
89
92
  () => {
90
93
  const arg = { limit, offset, ...filterOptions } as QueryArg
91
- // @ts-expect-error
94
+ // @ts-expect-error search key can index arg
92
95
  if (search) arg[searchKey] = search
93
96
 
94
97
  trigger(arg, true)
@@ -130,6 +133,44 @@ const ApiAutocompleteField = <
130
133
  setPagination(({ page, limit }) => ({ page: page + 1, limit }))
131
134
  }
132
135
 
136
+ const ListboxComponent: ForwardRefRenderFunction<
137
+ unknown,
138
+ HTMLAttributes<HTMLElement>
139
+ > = ({ children, ...props }, ref) => {
140
+ const listItems = Children.toArray(children)
141
+ if (isLoading) listItems.push(<CircularProgress key="is-loading" />)
142
+ else {
143
+ if (isError) listItems.push(<SyncError key="is-error" />)
144
+ if (hasMore) {
145
+ listItems.push(
146
+ <Button key="load-more" onClick={loadNextPage}>
147
+ Load more
148
+ </Button>,
149
+ )
150
+ }
151
+ }
152
+
153
+ return (
154
+ <ul
155
+ {...props}
156
+ // @ts-expect-error ref is assignable
157
+ ref={ref}
158
+ onScroll={event => {
159
+ // If not already loading and scrolled to bottom
160
+ if (
161
+ !isLoading &&
162
+ event.currentTarget.clientHeight + event.currentTarget.scrollTop >=
163
+ event.currentTarget.scrollHeight
164
+ ) {
165
+ loadNextPage()
166
+ }
167
+ }}
168
+ >
169
+ {listItems}
170
+ </ul>
171
+ )
172
+ }
173
+
133
174
  return (
134
175
  <AutocompleteField
135
176
  options={optionKeys}
@@ -137,41 +178,7 @@ const ApiAutocompleteField = <
137
178
  onInputChange={(_, value, reason) => {
138
179
  setSearch(reason === "input" ? value : "")
139
180
  }}
140
- ListboxComponent={forwardRef(({ children, ...props }, ref) => {
141
- const listItems = Children.toArray(children)
142
- if (isLoading) listItems.push(<CircularProgress key="is-loading" />)
143
- else {
144
- if (isError) listItems.push(<SyncError key="is-error" />)
145
- if (hasMore) {
146
- listItems.push(
147
- <Button key="load-more" onClick={loadNextPage}>
148
- Load more
149
- </Button>,
150
- )
151
- }
152
- }
153
-
154
- return (
155
- <ul
156
- {...props}
157
- // @ts-expect-error
158
- ref={ref}
159
- onScroll={event => {
160
- // If not already loading and scrolled to bottom
161
- if (
162
- !isLoading &&
163
- event.currentTarget.clientHeight +
164
- event.currentTarget.scrollTop >=
165
- event.currentTarget.scrollHeight
166
- ) {
167
- loadNextPage()
168
- }
169
- }}
170
- >
171
- {listItems}
172
- </ul>
173
- )
174
- })}
181
+ ListboxComponent={forwardRef(ListboxComponent)}
175
182
  {...otherAutocompleteFieldProps}
176
183
  />
177
184
  )
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  Autocomplete,
3
- TextField,
4
3
  type AutocompleteProps,
5
4
  type ChipTypeMap,
5
+ TextField,
6
6
  type TextFieldProps,
7
7
  } from "@mui/material"
8
+ import { type ElementType, type JSX } from "react"
8
9
  import { Field, type FieldConfig, type FieldProps } from "formik"
9
- import { type ElementType } from "react"
10
10
  import {
11
+ type ValidateOptions,
11
12
  number as YupNumber,
12
13
  string as YupString,
13
- type ValidateOptions,
14
14
  } from "yup"
15
15
 
16
- import { schemaToFieldValidator } from "../../utils/form"
16
+ import { type FormValues, schemaToFieldValidator } from "../../utils/form"
17
17
  import { getNestedProperty } from "../../utils/general"
18
18
 
19
19
  export interface AutocompleteFieldProps<
@@ -86,17 +86,28 @@ const AutocompleteField = <
86
86
  return (
87
87
  <Field {...fieldConfig}>
88
88
  {({ form, meta }: FieldProps) => {
89
- const value = getNestedProperty(form.values, dotPath)
90
- const touched = getNestedProperty(form.touched, dotPath)
91
- const error = getNestedProperty(form.errors, dotPath)
89
+ const value = getNestedProperty(
90
+ form.values as FormValues,
91
+ dotPath,
92
+ ) as string
93
+ const touched = getNestedProperty(form.touched, dotPath) as boolean
94
+ const error = getNestedProperty(form.errors, dotPath) as
95
+ | string
96
+ | undefined
92
97
 
93
98
  return (
94
99
  <Autocomplete
95
100
  options={options}
101
+ // @ts-expect-error value can be assigned
96
102
  defaultValue={
97
- meta.initialValue === "" ? undefined : meta.initialValue
103
+ meta.initialValue === ""
104
+ ? undefined
105
+ : (meta.initialValue as string)
98
106
  }
99
- renderInput={({ id: _, ...otherParams }) => (
107
+ renderInput={({
108
+ id: _, // eslint-disable-line @typescript-eslint/no-unused-vars
109
+ ...otherParams
110
+ }) => (
100
111
  <TextField
101
112
  id={id ?? name}
102
113
  name={name}
@@ -104,13 +115,13 @@ const AutocompleteField = <
104
115
  type="text" // Force to be string to avoid number incrementor/decrementor
105
116
  value={value}
106
117
  error={touched && Boolean(error)}
107
- helperText={(touched && error) as false | string}
118
+ helperText={touched && error}
108
119
  {...otherTextFieldProps}
109
120
  {...otherParams}
110
121
  />
111
122
  )}
112
123
  onChange={(_, value) => {
113
- form.setFieldValue(name, value ?? undefined, true)
124
+ void form.setFieldValue(name, value ?? undefined, true)
114
125
  }}
115
126
  onBlur={form.handleBlur}
116
127
  {...otherAutocompleteProps}
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  Checkbox,
3
+ type CheckboxProps,
3
4
  FormControl,
4
5
  FormControlLabel,
5
- FormHelperText,
6
- type CheckboxProps,
7
6
  type FormControlLabelProps,
7
+ FormHelperText,
8
8
  } from "@mui/material"
9
9
  import { Field, type FieldConfig, type FieldProps } from "formik"
10
+ import { type ValidateOptions, bool as YupBool } from "yup"
10
11
  import { type FC } from "react"
11
- import { bool as YupBool, type ValidateOptions } from "yup"
12
12
 
13
- import { schemaToFieldValidator } from "../../utils/form"
13
+ import { type FormValues, schemaToFieldValidator } from "../../utils/form"
14
14
  import { getNestedProperty } from "../../utils/general"
15
15
 
16
16
  export interface CheckboxFieldProps
@@ -47,9 +47,14 @@ const CheckboxField: FC<CheckboxFieldProps> = ({
47
47
  return (
48
48
  <Field {...fieldConfig}>
49
49
  {({ form, meta }: FieldProps) => {
50
- const touched = getNestedProperty(form.touched, dotPath)
51
- const error = getNestedProperty(form.errors, dotPath)
52
- const value = getNestedProperty(form.values, dotPath)
50
+ const touched = getNestedProperty(form.touched, dotPath) as boolean
51
+ const error = getNestedProperty(form.errors, dotPath) as
52
+ | string
53
+ | undefined
54
+ const value = getNestedProperty(
55
+ form.values as FormValues,
56
+ dotPath,
57
+ ) as boolean
53
58
 
54
59
  const hasError = touched && Boolean(error)
55
60
 
@@ -59,7 +64,7 @@ const CheckboxField: FC<CheckboxFieldProps> = ({
59
64
  <FormControlLabel
60
65
  control={
61
66
  <Checkbox
62
- defaultChecked={meta.initialValue}
67
+ defaultChecked={meta.initialValue as boolean}
63
68
  id={id ?? name}
64
69
  name={name}
65
70
  value={value}
@@ -70,7 +75,7 @@ const CheckboxField: FC<CheckboxFieldProps> = ({
70
75
  }
71
76
  {...formControlLabelProps}
72
77
  />
73
- {hasError && <FormHelperText>{error as string}</FormHelperText>}
78
+ {hasError && <FormHelperText>{error}</FormHelperText>}
74
79
  </FormControl>
75
80
  )
76
81
  }}
@@ -1,13 +1,14 @@
1
+ import { type ElementType, type JSX } from "react"
1
2
  import { type ChipTypeMap } from "@mui/material"
2
- import { type ElementType } from "react"
3
+
4
+ import AutocompleteField, {
5
+ type AutocompleteFieldProps,
6
+ } from "./AutocompleteField"
3
7
  import {
4
8
  COUNTRY_ISO_CODES,
5
9
  COUNTRY_ISO_CODE_MAPPING,
6
10
  type CountryIsoCodes,
7
11
  } from "../../utils/general"
8
- import AutocompleteField, {
9
- type AutocompleteFieldProps,
10
- } from "./AutocompleteField"
11
12
 
12
13
  export interface CountryFieldProps<
13
14
  Multiple extends boolean | undefined = false,
@@ -1,16 +1,17 @@
1
+ import "dayjs/locale/en-gb"
1
2
  import {
2
3
  DatePicker,
3
- LocalizationProvider,
4
4
  type DatePickerProps,
5
+ LocalizationProvider,
5
6
  type PickerValidDate,
6
7
  } from "@mui/x-date-pickers"
7
- import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"
8
- import dayjs, { type Dayjs } from "dayjs"
9
- import "dayjs/locale/en-gb"
10
8
  import { Field, type FieldConfig, type FieldProps } from "formik"
11
- import { date as YupDate, type ValidateOptions } from "yup"
9
+ import { type ValidateOptions, date as YupDate } from "yup"
10
+ import dayjs, { type Dayjs } from "dayjs"
11
+ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"
12
+ import { type JSX } from "react"
12
13
 
13
- import { schemaToFieldValidator } from "../../utils/form"
14
+ import { type FormValues, schemaToFieldValidator } from "../../utils/form"
14
15
  import { getNestedProperty } from "../../utils/general"
15
16
 
16
17
  export interface DatePickerFieldProps<
@@ -69,14 +70,19 @@ const DatePickerField = <
69
70
  return (
70
71
  <Field {...fieldConfig}>
71
72
  {({ form }: FieldProps) => {
72
- const error = getNestedProperty(form.errors, dotPath)
73
- const touched = getNestedProperty(form.touched, dotPath)
74
- let value = getNestedProperty(form.values, dotPath)
73
+ const error = getNestedProperty(form.errors, dotPath) as
74
+ | string
75
+ | undefined
76
+ const touched = getNestedProperty(form.touched, dotPath) as boolean
77
+ let value: Dayjs | null | string = getNestedProperty(
78
+ form.values as FormValues,
79
+ dotPath,
80
+ ) as string
75
81
 
76
82
  value = value ? dayjs(value) : null
77
83
 
78
84
  function handleChange(value: Dayjs | null) {
79
- form.setFieldValue(
85
+ void form.setFieldValue(
80
86
  name,
81
87
  value && value.isValid() ? value.format("YYYY-MM-DD") : null,
82
88
  true,
@@ -88,6 +94,7 @@ const DatePickerField = <
88
94
  dateAdapter={AdapterDayjs}
89
95
  adapterLocale="en-gb"
90
96
  >
97
+ {/* @ts-expect-error value is compatible */}
91
98
  <DatePicker
92
99
  name={name}
93
100
  value={value}
@@ -98,7 +105,7 @@ const DatePickerField = <
98
105
  textField: {
99
106
  id: name,
100
107
  onChange: value => {
101
- // @ts-expect-error
108
+ // @ts-expect-error value is compatible
102
109
  handleChange(value as Dayjs | null)
103
110
  },
104
111
  onBlur: form.handleBlur,
@@ -1,6 +1,6 @@
1
1
  import { EmailOutlined as EmailOutlinedIcon } from "@mui/icons-material"
2
- import { InputAdornment } from "@mui/material"
3
2
  import type { FC } from "react"
3
+ import { InputAdornment } from "@mui/material"
4
4
  import { string as YupString } from "yup"
5
5
 
6
6
  import TextField, { type TextFieldProps } from "./TextField"
@@ -1,6 +1,6 @@
1
- import { PersonOutlined as PersonOutlinedIcon } from "@mui/icons-material"
2
- import { InputAdornment } from "@mui/material"
3
1
  import type { FC } from "react"
2
+ import { InputAdornment } from "@mui/material"
3
+ import { PersonOutlined as PersonOutlinedIcon } from "@mui/icons-material"
4
4
 
5
5
  import TextField, { type TextFieldProps } from "./TextField"
6
6
  import { schemas } from "../../api"
@@ -1,26 +1,27 @@
1
+ import {
2
+ type FC,
3
+ type JSX,
4
+ type ReactNode,
5
+ type RefObject,
6
+ useEffect,
7
+ useRef,
8
+ } from "react"
1
9
  import { FormHelperText, type FormHelperTextProps } from "@mui/material"
2
10
  import {
3
11
  Formik,
4
- Form as FormikForm,
5
12
  type FormikConfig,
6
13
  type FormikErrors,
14
+ Form as FormikForm,
7
15
  type FormikProps,
8
16
  } from "formik"
9
- import {
10
- type ReactNode,
11
- type FC,
12
- useRef,
13
- useEffect,
14
- type RefObject,
15
- } from "react"
16
17
  import type { TypedUseMutation } from "@reduxjs/toolkit/query/react"
17
18
 
18
- import { getKeyPaths } from "../../utils/general"
19
19
  import {
20
- submitForm,
21
- type SubmitFormOptions,
22
20
  type FormValues,
21
+ type SubmitFormOptions,
22
+ submitForm,
23
23
  } from "../../utils/form"
24
+ import { getKeyPaths } from "../../utils/general"
24
25
 
25
26
  const SCROLL_INTO_VIEW_OPTIONS: ScrollIntoViewOptions = {
26
27
  behavior: "smooth",
@@ -67,7 +68,7 @@ const BaseForm = <Values extends FormValues>({
67
68
  ...otherFormikProps
68
69
  }: BaseFormProps<Values>) => (
69
70
  <Formik {...otherFormikProps}>
70
- {/* @ts-expect-error */}
71
+ {/* @ts-expect-error value is assignable */}
71
72
  {(formik: _FormikProps<Values>) => {
72
73
  const hasErrors = Boolean(Object.keys(formik.errors).length)
73
74
  const hasNonFieldErrors =
@@ -1,9 +1,9 @@
1
+ import { type FC, useState } from "react"
2
+ import { IconButton, InputAdornment } from "@mui/material"
1
3
  import {
2
4
  Visibility as VisibilityIcon,
3
5
  VisibilityOff as VisibilityOffIcon,
4
6
  } from "@mui/icons-material"
5
- import { IconButton, InputAdornment } from "@mui/material"
6
- import { useState, type FC } from "react"
7
7
  import { string as YupString } from "yup"
8
8
 
9
9
  import RepeatField, { type RepeatFieldProps } from "./RepeatField"
@@ -1,15 +1,15 @@
1
- import { TextField as MuiTextField, type TextFieldProps } from "@mui/material"
2
- import { Field, type FieldConfig, type FieldProps } from "formik"
3
1
  import {
4
- useEffect,
5
- useState,
6
2
  type Dispatch,
7
3
  type FC,
8
4
  type SetStateAction,
5
+ useEffect,
6
+ useState,
9
7
  } from "react"
10
- import { string as YupString, type ValidateOptions } from "yup"
8
+ import { Field, type FieldConfig, type FieldProps } from "formik"
9
+ import { TextField as MuiTextField, type TextFieldProps } from "@mui/material"
10
+ import { type ValidateOptions, string as YupString } from "yup"
11
11
 
12
- import { schemaToFieldValidator } from "../../utils/form"
12
+ import { type FormValues, schemaToFieldValidator } from "../../utils/form"
13
13
  import { getNestedProperty } from "../../utils/general"
14
14
 
15
15
  export type RepeatFieldProps = Omit<
@@ -47,12 +47,20 @@ const TextField: FC<
47
47
  const { form } = fieldProps
48
48
 
49
49
  const dotPath = name.split(".")
50
- const value = getNestedProperty(form.values, dotPath)
50
+ const value = getNestedProperty(form.values as FormValues, dotPath) as string
51
51
 
52
52
  const repeatDotPath = repeatName.split(".")
53
- const repeatValue = getNestedProperty(form.values, repeatDotPath)
54
- const repeatTouched = getNestedProperty(form.touched, repeatDotPath)
55
- const repeatError = getNestedProperty(form.errors, repeatDotPath)
53
+ const repeatValue = getNestedProperty(
54
+ form.values as FormValues,
55
+ repeatDotPath,
56
+ ) as string
57
+ const repeatTouched = getNestedProperty(
58
+ form.touched,
59
+ repeatDotPath,
60
+ ) as boolean
61
+ const repeatError = getNestedProperty(form.errors, repeatDotPath) as
62
+ | string
63
+ | undefined
56
64
 
57
65
  useEffect(() => {
58
66
  setValue(value)
@@ -2,6 +2,8 @@ import { Button, type ButtonProps } from "@mui/material"
2
2
  import { Field, type FieldProps } from "formik"
3
3
  import type { FC } from "react"
4
4
 
5
+ import { type FormValues } from "../../utils/form"
6
+
5
7
  export interface SubmitButtonProps
6
8
  extends Omit<ButtonProps, "type" | "onClick"> {}
7
9
 
@@ -15,7 +17,7 @@ const SubmitButton: FC<SubmitButtonProps> = ({
15
17
  ) {
16
18
  touched = touched || {}
17
19
  for (const key in values) {
18
- const value = values[key]
20
+ const value: unknown = values[key]
19
21
  touched[key] =
20
22
  value instanceof Object && value.constructor === Object
21
23
  ? getTouched(value, touched)
@@ -31,15 +33,17 @@ const SubmitButton: FC<SubmitButtonProps> = ({
31
33
  <Button
32
34
  type="button"
33
35
  onClick={() => {
34
- form.setTouched(getTouched(form.values), true).then(errors => {
35
- const hasErrors = Boolean(errors && Object.keys(errors).length)
36
- // If has errors, set isSubmitting=true so fields in the form are
37
- // aware that a submission was attempted. Else, set
38
- // isSubmitting=false as it will be set to true when calling
39
- // submitForm().
40
- form.setSubmitting(hasErrors)
41
- if (!hasErrors) form.submitForm()
42
- })
36
+ void form
37
+ .setTouched(getTouched(form.values as FormValues), true)
38
+ .then(errors => {
39
+ const hasErrors = Boolean(errors && Object.keys(errors).length)
40
+ // If has errors, set isSubmitting=true so fields in the form are
41
+ // aware that a submission was attempted. Else, set
42
+ // isSubmitting=false as it will be set to true when calling
43
+ // submitForm().
44
+ form.setSubmitting(hasErrors)
45
+ if (!hasErrors) void form.submitForm()
46
+ })
43
47
  }}
44
48
  {...otherButtonProps}
45
49
  >
@@ -1,12 +1,12 @@
1
+ import { type FC, useEffect, useState } from "react"
2
+ import { Field, type FieldConfig, type FieldProps } from "formik"
1
3
  import {
2
4
  TextField as MuiTextField,
3
5
  type TextFieldProps as MuiTextFieldProps,
4
6
  } from "@mui/material"
5
- import { Field, type FieldConfig, type FieldProps } from "formik"
6
- import { type FC, useState, useEffect } from "react"
7
7
  import { type StringSchema, type ValidateOptions, array as YupArray } from "yup"
8
8
 
9
- import { schemaToFieldValidator } from "../../utils/form"
9
+ import { type FormValues, schemaToFieldValidator } from "../../utils/form"
10
10
  import { getNestedProperty } from "../../utils/general"
11
11
 
12
12
  export type TextFieldProps = Omit<
@@ -79,7 +79,7 @@ const TextField: FC<TextFieldProps> = ({
79
79
  return (
80
80
  new Set(
81
81
  uniqueCaseInsensitive
82
- ? values.map(value => (value as string).toLowerCase())
82
+ ? values.map(value => value.toLowerCase())
83
83
  : values,
84
84
  ).size === values.length
85
85
  )
@@ -104,18 +104,24 @@ const TextField: FC<TextFieldProps> = ({
104
104
  validate: schemaToFieldValidator(buildSchema(), validateOptions),
105
105
  }
106
106
 
107
- const _Field: FC<FieldProps> = ({ form }) => {
108
- const initialValue = getNestedProperty(form.initialValues, dotPath)
109
- const value = getNestedProperty(form.values, dotPath)
110
- const error = getNestedProperty(form.errors, dotPath)
111
- const touched = getNestedProperty(form.touched, dotPath)
107
+ const FieldInternal: FC<FieldProps> = ({ form }) => {
108
+ const initialValue = getNestedProperty(
109
+ form.initialValues as FormValues,
110
+ dotPath,
111
+ ) as string
112
+ const value = getNestedProperty(
113
+ form.values as FormValues,
114
+ dotPath,
115
+ ) as string
116
+ const error = getNestedProperty(form.errors, dotPath) as string | undefined
117
+ const touched = getNestedProperty(form.touched, dotPath) as boolean
112
118
 
113
119
  useEffect(() => {
114
120
  setInitialValue(initialValue)
115
121
  }, [initialValue])
116
122
 
117
123
  useEffect(() => {
118
- form.setFieldValue(
124
+ void form.setFieldValue(
119
125
  name,
120
126
  split && typeof value === "string" ? value.split(split) : value,
121
127
  true,
@@ -138,7 +144,7 @@ const TextField: FC<TextFieldProps> = ({
138
144
  )
139
145
  }
140
146
 
141
- return <Field {...fieldConfig}>{_Field}</Field>
147
+ return <Field {...fieldConfig}>{FieldInternal}</Field>
142
148
  }
143
149
 
144
150
  export default TextField
@@ -1,9 +1,10 @@
1
+ import { type ElementType, type JSX } from "react"
1
2
  import { type ChipTypeMap } from "@mui/material"
2
- import { type ElementType } from "react"
3
- import { UK_COUNTIES } from "../../utils/general"
3
+
4
4
  import AutocompleteField, {
5
5
  type AutocompleteFieldProps,
6
6
  } from "./AutocompleteField"
7
+ import { UK_COUNTIES } from "../../utils/general"
7
8
 
8
9
  export interface UkCountyFieldProps<
9
10
  Multiple extends boolean | undefined = false,
@@ -1,28 +1,35 @@
1
- export * from "./ApiAutocompleteField"
2
- export { default as ApiAutocompleteField } from "./ApiAutocompleteField"
3
- export * from "./AutocompleteField"
4
- export { default as AutocompleteField } from "./AutocompleteField"
5
- export * from "./CheckboxField"
6
- export { default as CheckboxField } from "./CheckboxField"
7
- export * from "./CountryField"
8
- export { default as CountryField } from "./CountryField"
9
- export * from "./DatePickerField"
10
- export { default as DatePickerField } from "./DatePickerField"
11
- export * from "./EmailField"
12
- export { default as EmailField } from "./EmailField"
13
- export * from "./FirstNameField"
14
- export { default as FirstNameField } from "./FirstNameField"
15
- export * from "./Form"
16
- export { default as Form } from "./Form"
17
- export * from "./OtpField"
18
- export { default as OtpField } from "./OtpField"
19
- export * from "./PasswordField"
20
- export { default as PasswordField } from "./PasswordField"
21
- export * from "./RepeatField"
22
- export { default as RepeatField } from "./RepeatField"
23
- export * from "./SubmitButton"
24
- export { default as SubmitButton } from "./SubmitButton"
25
- export * from "./TextField"
26
- export { default as TextField } from "./TextField"
27
- export * from "./UkCountyField"
28
- export { default as UkCountyField } from "./UkCountyField"
1
+ export {
2
+ default as ApiAutocompleteField,
3
+ type ApiAutocompleteFieldProps,
4
+ } from "./ApiAutocompleteField"
5
+ export {
6
+ default as AutocompleteField,
7
+ type AutocompleteFieldProps,
8
+ } from "./AutocompleteField"
9
+ export {
10
+ default as CheckboxField,
11
+ type CheckboxFieldProps,
12
+ } from "./CheckboxField"
13
+ export { default as CountryField, type CountryFieldProps } from "./CountryField"
14
+ export {
15
+ default as DatePickerField,
16
+ type DatePickerFieldProps,
17
+ } from "./DatePickerField"
18
+ export { default as EmailField, type EmailFieldProps } from "./EmailField"
19
+ export {
20
+ default as FirstNameField,
21
+ type FirstNameFieldProps,
22
+ } from "./FirstNameField"
23
+ export { default as Form, type FormProps, type FormErrors } from "./Form"
24
+ export { default as OtpField, type OtpFieldProps } from "./OtpField"
25
+ export {
26
+ default as PasswordField,
27
+ type PasswordFieldProps,
28
+ } from "./PasswordField"
29
+ export { default as RepeatField, type RepeatFieldProps } from "./RepeatField"
30
+ export { default as SubmitButton, type SubmitButtonProps } from "./SubmitButton"
31
+ export { default as TextField, type TextFieldProps } from "./TextField"
32
+ export {
33
+ default as UkCountyField,
34
+ type UkCountyFieldProps,
35
+ } from "./UkCountyField"