This commit is contained in:
rizky 2024-08-19 18:18:17 -07:00
parent 5fff3856f0
commit 73ae85841b
12 changed files with 232 additions and 169 deletions

View File

@ -114,6 +114,8 @@ export const Detail: FC<{
if (typeof values !== "object" || values === null) return null; if (typeof values !== "object" || values === null) return null;
const entries = Object.entries(values); const entries = Object.entries(values);
console.log(entries)
return ( return (
<div <div
className={cx( className={cx(

View File

@ -296,13 +296,13 @@ export const ImgThumb = ({
url, url,
w, w,
h, h,
fit fit,
}: { }: {
className?: string; className?: string;
url: string; url: string;
w: number; w: number;
h: number; h: number;
fit?: 'cover' | 'contain', fit?: "cover" | "contain" | "inside" | "fill" | "outside";
}) => { }) => {
const local = useLocal({ error: false }); const local = useLocal({ error: false });
return ( return (
@ -329,7 +329,9 @@ export const ImgThumb = ({
local.render(); local.render();
}} }}
src={siteurl( src={siteurl(
`/_img/${url.substring("_file/".length)}?w=${w}&h=${h}&fit=${fit || 'cover'}` `/_img/${url.substring("_file/".length)}?w=${w}&h=${h}&fit=${
fit || "cover"
}`
)} )}
/> />
)} )}

View File

@ -1,3 +1,4 @@
import { kvToJSON } from "lib/utils/kv-to-json";
import { useLocal } from "lib/utils/use-local"; import { useLocal } from "lib/utils/use-local";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
@ -7,7 +8,7 @@ export const KeyValue = ({
index, index,
}: { }: {
value: any; value: any;
onChange: (val: any) => void; onChange?: (val: any) => void;
index?: "preserve" | "auto-sort"; index?: "preserve" | "auto-sort";
}) => { }) => {
const local = useLocal({ const local = useLocal({
@ -48,18 +49,9 @@ export const KeyValue = ({
if (typeof value !== "object") return null; if (typeof value !== "object") return null;
const reverseEntries = (input: [string, unknown][]) => { console.log(value);
return input
.filter(([k, v]) => {
return true; // some irrelevant conditions here
})
.reduce((accum: any, [k, v]) => {
accum[k] = v;
return accum;
}, {});
};
return ( return (
<div className="c-flex c-relative c-flex-1" ref={ref}> <div className="c-flex c-relative c-flex-1 key-value" ref={ref}>
<table <table
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@ -67,6 +59,10 @@ export const KeyValue = ({
}} }}
className={cx( className={cx(
"c-flex-1", "c-flex-1",
!onChange &&
css`
border: 1px solid #ececeb;
`,
css` css`
input { input {
width: 100%; width: 100%;
@ -88,54 +84,60 @@ export const KeyValue = ({
key={idx} key={idx}
item={item} item={item}
idx={idx} idx={idx}
update={(idx, k, v) => { update={
local.entries[idx] = [k, v]; onChange
? (idx, k, v) => {
local.entries[idx] = [k, v];
if (k === "" && v === "") { if (k === "" && v === "") {
local.entries.splice(idx, 1); local.entries.splice(idx, 1);
} }
local.render(); local.render();
}} }
: undefined
}
onBlur={() => { onBlur={() => {
if (index === "preserve") { if (index === "preserve") {
onChange([...local.entries]); onChange?.([...local.entries]);
} else { } else {
onChange(reverseEntries(local.entries)); onChange?.(kvToJSON(local.entries));
} }
}} }}
/> />
))} ))}
<KVRow {onChange && (
item={[local.new.key, local.new.value]} <KVRow
idx={local.entries.length} item={[local.new.key, local.new.value]}
update={(idx, k, v) => { idx={local.entries.length}
local.new.key = k; update={(idx, k, v) => {
local.new.value = v; local.new.key = k;
local.render(); local.new.value = v;
}}
onBlur={(field, val) => {
if (field === "key" && val) {
const idx = local.entries.length;
local.entries[idx] = [local.new.key, local.new.value];
local.new.key = "";
local.new.value = "";
local.render(); local.render();
if (index === "preserve") { }}
onChange([...local.entries]); onBlur={(field, val) => {
} else { if (field === "key" && val) {
onChange(reverseEntries(local.entries)); const idx = local.entries.length;
local.entries[idx] = [local.new.key, local.new.value];
local.new.key = "";
local.new.value = "";
local.render();
if (index === "preserve") {
onChange?.([...local.entries]);
} else {
onChange?.(kvToJSON(local.entries));
}
setTimeout(() => {
(
ref?.current?.querySelector(
`.kv-row-${idx} .kv-value input`
) as HTMLInputElement
)?.focus();
}, 10);
} }
setTimeout(() => { }}
( />
ref?.current?.querySelector( )}
`.kv-row-${idx} .kv-value input`
) as HTMLInputElement
)?.focus();
}, 10);
}
}}
/>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -150,7 +152,7 @@ const KVRow = ({
}: { }: {
item: [string, unknown]; item: [string, unknown];
idx: number; idx: number;
update: (idx: number, key: string, value: string) => void; update?: (idx: number, key: string, value: string) => void;
onBlur?: (field: "key" | "value", val: string) => void; onBlur?: (field: "key" | "value", val: string) => void;
}) => { }) => {
const [k, v] = item as any; const [k, v] = item as any;
@ -172,22 +174,26 @@ const KVRow = ({
` `
)} )}
> >
<input {update ? (
type="text" <input
spellCheck={false} type="text"
value={k} spellCheck={false}
onChange={(e) => { value={k}
update(idx, e.currentTarget.value, v || ""); onChange={(e) => {
}} update(idx, e.currentTarget.value, v || "");
onBlur={ }}
onBlur onBlur={
? (e) => { onBlur
onBlur("key", e.currentTarget.value); ? (e) => {
} onBlur("key", e.currentTarget.value);
: undefined }
} : undefined
ref={keyref} }
></input> ref={keyref}
></input>
) : (
k
)}
</td> </td>
<td <td
className={cx( className={cx(
@ -198,27 +204,31 @@ const KVRow = ({
` `
)} )}
> >
<input {update ? (
type="text" <input
spellCheck={false} type="text"
value={v || ""} spellCheck={false}
onChange={(e) => { value={v || ""}
update(idx, k, e.currentTarget.value || ""); onChange={(e) => {
}} update(idx, k, e.currentTarget.value || "");
onKeyUp={(e) => { }}
if (e.key === "Backspace" && !e.currentTarget.value) { onKeyUp={(e) => {
keyref.current?.focus(); if (e.key === "Backspace" && !e.currentTarget.value) {
keyref.current?.focus();
}
}}
onBlur={
onBlur
? (e) => {
onBlur("value", e.currentTarget.value);
}
: undefined
} }
}} ref={valref}
onBlur={ ></input>
onBlur ) : (
? (e) => { v
onBlur("value", e.currentTarget.value); )}
}
: undefined
}
ref={valref}
></input>
</td> </td>
</tr> </tr>
); );

View File

@ -129,7 +129,7 @@ const formatCurrency = (value: any) => {
return (isNegative ? "-" : "") + rupiah; return (isNegative ? "-" : "") + rupiah;
} }
}; };
export const formatMoney = (res: number) => { export const formatMoney = (res: any) => {
const formattedAmount = new Intl.NumberFormat("id-ID", { const formattedAmount = new Intl.NumberFormat("id-ID", {
minimumFractionDigits: 0, minimumFractionDigits: 0,
}).format(res); }).format(res);

View File

@ -81,7 +81,7 @@ export const TLSlider: FC<{
})} })}
</div> </div>
) : ( ) : (
<div className="c-flex c-items-center c-justify-center c-flex-1 w-full h-full c-flex-col "> <div className="c-flex c-items-center c-justify-center c-flex-1 w-full h-full c-flex-col c-py-10 ">
<Sticker size={35} strokeWidth={1} /> <Sticker size={35} strokeWidth={1} />
<div className="c-pt-1 c-text-center"> <div className="c-pt-1 c-text-center">
No&nbsp;Data No&nbsp;Data

View File

@ -39,6 +39,7 @@ import { sortTree } from "./utils/sort-tree";
import { TLList } from "./TLList"; import { TLList } from "./TLList";
import { OnRowClick } from "./utils/type"; import { OnRowClick } from "./utils/type";
import { TLSlider } from "./TLSlider"; import { TLSlider } from "./TLSlider";
import { getPathname } from "lib/exports";
let EMPTY_SET = new Set() as ReadonlySet<any>; let EMPTY_SET = new Set() as ReadonlySet<any>;
@ -253,6 +254,7 @@ export const TableList: FC<TableListProp> = ({
skip: local.paging.skip, skip: local.paging.skip,
}, },
}; };
if (id_parent) { if (id_parent) {
load_args.paging = {}; load_args.paging = {};
} }
@ -261,7 +263,8 @@ export const TableList: FC<TableListProp> = ({
if ( if (
id_parent || id_parent ||
!local.paging || !local.paging ||
(local.paging && !local.paging.take) (local.paging && !local.paging.take) ||
local.paging.skip === 0
) { ) {
local.data = data; local.data = data;
} else { } else {

View File

@ -95,14 +95,19 @@ export const ScrollArea = lazify(
async () => (await import("@/comps/ui/scroll-area")).ScrollArea async () => (await import("@/comps/ui/scroll-area")).ScrollArea
); );
export const KeyValue = lazify(
async () => (await import("@/comps/form/field/type/KeyValue")).KeyValue
);
export { fetchLinkParams } from "@/comps/form/field/type/TypeLink"; export { fetchLinkParams } from "@/comps/form/field/type/TypeLink";
export { FieldLoading } from "@/comps/ui/field-loading"; export { FieldLoading, Spinner } from "@/comps/ui/field-loading";
export { lang } from "lib/lang"; export { lang } from "lib/lang";
export { prasi_gen } from "./gen/prasi_gen"; export { prasi_gen } from "./gen/prasi_gen";
export { guessLabel } from "./utils/guess-label"; export { guessLabel } from "./utils/guess-label";
import __get from "lodash.get"; import __get from "lodash.get";
import { sum } from "./utils/sum"; import { sum } from "./utils/sum";
export { kvToJSON } from "./utils/kv-to-json";
export { overrideNav } from "./utils/override-nav";
export const _sum = sum; export const _sum = sum;
export const _get = __get; export const _get = __get;
@ -126,14 +131,14 @@ export {
fieldType, fieldType,
FieldTypeCustom, FieldTypeCustom,
FMLocal, FMLocal,
formType formType,
} from "@/comps/form/typings"; } from "@/comps/form/typings";
export { TableListType } from "@/comps/list/utils/typings"; export { TableListType } from "@/comps/list/utils/typings";
export { generateTableList as generateTableList } from "@/comps/md/gen/gen-table-list"; export { generateTableList as generateTableList } from "@/comps/md/gen/gen-table-list";
export { generateSelect } from "@/comps/md/gen/md-select"; export { generateSelect } from "@/comps/md/gen/md-select";
export { MasterDetailType } from "@/comps/md/utils/typings"; export { MasterDetailType } from "@/comps/md/utils/typings";
export { Button, FloatButton } from "@/comps/ui/button"; export { Button, FloatButton } from "@/comps/ui/button";
export { baseurl } from "@/utils/baseurl"; export { baseurl, imgThumb } from "@/utils/baseurl";
export { FormatValue } from "@/utils/format-value"; export { FormatValue } from "@/utils/format-value";
export { GetValue } from "@/utils/get-value"; export { GetValue } from "@/utils/get-value";
export { password } from "@/utils/password"; export { password } from "@/utils/password";
@ -146,7 +151,7 @@ export { logout } from "@/preset/login/utils/logout";
export { export {
registerSession, registerSession,
RG, RG,
UserSession UserSession,
} from "@/preset/login/utils/register"; } from "@/preset/login/utils/register";
export { Card } from "@/comps/custom/Card"; export { Card } from "@/comps/custom/Card";

View File

@ -5,6 +5,7 @@ import { getPathname } from "lib/utils/pathname";
import { useLocal } from "lib/utils/use-local"; import { useLocal } from "lib/utils/use-local";
import { FC, ReactNode, useLayoutEffect } from "react"; import { FC, ReactNode, useLayoutEffect } from "react";
import { loadSession } from "../login/utils/load"; import { loadSession } from "../login/utils/load";
import { overrideNav } from "lib/utils/override-nav";
const w = window as any; const w = window as any;
const initResponsive = function () { const initResponsive = function () {
@ -69,75 +70,7 @@ export const Layout: FC<LYTChild> = (props) => {
const path = getPathname(); const path = getPathname();
const no_layout = props.exception; const no_layout = props.exception;
if (!w.prasi_menu && !isEditor) { overrideNav({ local });
w.prasi_menu = { nav_override: true, nav: w.navigate, pm: null };
w.navigate = (async (_href, params) => {
if (!_href) {
console.error("Failed to navigate, empty url");
return;
}
if (_href.startsWith("/")) {
const url = new URL(location.href);
const newurl = new URL(`${url.protocol}//${url.host}${_href}`);
const pathname = newurl.pathname;
_href = baseurl(_href);
if (params) {
const prefix: LinkParam["prefix"] =
params.breads?.map((e) => {
return {
label: e.label,
url: e.url || getPathname({ hash: true }),
};
}) || [];
const values: LinkParam = {
name: params.name,
url: getPathname({ hash: true }),
prefix,
hash: "",
create: params.create,
update: params.update,
where: params.where,
};
const vhash = hashSum(values);
values.hash = vhash;
await api._kv("set", vhash, values);
const lnk = location.hash
.split("#")
.find((e) => e.startsWith("lnk="));
let prev_link = "";
if (lnk) {
prev_link = lnk.split("=").pop() || "";
if (prev_link) prev_link = prev_link + "+";
}
_href = `${_href}#lnk=${prev_link + vhash}`;
}
if (preloaded(pathname)) {
w.prasi_menu.nav(_href);
} else if (w.prasi_menu.pm?.on_load) {
let done = { exec: () => {} };
local.loading = true;
local.render();
w.prasi_menu.pm?.on_load((exec: any) => {
done.exec = exec;
});
await preload(pathname);
setTimeout(() => {
w.prasi_menu.nav(_href);
done.exec();
}, 500);
} else {
await preload(pathname);
w.prasi_menu.nav(_href);
}
}
}) as typeof navigate;
}
if ( if (
!isEditor && !isEditor &&

View File

@ -6,3 +6,21 @@ export const baseurl = (url: string) => {
} }
return url; return url;
}; };
export const imgThumb = ({
url,
w,
h,
fit,
}: {
url: string;
w: number;
h: number;
fit?: "cover" | "contain" | "inside" | "fill" | "outside";
}) => {
return siteurl(
`/_img/${url.substring("_file/".length)}?w=${w}&h=${h}&fit=${
fit || "cover"
}`
);
};

View File

@ -1,3 +1,4 @@
const w = window as any; const w = window as any;
if (typeof isEditor === "undefined") { if (typeof isEditor === "undefined") {
if ( if (

10
utils/kv-to-json.ts Executable file
View File

@ -0,0 +1,10 @@
export const kvToJSON = (input: [string, unknown][]) => {
return input
.filter(([k, v]) => {
return true; // some irrelevant conditions here
})
.reduce((accum: any, [k, v]) => {
accum[k] = v;
return accum;
}, {}) as Record<string, any>;
};

79
utils/override-nav.ts Executable file
View File

@ -0,0 +1,79 @@
import { LinkParam } from "lib/comps/form/field/type/TypeLink";
import { hashSum } from "lib/utils/hash-sum";
import { getPathname } from "lib/utils/pathname";
const w = window as any;
export const overrideNav = (arg?: { local?: any }) => {
if (!w.prasi_menu && !isEditor) {
w.prasi_menu = { nav_override: true, nav: w.navigate, pm: null };
w.navigate = (async (_href, params) => {
if (!_href) {
console.error("Failed to navigate, empty url");
return;
}
if (_href.startsWith("/")) {
const url = new URL(location.href);
const newurl = new URL(`${url.protocol}//${url.host}${_href}`);
const pathname = newurl.pathname;
_href = baseurl(_href);
if (params) {
const prefix: LinkParam["prefix"] =
params.breads?.map((e) => {
return {
label: e.label,
url: e.url || getPathname({ hash: true }),
};
}) || [];
const values: LinkParam = {
name: params.name,
url: getPathname({ hash: true }),
prefix,
hash: "",
create: params.create,
update: params.update,
where: params.where,
};
const vhash = hashSum(values);
values.hash = vhash;
await api._kv("set", vhash, values);
const lnk = location.hash
.split("#")
.find((e) => e.startsWith("lnk="));
let prev_link = "";
if (lnk) {
prev_link = lnk.split("=").pop() || "";
if (prev_link) prev_link = prev_link + "+";
}
_href = `${_href}#lnk=${prev_link + vhash}`;
}
if (preloaded(pathname)) {
w.prasi_menu.nav(_href);
} else if (w.prasi_menu.pm?.on_load) {
let done = { exec: () => {} };
if (arg?.local) {
arg.local.loading = true;
arg.local.render();
}
w.prasi_menu.pm?.on_load((exec: any) => {
done.exec = exec;
});
await preload(pathname);
setTimeout(() => {
w.prasi_menu.nav(_href);
done.exec();
}, 500);
} else {
await preload(pathname);
w.prasi_menu.nav(_href);
}
}
}) as typeof navigate;
}
};