diff --git a/comps/form/gen/gen-form.ts b/comps/form/gen/gen-form.ts index 9130366..79b5e82 100755 --- a/comps/form/gen/gen-form.ts +++ b/comps/form/gen/gen-form.ts @@ -78,6 +78,20 @@ async ({ form, error, fm }: IForm) => { fk: string; }>; + + // validasi + fm.error.clear(); + for (const [k, field] of Object.entries(fm.fields)) { + validateField(field, fm); + } + if (fm.error.list.length > 0) { + if (typeof md !== "undefined") { + fm.status = "ready"; + md.render(); + } + return false; + } + // pisahkan antara has_many dengan field biasa for (const [k, v] of Object.entries(data) as any) { if (Array.isArray(v)) { @@ -100,6 +114,8 @@ async ({ form, error, fm }: IForm) => { // prisma create / update ga boleh ada record.${pk} if (record) delete record.${pk}; + call_prasi_events("form", "before_save", [fm, record]); + if (form.${pk}) { await db.${table}.update({ where: { @@ -165,7 +181,14 @@ async ({ form, error, fm }: IForm) => { if (typeof md !== "undefined") { fm.status = "ready"; - md.render(); + // kembali ke tabel + setTimeout(() => { + md.selected = null; + md.tab.active = "master"; + md.internal.action_should_refresh = true; + md.params.apply(); + md.render(); + }, 500); } return result; diff --git a/comps/form/gen/on_load.ts b/comps/form/gen/on_load.ts index bb11af5..a0e1821 100755 --- a/comps/form/gen/on_load.ts +++ b/comps/form/gen/on_load.ts @@ -48,9 +48,16 @@ async (opt) => { ${pk}: id, }; if (id){ + //@ts-ignore const table = db[gen__table] as any; + //@ts-ignore const fields = parseGenField(gen__fields); + if (Array.isArray(fields)) { + const pk = fields.find((e) => e.is_pk); + if (pk && pk.type === "int") id = parseInt(id); + } + const gen = generateSelect(fields); item = await table?.findFirst({ where, diff --git a/comps/form/typings.ts b/comps/form/typings.ts index 86fb90b..33a8caa 100755 --- a/comps/form/typings.ts +++ b/comps/form/typings.ts @@ -1,5 +1,5 @@ import { GFCol } from "@/gen/utils"; -import { MutableRefObject, ReactNode } from "react"; +import { MutableRefObject, ReactElement, ReactNode } from "react"; import { editorFormData } from "./utils/ed-data"; export type FMProps = { @@ -20,7 +20,7 @@ export type FMProps = { on_load_deps?: any[]; feature?: any[]; sfd_field?: any; - style: "default" | "flex" + style: "default" | "flex"; }; export type GenField = @@ -51,7 +51,7 @@ export type FieldProp = { type: FieldType | (() => FieldType); required: ("y" | "n") | (() => "y" | "n"); field_ref?: (ref: any) => void; - required_msg: (name: string) => string; + required_msg: (name: string) => string | ReactElement; on_change: (arg: { value: any }) => void | Promise; PassProp: any; disabled: "y" | "n"; @@ -109,7 +109,7 @@ export type FMInternal = { error: { readonly object: Record; readonly list: { name: string; error: string[] }[]; - set: (name: string, error: string[]) => void; + set: (name: string, error: (string | ReactElement)[]) => void; get: (name: string) => string[]; clear: (name?: string) => void; }; @@ -256,4 +256,3 @@ export const FieldTypeCustom = `type CustomField = { field: "text", type: "text" | "password" | "number" | "date" | "datetime" } | { field: "relation", type: "has-many" | "has-one" } `; - diff --git a/comps/form/utils/error.ts b/comps/form/utils/error.ts index 79b7e53..4ca2cab 100755 --- a/comps/form/utils/error.ts +++ b/comps/form/utils/error.ts @@ -4,8 +4,6 @@ export const formError = (fm: FMLocal) => { const error = { _internal: {}, get list() { - if (fm.status !== "ready") return []; - const res = Object.entries(this._internal).map(([name, error]) => { return { name, error }; }); @@ -28,7 +26,7 @@ export const formError = (fm: FMLocal) => { return this._internal[name] || []; }, set(name, error) { - this._internal[name] = error; + this._internal[name] = error as any; }, } as FMLocal["error"] & { _internal: Record; diff --git a/comps/form/utils/validate.ts b/comps/form/utils/validate.ts deleted file mode 100755 index 0bd96cb..0000000 --- a/comps/form/utils/validate.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { FMLocal, FieldLocal } from "../typings"; - -export const validate = (field: FieldLocal, fm: FMLocal) => { - if (fm.status !== "ready") return; - - let msg = (name: string) => { - return `${name} harus diisi`; - }; - if (typeof field.required_msg === "function") { - msg = field.required_msg; - } - if (field.required) { - const error_msg = msg(field.name); - const error_list = fm.error.get(field.name).filter((e) => e !== error_msg); - if (!fm.data[field.name]) { - fm.error.set(field.name, [error_msg, ...error_list]); - } else { - fm.error.set(field.name, error_list); - } - } -}; diff --git a/comps/form/utils/validate.tsx b/comps/form/utils/validate.tsx new file mode 100755 index 0000000..e50ebf5 --- /dev/null +++ b/comps/form/utils/validate.tsx @@ -0,0 +1,26 @@ +import { FMLocal, FieldLocal } from "../typings"; + +export const validate = (field: FieldLocal, fm: FMLocal, record?: any) => { + const msg = (name: string) => { + return ( + <> + + {name} + {" "} + is required. + + ); + }; + if (field.required) { + const data = record || fm.data; + const error_msg = msg(field.name); + if (!data[field.name]) { + fm.error.set(field.name, [error_msg]); + } + } +}; diff --git a/exports.tsx b/exports.tsx index a9d9298..67d237b 100755 --- a/exports.tsx +++ b/exports.tsx @@ -61,6 +61,8 @@ export { parseGenField } from "@/gen/utils"; export { filterModifier } from "@/comps/filter/utils/filter-modifier"; export { generateField } from "@/comps/form/gen/gen-field"; export { generateForm } from "@/comps/form/gen/gen-form"; +export { validate as validateField } from "./comps/form/utils/validate"; + export { FMLocal, FieldTypeCustom, diff --git a/gen/gen_form/gen_form.ts b/gen/gen_form/gen_form.ts index 160ce32..53e1976 100755 --- a/gen/gen_form/gen_form.ts +++ b/gen/gen_form/gen_form.ts @@ -1,7 +1,7 @@ +import { on_load } from "lib/comps/form/gen/on_load"; import { codeBuild } from "../master_detail/utils"; import { GFCol, parseGenField } from "../utils"; import { newField } from "./new_field"; -import { on_load } from "./on_load"; import { on_submit } from "./on_submit"; export const gen_form = async (modify: (data: any) => void, data: any) => { @@ -43,7 +43,7 @@ export const gen_form = async (modify: (data: any) => void, data: any) => { const code = {} as any; if (data["on_load"]) { result["on_load"] = data["on_load"]; - result["on_load"].value = on_load({ pk, pks, select, table }); + result["on_load"].value = on_load({ pk: pk.name, pks, select, table }); code.on_load = result["on_load"].value; } diff --git a/gen/gen_form/on_load.ts b/gen/gen_form/on_load.ts deleted file mode 100755 index bd9b3b4..0000000 --- a/gen/gen_form/on_load.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { GFCol } from "../utils"; - -export const on_load = ({ - pk, - table, - select, - pks, - opt, -}: { - pk: GFCol; - table: string; - select: any; - pks: Record; - opt?: { - before_load: string; - after_load: string; - }; -}) => { - const sample: any = {}; - for (const [k, v] of Object.entries(select) as any) { - if (typeof v === "object") { - sample[k] = {}; - - Object.keys(v.select).map((e) => { - sample[k][e] = "sample"; - }); - } else { - sample[k] = "sample"; - } - } - - return `\ -async (opt) => { - if (isEditor) return ${JSON.stringify(sample)}; - - let raw_id = params.id; - if (typeof md === 'object' && md.selected && md.pk) { - const pk = md.pk?.name; - if (md.selected[pk]) { - raw_id = md.selected[pk]; - } - } - if (parseInt(raw_id)) raw_id = parseInt(raw_id); - - ${ - opt?.before_load - ? opt.before_load - : `let id = ${pk.type === "int" ? "parseInt(raw_id)" : "raw_id"};` - } - - let item = {}; - if (id){ - item = await db.${table}.findFirst({ - where: { - ${pk.name}: id, - }, - select: ${JSON.stringify(select, null, 2).split("\n").join("\n ")}, - }); - - ${opt?.after_load ? opt?.after_load : ""} - - return item; - } else { - ${opt?.after_load ? opt?.after_load : ""} - } -}`; -}; diff --git a/preset/login/utils/load.ts b/preset/login/utils/load.ts index 89e645a..a539c41 100755 --- a/preset/login/utils/load.ts +++ b/preset/login/utils/load.ts @@ -5,8 +5,8 @@ const w = window as any; const parse = parser.exportAsFunctionAny("en-US"); export const loadSession = (url_login?: string) => { if (!isEditor) { - let id_site = "" - if (location.hostname === "prasi.avolut.com" ) { + let id_site = ""; + if (location.hostname === "prasi.avolut.com") { const parts = location.pathname.split("/"); id_site = parts[2]; } @@ -25,6 +25,7 @@ export const loadSession = (url_login?: string) => { } } } + return w.user; } else { if (url_login) logout(url_login); } diff --git a/utils/prasi-events.ts b/utils/prasi-events.ts index 4b1e711..43a8536 100755 --- a/utils/prasi-events.ts +++ b/utils/prasi-events.ts @@ -1,13 +1,11 @@ import { FMLocal } from "../.."; import { Prisma } from "../../typings/prisma"; +import { set } from "./set"; const events = { form: { where: async (fm: FMLocal, where: any) => {}, - before_update: async (fm: FMLocal) => {}, - after_update: async (fm: FMLocal) => {}, - before_insert: async (fm: FMLocal) => {}, - after_insert: async (fm: FMLocal) => {}, + before_save: async (fm: FMLocal, record: any) => {}, before_load: async (fm: FMLocal) => {}, after_load: async (fm: FMLocal) => {}, }, @@ -16,16 +14,24 @@ const events = { }, }; -let w = null as any; -if (typeof window !== "undefined") { - w = window; - if (!w.prasi_events) { - w.prasi_events = events; - } -} - type PRASI_EVENT = typeof events; -export const prasi_events: PRASI_EVENT = w.prasi_events; +export const prasi_events = < + K extends keyof PRASI_EVENT, + L extends keyof PRASI_EVENT[K] +>( + k: K, + l: L, + fn?: PRASI_EVENT[K][L] +) => { + const w = window as any; + if (!w.__prasi_custom_events) { + w.__prasi_custom_events = events; + } + if (fn) { + set(w.__prasi_custom_events, `${k}.${l as string}`, fn); + } + return w.__prasi_custom_events?.[k]?.[l]; +}; export const call_prasi_events = async < K extends keyof PRASI_EVENT, L extends keyof PRASI_EVENT[K] @@ -34,7 +40,7 @@ export const call_prasi_events = async < l: L, args: any[] ) => { - const fn = prasi_events?.[k]?.[l] as any; + const fn = prasi_events(k, l); if (fn) { await fn(...args); diff --git a/utils/soft-del-rel.ts b/utils/soft-del-rel.ts index aee748a..dfc4322 100755 --- a/utils/soft-del-rel.ts +++ b/utils/soft-del-rel.ts @@ -1,18 +1,16 @@ import { prasi_gen } from "lib/gen/prasi_gen"; -export const sofDeleteField = async ( - table: string, - field: string -) => { +export const sofDeleteField = async (table: string, field: string) => { const result = {} as any; - const fields =await prasi_gen.prop.fields(table); + const fields = await prasi_gen.prop.fields(table); const value = fields.find((e: any) => { const val = JSON.parse(e.value); if (val.type === "has-one" || val.type === "has-many" || val.is_pk) { return false; } - return (e.label === field); + return e.label === field; }); - if(value) return JSON.parse(value.value) + if (typeof value === "object" && typeof value.value === "string") + return JSON.parse(value.value); return result; };