This commit is contained in:
rizrmd 2024-06-03 00:24:41 -07:00
parent 0e1fa9f6f4
commit d257667ea3
16 changed files with 340 additions and 149 deletions

View File

@ -5,6 +5,7 @@ import { FieldTypeText } from "../form/field/type/TypeText";
import { FieldModifier } from "./FieldModifier"; import { FieldModifier } from "./FieldModifier";
import { useLocal } from "lib/utils/use-local"; import { useLocal } from "lib/utils/use-local";
import { FieldCheckbox } from "../form/field/type/TypeCheckbox"; import { FieldCheckbox } from "../form/field/type/TypeCheckbox";
import { SingleOption } from "../form/field/type/TypeSingleOption";
export const FilterField: FC<{ export const FilterField: FC<{
filter: FilterLocal; filter: FilterLocal;
@ -42,7 +43,10 @@ export const FilterField: FC<{
type={type} type={type}
/> />
), ),
opt_get_value: () => { } onLoad() {
return [{ label: 'halo', 'value': 'asda' }]
},
subType: "dropdown"
})} })}
> >
{(field) => ( {(field) => (
@ -96,6 +100,9 @@ export const FilterField: FC<{
{type === "boolean" && ( {type === "boolean" && (
<FieldCheckbox arg={field.arg} field={field.field} fm={field.fm} /> <FieldCheckbox arg={field.arg} field={field.field} fm={field.fm} />
)} )}
{type === "options" && (
<p>Haloha</p>
)}
</> </>
)} )}
</BaseField > </BaseField >

View File

@ -37,7 +37,11 @@ export const BaseForm = <T extends Record<string, any>>(
}, [on_submit]); }, [on_submit]);
form.createArg = (arg) => { 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; if (arg.onChange) prop.on_change = arg.onChange;
return prop; return prop;
}; };

View File

@ -12,7 +12,8 @@ type CreateFieldArg = {
prefix?: ReactNode | (() => ReactNode); prefix?: ReactNode | (() => ReactNode);
onChange?: (value: any) => void; onChange?: (value: any) => void;
render?: () => void; render?: () => void;
opt_get_value?: (value: any) => any onLoad?: () => { value: string; label: string }[];
subType?: string
}; };
export type BaseFormLocal<T> = Omit<typeof default_base_form_local, "data"> & { export type BaseFormLocal<T> = Omit<typeof default_base_form_local, "data"> & {

View File

@ -43,7 +43,7 @@ export const FieldButton: FC<{
{local.list.map((item) => { {local.list.map((item) => {
let isChecked = false; let isChecked = false;
try { try {
isChecked = value.some((e: any) => e === item[arg.pk]); isChecked = value.some((e: any) => e === item.value);
} catch (ex) {} } catch (ex) {}
return ( return (

View File

@ -21,14 +21,15 @@ export const FieldCheckbox: FC<{
else callback(res); else callback(res);
}, []); }, []);
console.log('arg', arg); let value =
typeof arg.opt_get_value === "function"
let value = arg.opt_get_value({ ? arg.opt_get_value({
fm, fm,
name: field.name, name: field.name,
options: local.list, options: local.list,
type: field.type, type: field.type,
}); })
: fm.data[field.name];
return ( return (
<> <>
@ -37,17 +38,18 @@ export const FieldCheckbox: FC<{
{local.list.map((item) => { {local.list.map((item) => {
let isChecked = false; let isChecked = false;
try { try {
isChecked = value.some((e: any) => e === item[arg.pk]); isChecked = value.some((e: any) => e === item.value);
} catch (ex) { } } catch (ex) {}
return ( return (
<div <div
onClick={() => { onClick={() => {
let selected = Array.isArray(value) let selected = Array.isArray(value)
? value.map((row) => { ? value.map((row) => {
return local.list.find((e) => e.value === row); return local.list.find((e) => e.value === row);
}) })
: []; : [];
if (isChecked) { if (isChecked) {
selected = selected.filter( selected = selected.filter(
(e: any) => e.value !== item.value (e: any) => e.value !== item.value
@ -56,13 +58,19 @@ export const FieldCheckbox: FC<{
selected.push(item); selected.push(item);
} }
arg.opt_set_value({ if (typeof arg.opt_set_value === "function") {
fm, arg.opt_set_value({
name: field.name, fm,
selected: selected.map((e) => e.value), name: field.name,
options: local.list, selected: selected.map((e) => e.value),
type: field.type, 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" 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<{
/> />
</svg> </svg>
)} )}
<div className="">{arg.opt_get_label(item)}</div> <div className="">
{typeof arg.opt_get_label === "function"
? arg.opt_get_label(item)
: item.label}
</div>
</div> </div>
); );
})} })}

View File

@ -1,8 +1,8 @@
import { useLocal } from "@/utils/use-local"; import { useLocal } from "@/utils/use-local";
import { FC, useEffect } from "react"; import { FC, useEffect } from "react";
import { Typeahead } from "../../../../..";
import { FMLocal, FieldLocal, FieldProp } from "../../typings"; import { FMLocal, FieldLocal, FieldProp } from "../../typings";
import { FieldLoading } from "lib/comps/ui/field-loading"; import { FieldLoading } from "lib/comps/ui/field-loading";
import { Typeahead } from "lib/comps/ui/typeahead";
export const TypeDropdown: FC<{ export const TypeDropdown: FC<{
field: FieldLocal; field: FieldLocal;
@ -13,26 +13,38 @@ export const TypeDropdown: FC<{
loaded: false, loaded: false,
options: [], options: [],
}); });
let value = arg.opt_get_value({ let value = typeof arg.opt_get_value === "function" ? arg.opt_get_value({
fm, fm,
name: field.name, name: field.name,
options: local.options, options: local.options,
type: field.type, type: field.type,
}); }) : fm.data[field.name];;
useEffect(() => { useEffect(() => {
if (typeof arg.on_load === "function") { if (typeof arg.on_load === "function") {
console.log("masuk") const options = arg.on_load({});
const options = arg.on_load();
console.log({options})
if (options instanceof Promise) { if (options instanceof Promise) {
options.then((res) => { options.then((res) => {
console.log({res}) if (Array.isArray(res)) {
local.options = 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.loaded = true;
local.render(); local.render();
}); });
} else { } else {
local.options = options; local.loaded = true;
local.options = [];
local.render(); local.render();
} }
} }
@ -45,6 +57,7 @@ export const TypeDropdown: FC<{
<Typeahead <Typeahead
value={value} value={value}
onSelect={({ search, item }) => { onSelect={({ search, item }) => {
console.log({ search, item })
if (item) { if (item) {
arg.opt_set_value({ arg.opt_set_value({
fm, fm,
@ -54,7 +67,6 @@ export const TypeDropdown: FC<{
selected: [item.value], selected: [item.value],
}); });
} }
return item?.value || search; return item?.value || search;
}} }}
allowNew={false} allowNew={false}

View File

@ -2,7 +2,7 @@ import { sortTree } from "@/comps/list/utils/sort-tree";
import { useLocal } from "@/utils/use-local"; import { useLocal } from "@/utils/use-local";
import { FC, useEffect } from "react"; import { FC, useEffect } from "react";
import { FMLocal, FieldLocal } from "../../typings"; import { FMLocal, FieldLocal } from "../../typings";
import { OptionItem, RawDropdown } from "../raw/Dropdown"; // import { OptionItem, RawDropdown } from "../raw/Dropdown";
import { FieldLoading } from "../../../ui/field-loading"; import { FieldLoading } from "../../../ui/field-loading";
export type PropTypeRelation = { export type PropTypeRelation = {
@ -96,121 +96,122 @@ const HasOne: FC<{
PassProp: any; PassProp: any;
child: any; child: any;
}> = ({ field, fm, prop, PassProp, child }) => { }> = ({ field, fm, prop, PassProp, child }) => {
const input = useLocal({ return <>1223</>
list: null as null | any[], // const input = useLocal({
pk: "", // list: null as null | any[],
}); // pk: "",
const name = field.name; // });
const value = fm.data[name]; // const name = field.name;
field.input = input; // const value = fm.data[name];
field.prop = prop; // field.input = input;
// field.prop = prop;
useEffect(() => { // useEffect(() => {
if (!isEditor && input.list === null) { // if (!isEditor && input.list === null) {
field.status = "loading"; // field.status = "loading";
field.render(); // field.render();
const callback = (arg: { items: any[]; pk: string }) => { // const callback = (arg: { items: any[]; pk: string }) => {
input.list = arg.items; // input.list = arg.items;
input.pk = arg.pk; // input.pk = arg.pk;
field.status = "ready"; // field.status = "ready";
input.render(); // input.render();
}; // };
const res = prop.on_load({ value }); // const res = prop.on_load({ value });
if (res instanceof Promise) res.then(callback); // if (res instanceof Promise) res.then(callback);
else callback(res); // else callback(res);
} // }
}, []); // }, []);
let list: OptionItem[] = []; // let list: OptionItem[] = [];
if (input.list && input.pk && input.list.length) { // if (input.list && input.pk && input.list.length) {
if (fm.field_def[name]?.optional) { // if (fm.field_def[name]?.optional) {
list.push({ // list.push({
value: null, // value: null,
label: "-", // label: "-",
}); // });
} // }
let sorted = input.list; // let sorted = input.list;
if (prop.id_parent && input.pk) { // if (prop.id_parent && input.pk) {
sorted = sortTree(sorted, prop.id_parent, input.pk); // sorted = sortTree(sorted, prop.id_parent, input.pk);
} // }
for (const item of sorted) { // for (const item of sorted) {
if (typeof item !== "object") continue; // if (typeof item !== "object") continue;
let label = ""; // let label = "";
if (typeof prop.label === "function") { // if (typeof prop.label === "function") {
label = prop.label(item, input.pk); // label = prop.label(item, input.pk);
if (!label) { // if (!label) {
const label_arr: string[] = []; // const label_arr: string[] = [];
for (const [k, v] of Object.entries(item)) { // for (const [k, v] of Object.entries(item)) {
if (k !== input.pk) label_arr.push(v as any); // if (k !== input.pk) label_arr.push(v as any);
} // }
label = label_arr.join(" "); // label = label_arr.join(" ");
} // }
} else { // } else {
const label_arr: string[] = []; // const label_arr: string[] = [];
for (const [k, v] of Object.entries(item)) { // for (const [k, v] of Object.entries(item)) {
if (k !== input.pk) label_arr.push(v as any); // if (k !== input.pk) label_arr.push(v as any);
} // }
label = label_arr.join(" "); // label = label_arr.join(" ");
} // }
list.push({ // list.push({
value: item[input.pk], // value: item[input.pk],
label, // label,
el: <PassProp item={item}>{child}</PassProp>, // el: <PassProp item={item}>{child}</PassProp>,
}); // });
} // }
} // }
let selected = null; // let selected = null;
if (value && typeof value === "object") { // if (value && typeof value === "object") {
if (input.pk) selected = value[input.pk]; // if (input.pk) selected = value[input.pk];
} else { // } else {
selected = value; // selected = value;
} // }
return ( // return (
<> // <>
{field.status === "loading" ? ( // {field.status === "loading" ? (
<FieldLoading /> // <FieldLoading />
) : ( // ) : (
<RawDropdown // <RawDropdown
options={list} // options={list}
value={selected} // value={selected}
onChange={(val) => { // onChange={(val) => {
if (val === null) { // if (val === null) {
fm.data[name] = null; // fm.data[name] = null;
fm.render(); // fm.render();
return; // return;
} // }
if (input.list && input.pk) { // if (input.list && input.pk) {
for (const item of input.list) { // for (const item of input.list) {
if (item[input.pk] === val) { // if (item[input.pk] === val) {
fm.data[name] = item; // fm.data[name] = item;
fm.render(); // fm.render();
break; // break;
} // }
} // }
} // }
}} // }}
className="c-flex-1 c-bg-transparent c-outline-none c-px-2 c-text-sm c-w-full c-h-full" // 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} // disabled={field.disabled}
onFocus={() => { // onFocus={() => {
field.focused = true; // field.focused = true;
field.render(); // field.render();
}} // }}
onBlur={() => { // onBlur={() => {
field.focused = false; // field.focused = false;
field.render(); // field.render();
}} // }}
/> // />
)} // )}
</> // </>
); // );
}; };

View File

@ -5,6 +5,9 @@ import capitalize from "lodash.capitalize";
import { ArrowBigDown } from "lucide-react"; import { ArrowBigDown } from "lucide-react";
import { on_load_rel } from "./on_load_rel"; import { on_load_rel } from "./on_load_rel";
import { createId } from "@paralleldrive/cuid2"; 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 = { export type GFCol = {
name: string; name: string;
type: string; type: string;
@ -70,13 +73,14 @@ export const newField = (
}); });
} else if (["has-many", "has-one"].includes(arg.type) && arg.relation) { } else if (["has-many", "has-one"].includes(arg.type) && arg.relation) {
const fields = parseGenField(opt.value); const fields = parseGenField(opt.value);
const res = generateSelect(fields); const res = generateSelect(fields);
const load = on_load_rel({ const load = on_load_rel({
pk: res.pk, pk: res.pk,
table: arg.name, table: arg.name,
select: res.select, select: res.select,
pks: {}, pks: {},
}); });
console.log("halo");
if (["has-one"].includes(arg.type)) { if (["has-one"].includes(arg.type)) {
return createItem({ return createItem({
component: { component: {
@ -88,6 +92,27 @@ export const newField = (
sub_type: "dropdown", sub_type: "dropdown",
rel__gen_table: arg.name, rel__gen_table: arg.name,
opt__on_load: [load], 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: { child: {
childs: [], childs: [],
}, },

36
comps/form/gen/gen-label.ts Executable file
View File

@ -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);
}
`;
};

42
comps/form/gen/get-value.ts Executable file
View File

@ -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;
}
`;
};

View File

@ -64,6 +64,7 @@ export const on_load_rel = ({
return { return {
value: e.${pk}, value: e.${pk},
label: getLabel(e), label: getLabel(e),
data: e,
} }
})) }))
} else { } else {

38
comps/form/gen/set-value.ts Executable file
View File

@ -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();
}
`
};

View File

@ -58,7 +58,11 @@ export type FieldProp = {
width: "auto" | "full" | "¾" | "½" | "⅓" | "¼"; width: "auto" | "full" | "¾" | "½" | "⅓" | "¼";
_item: PrasiItem; _item: PrasiItem;
custom?: () => CustomField; custom?: () => CustomField;
on_load: (arg?: any) => any | Promise<any>; on_load: (
arg?: any
) =>
| { value: string; label: string }[]
| Promise<{ value: string; label: string }[]>;
opt_get_label: (row: any) => string; opt_get_label: (row: any) => string;
opt_get_value: (arg: { opt_get_value: (arg: {
options: { label: string; value: string; item?: string }[]; options: { label: string; value: string; item?: string }[];

View File

@ -269,6 +269,7 @@ export const TableList: FC<TableListProp> = ({
(e: any) => e.name === sub_name || e.name === mode (e: any) => e.name === sub_name || e.name === mode
); );
if (mode_child) { if (mode_child) {
console.log({_item})
const tbl = _item.edit.childs[0].edit.childs.find( const tbl = _item.edit.childs[0].edit.childs.find(
(e) => get(e, "id") === mode_child.id (e) => get(e, "id") === mode_child.id
); );
@ -639,6 +640,7 @@ const dataGridStyle = (local: { height: number }) => css`
} }
div[role="columnheader"] span svg { div[role="columnheader"] span svg {
margin: 12px 2px; margin: 12px 2px;
/* color: #ffffff */
} }
div[aria-selected="true"] { div[aria-selected="true"] {
outline: none; outline: none;

View File

@ -334,15 +334,20 @@ export const Typeahead: FC<{
searching={local.search.searching} searching={local.search.searching}
onSelect={(value) => { onSelect={(value) => {
local.open = false; local.open = false;
local.value.push(value);
resetSearch(); resetSearch();
if (local.mode === "single") { if (local.mode === "single") {
const item = local.options.find((item) => item.value === value); const item = local.options.find((item) => item.value === value);
if (item) { if (item) {
local.search.input = item.label; local.search.input = item.label;
select({
search: local.search.input,
item,
});
} }
} }
local.render(); local.render();
}} }}
width={local.auto_popup_width ? input.current?.offsetWidth : undefined} width={local.auto_popup_width ? input.current?.offsetWidth : undefined}

View File

@ -13,6 +13,7 @@ export type LGProps = {
export const Login: FC<LGProps> = (props) => { export const Login: FC<LGProps> = (props) => {
w.prasi_home = props.url_home[0]; w.prasi_home = props.url_home[0];
console.log("render?");
try { try {
const home = prasi_user.prasi_home[prasi_user.user.m_role.name]; const home = prasi_user.prasi_home[prasi_user.user.m_role.name];
navigate(home); navigate(home);