Better dates and cleanData
This commit is contained in:
parent
4400ceb459
commit
316998f5f7
|
|
@ -10,15 +10,23 @@ export default function DateField(props) {
|
||||||
|
|
||||||
const [{onChange, value, ...field}, meta, helpers] = useField(props);
|
const [{onChange, value, ...field}, meta, helpers] = useField(props);
|
||||||
|
|
||||||
const parsedDate = dayjs(value);
|
const parsedDate = typeof value === "string" && /^\d{4}-\d{2}-\d{2}/.test(value)
|
||||||
|
? dayjs(value.slice(0, 10))
|
||||||
|
: dayjs(value);
|
||||||
const isValid = value && parsedDate.isValid();
|
const isValid = value && parsedDate.isValid();
|
||||||
|
const displayDate = isValid ? parsedDate.toDate() : null;
|
||||||
|
|
||||||
const {value: _x, onChange: _y, ...restProps} = props;
|
const {value: _x, onChange: _y, ...restProps} = props;
|
||||||
|
|
||||||
return <DatePickerInput
|
return <DatePickerInput
|
||||||
value={isValid ? parsedDate.toDate() : null}
|
value={displayDate}
|
||||||
onChange={(val)=>onChange({ target: { value: val, name: field.name } })}
|
onChange={(val)=>{
|
||||||
|
const outDate = val && dayjs(val).isValid() ? dayjs(val).format("YYYY-MM-DD") : null;
|
||||||
|
onChange({ target: { value: outDate, name: field.name } });
|
||||||
|
}}
|
||||||
{...field}
|
{...field}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DateOnlyField = DateField;
|
||||||
|
|
|
||||||
1
Form/Core/DateOnlyField.js
Normal file
1
Form/Core/DateOnlyField.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default, DateOnlyField } from "./DateFields";
|
||||||
|
|
@ -13,16 +13,16 @@ export default function DateTimeField(props) {
|
||||||
|
|
||||||
const [{onChange, value, ...field}, meta, helpers] = useField(props);
|
const [{onChange, value, ...field}, meta, helpers] = useField(props);
|
||||||
|
|
||||||
const parsedDate = dayjs.utc(value);
|
const parsedDate = dayjs(value);
|
||||||
const isValid = value && parsedDate.isValid();
|
const isValid = value && parsedDate.isValid();
|
||||||
const displayDate = isValid ? dayjs(parsedDate.format("YYYY-MM-DDTHH:mm:ss")).toDate() : null;
|
const displayDate = isValid ? parsedDate.toDate() : null;
|
||||||
|
|
||||||
const {value: _x, onChange: _y, ...restProps} = props;
|
const {value: _x, onChange: _y, ...restProps} = props;
|
||||||
|
|
||||||
return <DateTimePicker
|
return <DateTimePicker
|
||||||
value={displayDate}
|
value={displayDate}
|
||||||
onChange={(val)=>{
|
onChange={(val)=>{
|
||||||
const outDate = val ? dayjs.utc(dayjs(val).format("YYYY-MM-DDTHH:mm:ss")).toDate() : null;
|
const outDate = val && dayjs(val).isValid() ? dayjs(val).format("YYYY-MM-DDTHH:mm:ss") : null;
|
||||||
onChange({ target: { value: outDate, name: field.name } });
|
onChange({ target: { value: outDate, name: field.name } });
|
||||||
}}
|
}}
|
||||||
{...field}
|
{...field}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Form, Formik, FormikConfig, FormikErrors, FormikProps } from "formik";
|
import { Form, Formik, FormikConfig, FormikErrors, FormikProps } from "formik";
|
||||||
import { Button, Divider } from "@mantine/core";
|
import { Button, Divider } from "@mantine/core";
|
||||||
|
import { cleanEmptyStrings } from "./cleanEmptyStrings";
|
||||||
|
|
||||||
//formik is defined as
|
//formik is defined as
|
||||||
//export declare function Formik<Values extends FormikValues = FormikValues, ExtraProps = {}>(props: FormikConfig<Values> & ExtraProps): React.JSX.Element;
|
//export declare function Formik<Values extends FormikValues = FormikValues, ExtraProps = {}>(props: FormikConfig<Values> & ExtraProps): React.JSX.Element;
|
||||||
|
|
@ -13,6 +14,7 @@ export function FormikForm<Values extends object>({
|
||||||
onDelete = null,
|
onDelete = null,
|
||||||
closeModal = null,
|
closeModal = null,
|
||||||
createForm = null,
|
createForm = null,
|
||||||
|
sendEmptyKeys = null,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: Omit<FormikConfig<Values>, "initialValues"> & {
|
}: Omit<FormikConfig<Values>, "initialValues"> & {
|
||||||
|
|
@ -22,13 +24,19 @@ export function FormikForm<Values extends object>({
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
closeModal?: () => void;
|
closeModal?: () => void;
|
||||||
createForm?: (values, handleChange, errors, touched) => React.ReactNode;
|
createForm?: (values, handleChange, errors, touched) => React.ReactNode;
|
||||||
|
sendEmptyKeys?: Set<string> | string[];
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleCleanSubmit = (values: Values, formikHelpers: any) => {
|
||||||
|
const cleaned = cleanEmptyStrings(values, sendEmptyKeys);
|
||||||
|
return onSubmit(cleaned, formikHelpers);
|
||||||
|
};
|
||||||
|
|
||||||
return <Formik<Values>
|
return <Formik<Values>
|
||||||
initialValues={data}
|
initialValues={data}
|
||||||
onSubmit={onSubmit}
|
onSubmit={handleCleanSubmit}
|
||||||
validationSchema={schema}
|
validationSchema={schema}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
36
Form/cleanEmptyStrings.ts
Normal file
36
Form/cleanEmptyStrings.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Recursively cleans empty string values ("" or whitespace only) to null in form submission payloads,
|
||||||
|
* unless explicitly exempted by sendEmpty configuration.
|
||||||
|
*/
|
||||||
|
export function cleanEmptyStrings<T>(values: T, sendEmptyKeys?: Set<string> | string[]): T {
|
||||||
|
const exemptions = sendEmptyKeys instanceof Set ? sendEmptyKeys : new Set(sendEmptyKeys || []);
|
||||||
|
|
||||||
|
function clean(val: any, currentKey?: string): any {
|
||||||
|
if (val === null || val === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val === "string") {
|
||||||
|
if (val.trim() === "") {
|
||||||
|
return currentKey && exemptions.has(currentKey) ? "" : null;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
return val.map((item) => clean(item, currentKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val === "object" && !(val instanceof Date) && !(val instanceof Blob) && !(val instanceof File)) {
|
||||||
|
const cleanedObj: Record<string, any> = {};
|
||||||
|
for (const [k, v] of Object.entries(val)) {
|
||||||
|
cleanedObj[k] = clean(v, k);
|
||||||
|
}
|
||||||
|
return cleanedObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clean(values);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import { useApiClient } from "@utils/NejManager/NejProvider";
|
||||||
import useMethod from "../macros/useMethod.macro";
|
import useMethod from "../macros/useMethod.macro";
|
||||||
import useQuery from "../macros/useQuery.macro";
|
import useQuery from "../macros/useQuery.macro";
|
||||||
import { CancelablePromise, ApiClient, OwnerResponse, useOwner } from "@services/api";
|
import { CancelablePromise, ApiClient, OwnerResponse, useOwner } from "@services/api";
|
||||||
|
import { cleanEmptyStrings } from "./cleanEmptyStrings";
|
||||||
|
|
||||||
type FormProps<T> = {
|
type FormProps<T> = {
|
||||||
refresh: () => void;
|
refresh: () => void;
|
||||||
|
|
@ -30,7 +31,11 @@ export function withForm<T extends object, P extends FormProps<T>>(WrappedForm:
|
||||||
return (
|
return (
|
||||||
<FormikForm
|
<FormikForm
|
||||||
data={initialData || {} as T}
|
data={initialData || {} as T}
|
||||||
onSubmit={(values) => { submit(values); afterSubmit && afterSubmit(values) }}
|
onSubmit={(values) => {
|
||||||
|
const cleaned = cleanEmptyStrings(values);
|
||||||
|
submit(cleaned);
|
||||||
|
afterSubmit && afterSubmit(cleaned);
|
||||||
|
}}
|
||||||
submitText={submitText}
|
submitText={submitText}
|
||||||
>
|
>
|
||||||
<WrappedForm {...props} />
|
<WrappedForm {...props} />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user