diff --git a/comps/filter/FilterField.tsx b/comps/filter/FilterField.tsx index 5e36308..88644b2 100755 --- a/comps/filter/FilterField.tsx +++ b/comps/filter/FilterField.tsx @@ -5,6 +5,7 @@ import { FieldTypeText } from "../form/field/type/TypeText"; import { FieldModifier } from "./FieldModifier"; import { useLocal } from "lib/utils/use-local"; import { FieldCheckbox } from "../form/field/type/TypeCheckbox"; +import { SingleOption } from "../form/field/type/TypeSingleOption"; export const FilterField: FC<{ filter: FilterLocal; @@ -42,7 +43,10 @@ export const FilterField: FC<{ type={type} /> ), - opt_get_value: () => { } + onLoad() { + return [{ label: 'halo', 'value': 'asda' }] + }, + subType: "dropdown" })} > {(field) => ( @@ -96,6 +100,9 @@ export const FilterField: FC<{ {type === "boolean" && ( )} + {type === "options" && ( +

Haloha

+ )} )} diff --git a/comps/form/base/BaseForm.tsx b/comps/form/base/BaseForm.tsx index bd48774..add7333 100755 --- a/comps/form/base/BaseForm.tsx +++ b/comps/form/base/BaseForm.tsx @@ -37,7 +37,11 @@ export const BaseForm = >( }, [on_submit]); form.createArg = (arg) => { - const prop: FieldProp = { name: arg.name } as any; + const prop: FieldProp = { + name: arg.name, + on_load: arg.onLoad, + sub_type: arg.subType + } as any; if (arg.onChange) prop.on_change = arg.onChange; return prop; }; diff --git a/comps/form/base/types.ts b/comps/form/base/types.ts index d4f1dc1..d09cd19 100755 --- a/comps/form/base/types.ts +++ b/comps/form/base/types.ts @@ -12,7 +12,8 @@ type CreateFieldArg = { prefix?: ReactNode | (() => ReactNode); onChange?: (value: any) => void; render?: () => void; - opt_get_value?: (value: any) => any + onLoad?: () => { value: string; label: string }[]; + subType?: string }; export type BaseFormLocal = Omit & { diff --git a/comps/form/field/type/TypeButton.tsx b/comps/form/field/type/TypeButton.tsx index 964286e..ffca63b 100755 --- a/comps/form/field/type/TypeButton.tsx +++ b/comps/form/field/type/TypeButton.tsx @@ -43,7 +43,7 @@ export const FieldButton: FC<{ {local.list.map((item) => { let isChecked = false; try { - isChecked = value.some((e: any) => e === item[arg.pk]); + isChecked = value.some((e: any) => e === item.value); } catch (ex) {} return ( diff --git a/comps/form/field/type/TypeCheckbox.tsx b/comps/form/field/type/TypeCheckbox.tsx index bb01f76..57ca0e1 100755 --- a/comps/form/field/type/TypeCheckbox.tsx +++ b/comps/form/field/type/TypeCheckbox.tsx @@ -21,14 +21,15 @@ export const FieldCheckbox: FC<{ else callback(res); }, []); - console.log('arg', arg); - - let value = arg.opt_get_value({ - fm, - name: field.name, - options: local.list, - type: field.type, - }); + let value = + typeof arg.opt_get_value === "function" + ? arg.opt_get_value({ + fm, + name: field.name, + options: local.list, + type: field.type, + }) + : fm.data[field.name]; return ( <> @@ -37,17 +38,18 @@ export const FieldCheckbox: FC<{ {local.list.map((item) => { let isChecked = false; try { - isChecked = value.some((e: any) => e === item[arg.pk]); - } catch (ex) { } + isChecked = value.some((e: any) => e === item.value); + } catch (ex) {} return (
{ let selected = Array.isArray(value) ? value.map((row) => { - return local.list.find((e) => e.value === row); - }) + return local.list.find((e) => e.value === row); + }) : []; + if (isChecked) { selected = selected.filter( (e: any) => e.value !== item.value @@ -56,13 +58,19 @@ export const FieldCheckbox: FC<{ selected.push(item); } - arg.opt_set_value({ - fm, - name: field.name, - selected: selected.map((e) => e.value), - options: local.list, - type: field.type, - }); + if (typeof arg.opt_set_value === "function") { + arg.opt_set_value({ + fm, + name: field.name, + selected: selected.map((e) => e.value), + options: local.list, + type: field.type, + }); + } else { + fm.data[field.name] = selected.map((e) => e.value); + console.log(fm.data); + fm.render(); + } }} className="c-flex c-flex-row c-space-x-1 cursor-pointer c-items-center rounded-full p-0.5" > @@ -92,7 +100,11 @@ export const FieldCheckbox: FC<{ /> )} -
{arg.opt_get_label(item)}
+
+ {typeof arg.opt_get_label === "function" + ? arg.opt_get_label(item) + : item.label} +
); })} diff --git a/comps/form/field/type/TypeDropdown.tsx b/comps/form/field/type/TypeDropdown.tsx index 29783b6..adc6d38 100755 --- a/comps/form/field/type/TypeDropdown.tsx +++ b/comps/form/field/type/TypeDropdown.tsx @@ -1,8 +1,8 @@ import { useLocal } from "@/utils/use-local"; import { FC, useEffect } from "react"; -import { Typeahead } from "../../../../.."; import { FMLocal, FieldLocal, FieldProp } from "../../typings"; import { FieldLoading } from "lib/comps/ui/field-loading"; +import { Typeahead } from "lib/comps/ui/typeahead"; export const TypeDropdown: FC<{ field: FieldLocal; @@ -13,26 +13,38 @@ export const TypeDropdown: FC<{ loaded: false, options: [], }); - let value = arg.opt_get_value({ + let value = typeof arg.opt_get_value === "function" ? arg.opt_get_value({ fm, name: field.name, options: local.options, type: field.type, - }); + }) : fm.data[field.name];; useEffect(() => { if (typeof arg.on_load === "function") { - console.log("masuk") - const options = arg.on_load(); - console.log({options}) + const options = arg.on_load({}); if (options instanceof Promise) { options.then((res) => { - console.log({res}) - local.options = res; + if (Array.isArray(res)) { + const list: any = res.map((e: any) => { + return { + label: arg.opt_get_label({ + label: e.label, + value: e.value, + item: e.data, + }), + value: e.value, + }; + }); + local.options = list; + } else { + local.options = res; + } local.loaded = true; local.render(); }); } else { - local.options = options; + local.loaded = true; + local.options = []; local.render(); } } @@ -45,6 +57,7 @@ export const TypeDropdown: FC<{ { + console.log({ search, item }) if (item) { arg.opt_set_value({ fm, @@ -54,7 +67,6 @@ export const TypeDropdown: FC<{ selected: [item.value], }); } - return item?.value || search; }} allowNew={false} diff --git a/comps/form/field/type/TypeRelation.tsx b/comps/form/field/type/TypeRelation.tsx index ef2342f..b1798e5 100755 --- a/comps/form/field/type/TypeRelation.tsx +++ b/comps/form/field/type/TypeRelation.tsx @@ -2,7 +2,7 @@ import { sortTree } from "@/comps/list/utils/sort-tree"; import { useLocal } from "@/utils/use-local"; import { FC, useEffect } from "react"; import { FMLocal, FieldLocal } from "../../typings"; -import { OptionItem, RawDropdown } from "../raw/Dropdown"; +// import { OptionItem, RawDropdown } from "../raw/Dropdown"; import { FieldLoading } from "../../../ui/field-loading"; export type PropTypeRelation = { @@ -96,121 +96,122 @@ const HasOne: FC<{ PassProp: any; child: any; }> = ({ field, fm, prop, PassProp, child }) => { - const input = useLocal({ - list: null as null | any[], - pk: "", - }); - const name = field.name; - const value = fm.data[name]; - field.input = input; - field.prop = prop; + return <>1223 + // const input = useLocal({ + // list: null as null | any[], + // pk: "", + // }); + // const name = field.name; + // const value = fm.data[name]; + // field.input = input; + // field.prop = prop; - useEffect(() => { - if (!isEditor && input.list === null) { - field.status = "loading"; - field.render(); + // useEffect(() => { + // if (!isEditor && input.list === null) { + // field.status = "loading"; + // field.render(); - const callback = (arg: { items: any[]; pk: string }) => { - input.list = arg.items; - input.pk = arg.pk; - field.status = "ready"; - input.render(); - }; - const res = prop.on_load({ value }); - if (res instanceof Promise) res.then(callback); - else callback(res); - } - }, []); + // const callback = (arg: { items: any[]; pk: string }) => { + // input.list = arg.items; + // input.pk = arg.pk; + // field.status = "ready"; + // input.render(); + // }; + // const res = prop.on_load({ value }); + // if (res instanceof Promise) res.then(callback); + // else callback(res); + // } + // }, []); - let list: OptionItem[] = []; - if (input.list && input.pk && input.list.length) { - if (fm.field_def[name]?.optional) { - list.push({ - value: null, - label: "-", - }); - } + // let list: OptionItem[] = []; + // if (input.list && input.pk && input.list.length) { + // if (fm.field_def[name]?.optional) { + // list.push({ + // value: null, + // label: "-", + // }); + // } - let sorted = input.list; - if (prop.id_parent && input.pk) { - sorted = sortTree(sorted, prop.id_parent, input.pk); - } + // let sorted = input.list; + // if (prop.id_parent && input.pk) { + // sorted = sortTree(sorted, prop.id_parent, input.pk); + // } - for (const item of sorted) { - if (typeof item !== "object") continue; - let label = ""; + // for (const item of sorted) { + // if (typeof item !== "object") continue; + // let label = ""; - if (typeof prop.label === "function") { - label = prop.label(item, input.pk); + // if (typeof prop.label === "function") { + // label = prop.label(item, input.pk); - if (!label) { - const label_arr: string[] = []; + // if (!label) { + // const label_arr: string[] = []; - for (const [k, v] of Object.entries(item)) { - if (k !== input.pk) label_arr.push(v as any); - } - label = label_arr.join(" "); - } - } else { - const label_arr: string[] = []; + // for (const [k, v] of Object.entries(item)) { + // if (k !== input.pk) label_arr.push(v as any); + // } + // label = label_arr.join(" "); + // } + // } else { + // const label_arr: string[] = []; - for (const [k, v] of Object.entries(item)) { - if (k !== input.pk) label_arr.push(v as any); - } - label = label_arr.join(" "); - } + // for (const [k, v] of Object.entries(item)) { + // if (k !== input.pk) label_arr.push(v as any); + // } + // label = label_arr.join(" "); + // } - list.push({ - value: item[input.pk], - label, - el: {child}, - }); - } - } + // list.push({ + // value: item[input.pk], + // label, + // el: {child}, + // }); + // } + // } - let selected = null; - if (value && typeof value === "object") { - if (input.pk) selected = value[input.pk]; - } else { - selected = value; - } + // let selected = null; + // if (value && typeof value === "object") { + // if (input.pk) selected = value[input.pk]; + // } else { + // selected = value; + // } - return ( - <> - {field.status === "loading" ? ( - - ) : ( - { - if (val === null) { - fm.data[name] = null; - fm.render(); - return; - } - if (input.list && input.pk) { - for (const item of input.list) { - if (item[input.pk] === val) { - fm.data[name] = item; - fm.render(); - break; - } - } - } - }} - className="c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full c-h-full" - disabled={field.disabled} - onFocus={() => { - field.focused = true; - field.render(); - }} - onBlur={() => { - field.focused = false; - field.render(); - }} - /> - )} - - ); + // return ( + // <> + // {field.status === "loading" ? ( + // + // ) : ( + // { + // if (val === null) { + // fm.data[name] = null; + // fm.render(); + // return; + // } + // if (input.list && input.pk) { + // for (const item of input.list) { + // if (item[input.pk] === val) { + // fm.data[name] = item; + // fm.render(); + // break; + // } + // } + // } + // }} + // className="c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full c-h-full" + // disabled={field.disabled} + // onFocus={() => { + // field.focused = true; + // field.render(); + // }} + // onBlur={() => { + // field.focused = false; + // field.render(); + // }} + // /> + // )} + // + // ); }; diff --git a/comps/form/gen/fields.ts b/comps/form/gen/fields.ts index f418a19..076eae9 100755 --- a/comps/form/gen/fields.ts +++ b/comps/form/gen/fields.ts @@ -5,6 +5,9 @@ import capitalize from "lodash.capitalize"; import { ArrowBigDown } from "lucide-react"; import { on_load_rel } from "./on_load_rel"; import { createId } from "@paralleldrive/cuid2"; +import { gen_label } from "./gen-label"; +import { get_value } from "./get-value"; +import { set_value } from "./set-value"; export type GFCol = { name: string; type: string; @@ -70,13 +73,14 @@ export const newField = ( }); } else if (["has-many", "has-one"].includes(arg.type) && arg.relation) { const fields = parseGenField(opt.value); - const res = generateSelect(fields); - const load = on_load_rel({ - pk: res.pk, - table: arg.name, - select: res.select, - pks: {}, - }); + const res = generateSelect(fields); + const load = on_load_rel({ + pk: res.pk, + table: arg.name, + select: res.select, + pks: {}, + }); + console.log("halo"); if (["has-one"].includes(arg.type)) { return createItem({ component: { @@ -88,6 +92,27 @@ export const newField = ( sub_type: "dropdown", rel__gen_table: arg.name, opt__on_load: [load], + opt__label: [ + gen_label({ + pk: res.pk, + table: arg.name, + select: res.select, + }), + ], + opt__get_value: [ + get_value({ + pk: res.pk, + table: arg.name, + select: res.select, + }), + ], + opt__set_value: [ + set_value({ + pk: res.pk, + table: arg.name, + select: res.select, + }), + ], child: { childs: [], }, diff --git a/comps/form/gen/gen-label.ts b/comps/form/gen/gen-label.ts new file mode 100755 index 0000000..2cb1993 --- /dev/null +++ b/comps/form/gen/gen-label.ts @@ -0,0 +1,36 @@ +export const gen_label = ({ + pk, + table, + select +}: { + pk: string; + table: string; + select: any; +}) => { + const sample = {} as any; + const cols = []; + for (const [k, v] of Object.entries(select) as any) { + if (k !== pk && typeof v !== "object") { + cols.push(k); + } + } + + return `\ + (row: { value: string; label: string; item?: any }) => { + const cols = ${JSON.stringify(cols)}; + const getLabel = (data: any) => { + const result = []; + cols.map((e) => { + if (data[e]) { + result.push(data[e]); + } + }); + return result.join(" - "); + }; + if (isEditor) { + return row.label; + } + return getLabel(row.item); + } + `; +}; diff --git a/comps/form/gen/get-value.ts b/comps/form/gen/get-value.ts new file mode 100755 index 0000000..27f2164 --- /dev/null +++ b/comps/form/gen/get-value.ts @@ -0,0 +1,42 @@ +export const get_value = ({ + pk, + table, + select +}: { + pk: string; + table: string; + select: any; +}) => { + const sample = {} as any; + const cols = []; + for (const [k, v] of Object.entries(select) as any) { + if (k !== pk && typeof v !== "object") { + cols.push(k); + } + } + return `\ + (arg: { + options: { label: string; value: string; item?: string }[]; + fm: FMLocal; + name: string; + type: string; + }) => { + const { options, fm, name, type } = arg; + if(isEditor){ + return fm.data[name]; + } + let result = null; + result = fm.data[name]; + try{ + const data = fm.data[${table}]; + if(typeof data === "object"){ + if(typeof data?.connect?.${pk} === "string"){ + result = data.connect.${pk}; + } + } + }catch(ex){ + } + return result; + } + `; +}; diff --git a/comps/form/gen/on_load_rel.ts b/comps/form/gen/on_load_rel.ts index 8e7b4ec..370e716 100755 --- a/comps/form/gen/on_load_rel.ts +++ b/comps/form/gen/on_load_rel.ts @@ -64,6 +64,7 @@ export const on_load_rel = ({ return { value: e.${pk}, label: getLabel(e), + data: e, } })) } else { diff --git a/comps/form/gen/set-value.ts b/comps/form/gen/set-value.ts new file mode 100755 index 0000000..b264b5e --- /dev/null +++ b/comps/form/gen/set-value.ts @@ -0,0 +1,38 @@ +export const set_value = ({ + pk, + table, + select +}: { + pk: string; + table: string; + select: any; +}) => { + const sample = {} as any; + const cols = []; + for (const [k, v] of Object.entries(select) as any) { + if (k !== pk && typeof v !== "object") { + cols.push(k); + } + } + return `\ + (arg: { + selected: any[]; + options: { label: string; value: string; item?: string }[]; + fm: FMLocal; + name: string; + type: string; + }) => { + const { selected, options, fm, name, type } = arg; + if (type === "single-option") { + fm.data[name] = { + connect: { + ${pk}: selected[0], + }, + }; + } else { + fm.data[name] = selected.map((e) => e); + } + fm.render(); + } + ` +}; diff --git a/comps/form/typings.ts b/comps/form/typings.ts index f43cc0c..51cd318 100755 --- a/comps/form/typings.ts +++ b/comps/form/typings.ts @@ -58,7 +58,11 @@ export type FieldProp = { width: "auto" | "full" | "¾" | "½" | "⅓" | "¼"; _item: PrasiItem; custom?: () => CustomField; - on_load: (arg?: any) => any | Promise; + on_load: ( + arg?: any + ) => + | { value: string; label: string }[] + | Promise<{ value: string; label: string }[]>; opt_get_label: (row: any) => string; opt_get_value: (arg: { options: { label: string; value: string; item?: string }[]; diff --git a/comps/list/TableList.tsx b/comps/list/TableList.tsx index 1180d30..2a90bc6 100755 --- a/comps/list/TableList.tsx +++ b/comps/list/TableList.tsx @@ -269,6 +269,7 @@ export const TableList: FC = ({ (e: any) => e.name === sub_name || e.name === mode ); if (mode_child) { + console.log({_item}) const tbl = _item.edit.childs[0].edit.childs.find( (e) => get(e, "id") === mode_child.id ); @@ -639,6 +640,7 @@ const dataGridStyle = (local: { height: number }) => css` } div[role="columnheader"] span svg { margin: 12px 2px; + /* color: #ffffff */ } div[aria-selected="true"] { outline: none; diff --git a/comps/ui/typeahead.tsx b/comps/ui/typeahead.tsx index a0d3221..2af03ef 100755 --- a/comps/ui/typeahead.tsx +++ b/comps/ui/typeahead.tsx @@ -334,15 +334,20 @@ export const Typeahead: FC<{ searching={local.search.searching} onSelect={(value) => { local.open = false; - local.value.push(value); resetSearch(); if (local.mode === "single") { const item = local.options.find((item) => item.value === value); if (item) { local.search.input = item.label; + + select({ + search: local.search.input, + item, + }); } } + local.render(); }} width={local.auto_popup_width ? input.current?.offsetWidth : undefined} diff --git a/preset/login/Login.tsx b/preset/login/Login.tsx index c91507f..b39e95b 100755 --- a/preset/login/Login.tsx +++ b/preset/login/Login.tsx @@ -13,6 +13,7 @@ export type LGProps = { export const Login: FC = (props) => { w.prasi_home = props.url_home[0]; + console.log("render?"); try { const home = prasi_user.prasi_home[prasi_user.user.m_role.name]; navigate(home);