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 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 displayDate = isValid ? parsedDate.toDate() : null;
|
||||
|
||||
const {value: _x, onChange: _y, ...restProps} = props;
|
||||
|
||||
return <DatePickerInput
|
||||
value={isValid ? parsedDate.toDate() : null}
|
||||
onChange={(val)=>onChange({ target: { value: val, name: field.name } })}
|
||||
value={displayDate}
|
||||
onChange={(val)=>{
|
||||
const outDate = val && dayjs(val).isValid() ? dayjs(val).format("YYYY-MM-DD") : null;
|
||||
onChange({ target: { value: outDate, name: field.name } });
|
||||
}}
|
||||
{...field}
|
||||
{...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 parsedDate = dayjs.utc(value);
|
||||
const parsedDate = dayjs(value);
|
||||
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;
|
||||
|
||||
return <DateTimePicker
|
||||
value={displayDate}
|
||||
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 } });
|
||||
}}
|
||||
{...field}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Formik, FormikConfig, FormikErrors, FormikProps } from "formik";
|
||||
import { Button, Divider } from "@mantine/core";
|
||||
import { cleanEmptyStrings } from "./cleanEmptyStrings";
|
||||
|
||||
//formik is defined as
|
||||
//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,
|
||||
closeModal = null,
|
||||
createForm = null,
|
||||
sendEmptyKeys = null,
|
||||
children,
|
||||
...props
|
||||
}: Omit<FormikConfig<Values>, "initialValues"> & {
|
||||
|
|
@ -22,13 +24,19 @@ export function FormikForm<Values extends object>({
|
|||
onDelete?: () => void;
|
||||
closeModal?: () => void;
|
||||
createForm?: (values, handleChange, errors, touched) => React.ReactNode;
|
||||
sendEmptyKeys?: Set<string> | string[];
|
||||
children?: React.ReactNode;
|
||||
}): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleCleanSubmit = (values: Values, formikHelpers: any) => {
|
||||
const cleaned = cleanEmptyStrings(values, sendEmptyKeys);
|
||||
return onSubmit(cleaned, formikHelpers);
|
||||
};
|
||||
|
||||
return <Formik<Values>
|
||||
initialValues={data}
|
||||
onSubmit={onSubmit}
|
||||
onSubmit={handleCleanSubmit}
|
||||
validationSchema={schema}
|
||||
{...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 useQuery from "../macros/useQuery.macro";
|
||||
import { CancelablePromise, ApiClient, OwnerResponse, useOwner } from "@services/api";
|
||||
import { cleanEmptyStrings } from "./cleanEmptyStrings";
|
||||
|
||||
type FormProps<T> = {
|
||||
refresh: () => void;
|
||||
|
|
@ -30,7 +31,11 @@ export function withForm<T extends object, P extends FormProps<T>>(WrappedForm:
|
|||
return (
|
||||
<FormikForm
|
||||
data={initialData || {} as T}
|
||||
onSubmit={(values) => { submit(values); afterSubmit && afterSubmit(values) }}
|
||||
onSubmit={(values) => {
|
||||
const cleaned = cleanEmptyStrings(values);
|
||||
submit(cleaned);
|
||||
afterSubmit && afterSubmit(cleaned);
|
||||
}}
|
||||
submitText={submitText}
|
||||
>
|
||||
<WrappedForm {...props} />
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user