fix
This commit is contained in:
parent
9cde4fb165
commit
ad557ca5c0
|
|
@ -32,6 +32,11 @@ export const Form: FC<FMProps> = (props) => {
|
||||||
promises: [],
|
promises: [],
|
||||||
done: [],
|
done: [],
|
||||||
},
|
},
|
||||||
|
submit: {
|
||||||
|
timeout: null as any,
|
||||||
|
promises: [],
|
||||||
|
done: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
field_def: {},
|
field_def: {},
|
||||||
props: {} as any,
|
props: {} as any,
|
||||||
|
|
@ -90,11 +95,6 @@ export const Form: FC<FMProps> = (props) => {
|
||||||
}
|
}
|
||||||
const toaster_el = document.getElementsByClassName("prasi-toaster")[0];
|
const toaster_el = document.getElementsByClassName("prasi-toaster")[0];
|
||||||
|
|
||||||
const childs = get(
|
|
||||||
body,
|
|
||||||
"props.meta.item.component.props.body.content.childs"
|
|
||||||
) as any[];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,47 @@ export const TypeCustom: FC<{ field: FieldLocal; fm: FMLocal }> = ({
|
||||||
field,
|
field,
|
||||||
fm,
|
fm,
|
||||||
}) => {
|
}) => {
|
||||||
const local = useLocal({ custom: null as any }, async () => {
|
const local = useLocal({
|
||||||
if (field.custom) {
|
custom: null as any,
|
||||||
local.custom = await field.custom();
|
exec: false,
|
||||||
local.render();
|
result: null as any,
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!local.custom && field.custom) {
|
||||||
|
console.log("field", field.custom);
|
||||||
|
local.custom = field.custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!local.exec) {
|
||||||
|
local.exec = true;
|
||||||
|
const callback = (value: any, should_render: boolean) => {
|
||||||
|
local.result = value;
|
||||||
|
if (should_render) {
|
||||||
|
local.render();
|
||||||
|
setTimeout(() => {
|
||||||
|
local.exec = false;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (field.custom) {
|
||||||
|
const res = local.custom();
|
||||||
|
if (res instanceof Promise) {
|
||||||
|
res.then((value) => {
|
||||||
|
callback(value, true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback(res, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let el = null as any;
|
let el = null as any;
|
||||||
if (local.custom) {
|
if (local.result) {
|
||||||
if (isValidElement(local.custom)) {
|
if (isValidElement(local.result)) {
|
||||||
el = local.custom;
|
el = local.result;
|
||||||
} else {
|
} else {
|
||||||
if (local.custom.field === "text") {
|
if (local.result.field === "text") {
|
||||||
el = <FieldTypeText field={field} fm={fm} prop={local.custom} />;
|
el = <FieldTypeText field={field} fm={fm} prop={local.result} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,34 @@
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { FMLocal, FieldLocal } from "../../typings";
|
import { FMLocal, FieldLocal } from "../../typings";
|
||||||
import { useLocal } from "@/utils/use-local";
|
import { useLocal } from "@/utils/use-local";
|
||||||
|
import parser from "any-date-parser";
|
||||||
|
|
||||||
export type PropTypeText = {
|
export type PropTypeText = {
|
||||||
type: "text" | "password" | "number";
|
type: "text" | "password" | "number" | "date" | "datetime";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parse = parser.exportAsFunctionAny("en-US");
|
||||||
|
|
||||||
export const FieldTypeText: FC<{
|
export const FieldTypeText: FC<{
|
||||||
field: FieldLocal;
|
field: FieldLocal;
|
||||||
fm: FMLocal;
|
fm: FMLocal;
|
||||||
prop: PropTypeText;
|
prop: PropTypeText;
|
||||||
}> = ({ field, fm, prop }) => {
|
}> = ({ field, fm, prop }) => {
|
||||||
const input = useLocal({});
|
const input = useLocal({});
|
||||||
const value = fm.data[field.name];
|
let value: any = fm.data[field.name];
|
||||||
field.input = input;
|
field.input = input;
|
||||||
field.prop = prop;
|
field.prop = prop;
|
||||||
|
|
||||||
|
if (["date", "datetime"].includes(prop.type)) {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
let date = parse(value);
|
||||||
|
if (typeof date === "object" && date instanceof Date) {
|
||||||
|
if (prop.type === "date") value = date.toISOString().substring(0, 10);
|
||||||
|
else if (prop.type === "datetime") value = date.toISOString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ export type FMInternal = {
|
||||||
status: "init" | "resizing" | "loading" | "saving" | "ready";
|
status: "init" | "resizing" | "loading" | "saving" | "ready";
|
||||||
data: any;
|
data: any;
|
||||||
reload: () => Promise<void>;
|
reload: () => Promise<void>;
|
||||||
submit: () => Promise<void>;
|
submit: () => Promise<boolean>;
|
||||||
events: {
|
events: {
|
||||||
on_change: (name: string, new_value: any) => void;
|
on_change: (name: string, new_value: any) => void;
|
||||||
};
|
};
|
||||||
|
|
@ -82,6 +82,11 @@ export type FMInternal = {
|
||||||
promises: Promise<void>[];
|
promises: Promise<void>[];
|
||||||
done: any[];
|
done: any[];
|
||||||
};
|
};
|
||||||
|
submit: {
|
||||||
|
promises: Promise<boolean>[];
|
||||||
|
timeout: ReturnType<typeof setTimeout>;
|
||||||
|
done: any[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
props: Exclude<FMProps, "body" | "PassProp">;
|
props: Exclude<FMProps, "body" | "PassProp">;
|
||||||
size: {
|
size: {
|
||||||
|
|
@ -204,6 +209,6 @@ export type CustomField =
|
||||||
| { field: "relation"; type: "has-many" | "has-one" };
|
| { field: "relation"; type: "has-many" | "has-one" };
|
||||||
|
|
||||||
export const FieldTypeCustom = `type CustomField =
|
export const FieldTypeCustom = `type CustomField =
|
||||||
{ field: "text", type: "text" | "password" | "number" }
|
{ field: "text", type: "text" | "password" | "number" | "date" | "datetime" }
|
||||||
| { field: "relation", type: "has-many" | "has-one" }
|
| { field: "relation", type: "has-many" | "has-one" }
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { parseGenField } from "@/gen/utils";
|
import { parseGenField } from "@/gen/utils";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
import { Loader2 } from "lucide-react";
|
import { AlertTriangle, Check, Loader2 } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { FMLocal, FMProps } from "../typings";
|
import { FMLocal, FMProps } from "../typings";
|
||||||
import { editorFormData } from "./ed-data";
|
import { editorFormData } from "./ed-data";
|
||||||
|
|
@ -89,10 +89,77 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
|
||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
fm.submit = async () => {
|
fm.submit = () => {
|
||||||
if (typeof fm.props.on_submit === "function") {
|
const promise = new Promise<boolean>(async (done) => {
|
||||||
fm.props.on_submit({ fm, form: fm.data, error: fm.error.object });
|
fm.internal.submit.done.push(done);
|
||||||
}
|
clearTimeout(fm.internal.submit.timeout);
|
||||||
|
fm.internal.submit.timeout = setTimeout(async () => {
|
||||||
|
const done_all = (val: boolean) => {
|
||||||
|
for (const d of fm.internal.submit.done) {
|
||||||
|
d(val);
|
||||||
|
}
|
||||||
|
fm.internal.submit.done = [];
|
||||||
|
fm.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof fm.props.on_submit === "function") {
|
||||||
|
if (fm.props.sonar === "on") {
|
||||||
|
toast.loading(
|
||||||
|
<>
|
||||||
|
<Loader2 className="c-h-4 c-w-4 c-animate-spin" />
|
||||||
|
Submitting...
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const success = await fm.props.on_submit({
|
||||||
|
fm,
|
||||||
|
form: fm.data,
|
||||||
|
error: fm.error.object,
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.dismiss();
|
||||||
|
done_all(success);
|
||||||
|
if (fm.props.sonar === "on") {
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.dismiss();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
toast.error(
|
||||||
|
<div className="c-flex c-text-red-600 c-items-center">
|
||||||
|
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
||||||
|
Save Failed, please correct{" "}
|
||||||
|
{Object.keys(fm.error.list).length} errors.
|
||||||
|
</div>,
|
||||||
|
{
|
||||||
|
dismissible: true,
|
||||||
|
className: css`
|
||||||
|
background: #ffecec;
|
||||||
|
border: 2px solid red;
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
toast.success(
|
||||||
|
<div className="c-flex c-text-green-700 c-items-center">
|
||||||
|
<Check className="c-h-4 c-w-4 c-mr-1 " />
|
||||||
|
Done
|
||||||
|
</div>,
|
||||||
|
{
|
||||||
|
className: css`
|
||||||
|
background: #e4ffed;
|
||||||
|
border: 2px solid green;
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
fm.internal.submit.promises.push(promise);
|
||||||
|
|
||||||
|
return promise;
|
||||||
};
|
};
|
||||||
if (typeof fm.props.on_init === "function") {
|
if (typeof fm.props.on_init === "function") {
|
||||||
fm.props.on_init({ fm, submit: fm.submit, reload: fm.reload });
|
fm.props.on_init({ fm, submit: fm.submit, reload: fm.reload });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue