Skip to content

Commit

Permalink
fix: Portal frontend 51 (#58)
Browse files Browse the repository at this point in the history
* fix: support dirty fields

* fix: navigate
  • Loading branch information
SKairinos committed Sep 19, 2024
1 parent 11b25c4 commit 516de83
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 29 deletions.
56 changes: 32 additions & 24 deletions src/components/form/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
type TextFieldProps as MuiTextFieldProps,
} from "@mui/material"
import { Field, type FieldConfig, type FieldProps } from "formik"
import type { FC } from "react"
import { type FC, useState, useEffect } from "react"
import { type StringSchema, type ValidateOptions } from "yup"

import { schemaToFieldValidator } from "../../utils/form"
Expand All @@ -23,6 +23,7 @@ export type TextFieldProps = Omit<
name: string
schema: StringSchema
validateOptions?: ValidateOptions
dirty?: boolean
}

// https://formik.org/docs/examples/with-material-ui
Expand All @@ -31,43 +32,50 @@ const TextField: FC<TextFieldProps> = ({
schema,
type = "text",
required = false,
dirty = false,
validateOptions,
...otherTextFieldProps
}) => {
const [initialValue, setInitialValue] = useState("")

const dotPath = name.split(".")

if (required) schema = schema.required()
if (dirty) schema = schema.notOneOf([initialValue], "cannot be initial value")

const fieldConfig: FieldConfig = {
name,
type,
validate: schemaToFieldValidator(schema, validateOptions),
}

return (
<Field {...fieldConfig}>
{({ form }: FieldProps) => {
const value = getNestedProperty(form.values, dotPath)
const error = getNestedProperty(form.errors, dotPath)
const touched = getNestedProperty(form.touched, dotPath)
const _Field: FC<FieldProps> = ({ form }) => {
const initialValue = getNestedProperty(form.initialValues, dotPath)
const value = getNestedProperty(form.values, dotPath)
const error = getNestedProperty(form.errors, dotPath)
const touched = getNestedProperty(form.touched, dotPath)

useEffect(() => {
setInitialValue(initialValue)
}, [initialValue])

return (
<MuiTextField
id={name}
name={name}
type={type}
required={required}
value={value}
onChange={form.handleChange}
onBlur={form.handleBlur}
error={touched && Boolean(error)}
helperText={(touched && error) as false | string}
{...otherTextFieldProps}
/>
)
}

return (
<MuiTextField
id={name}
name={name}
type={type}
required={required}
value={value}
onChange={form.handleChange}
onBlur={form.handleBlur}
error={touched && Boolean(error)}
helperText={(touched && error) as false | string}
{...otherTextFieldProps}
/>
)
}}
</Field>
)
return <Field {...fieldConfig}>{_Field}</Field>
}

export default TextField
33 changes: 33 additions & 0 deletions src/components/router/Navigate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect } from "react"
import { type To } from "react-router-dom"

import { useNavigate, type NavigateOptions } from "../../hooks"

export type NavigateProps<
Override extends "delta" | "to",
State extends Record<string, any> = Record<string, any>,
> = Override extends "delta"
? { delta: number; to?: undefined }
: { delta?: undefined; to: To } & NavigateOptions<State>

const Navigate: {
(props: NavigateProps<"delta">): JSX.Element
<State extends Record<string, any> = Record<string, any>>(
props: NavigateProps<"to", State>,
): JSX.Element
} = ({
delta,
to,
...options
}: NavigateProps<"delta"> | NavigateProps<"to">) => {
const navigate = useNavigate()

useEffect(() => {
if (typeof delta === "number") navigate(delta)
else navigate(to, options)
}, [navigate, delta, to, options])

return <></>
}

export default Navigate
2 changes: 2 additions & 0 deletions src/components/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export * from "./LinkListItem"
export { default as LinkListItem } from "./LinkListItem"
export * from "./LinkTab"
export { default as LinkTab } from "./LinkTab"
export * from "./Navigate"
export { default as Navigate } from "./Navigate"
14 changes: 9 additions & 5 deletions src/hooks/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
useParams as _useParams,
useSearchParams as _useSearchParams,
type Location,
type NavigateOptions,
type NavigateOptions as _NavigateOptions,
type Params,
type To,
} from "react-router-dom"
Expand All @@ -21,13 +21,17 @@ import {
type TryValidateSyncRT,
} from "../utils/schema"

export type NavigateOptions<
State extends Record<string, any> = Record<string, any>,
> = Omit<_NavigateOptions, "state"> & {
state?: State & Partial<PageState>
next?: boolean
}

export type Navigate = {
<State extends Record<string, any> = Record<string, any>>(
to: To,
options?: Omit<NavigateOptions, "state"> & {
state?: State & Partial<PageState>
next?: boolean
},
options?: NavigateOptions<State>,
): void
(delta: number): void
}
Expand Down

0 comments on commit 516de83

Please sign in to comment.