This commit is contained in:
rizky 2024-08-13 03:42:11 -07:00
parent 8ec266d47c
commit d14e07a1fc
7 changed files with 67 additions and 7 deletions

View File

@ -24,6 +24,7 @@ export const Form: FC<FMProps> = (props) => {
reload: async () => { reload: async () => {
formReload(fm); formReload(fm);
}, },
save_status: "init",
fields: {}, fields: {},
events: { events: {
on_change(name: string, new_value: any) {}, on_change(name: string, new_value: any) {},
@ -81,7 +82,9 @@ export const Form: FC<FMProps> = (props) => {
fm.soft_delete.field = null; fm.soft_delete.field = null;
} }
} }
}, []); }, []);
const ref = useRef({ const ref = useRef({
el: null as null | HTMLFormElement, el: null as null | HTMLFormElement,
rob: new ResizeObserver(([e]) => { rob: new ResizeObserver(([e]) => {

View File

@ -6,6 +6,7 @@ import { useField } from "../utils/use-field";
import { validate } from "../utils/validate"; import { validate } from "../utils/validate";
import { FieldInput } from "./FieldInput"; import { FieldInput } from "./FieldInput";
import { Label } from "./Label"; import { Label } from "./Label";
import { hashSum } from "lib/utils/hash-sum";
export const Field: FC<FieldProp> = (arg) => { export const Field: FC<FieldProp> = (arg) => {
const showlabel = arg.show_label || "y"; const showlabel = arg.show_label || "y";
@ -19,7 +20,33 @@ export const Field: FC<FieldProp> = (arg) => {
const w = field.width; const w = field.width;
useEffect(() => { useEffect(() => {
if (fm.save_status === "init" || fm.status !== "ready") return;
if (local.prev_val === undefined) {
if (typeof fm.data[name] === "object") {
const sfied = hashSum(fm.data[name]);
if (sfied !== local.prev_val) {
local.prev_val = sfied;
} else {
return;
}
} else {
local.prev_val = fm.data[name];
}
return;
}
if (local.prev_val !== fm.data[name]) { if (local.prev_val !== fm.data[name]) {
if (typeof fm.data[name] === "object") {
const sfied = hashSum(fm.data[name]);
if (sfied !== local.prev_val) {
local.prev_val = sfied;
} else {
return;
}
} else {
local.prev_val = fm.data[name];
}
if ( if (
(!local.prev_val && fm.data[name]) || (!local.prev_val && fm.data[name]) ||
(local.prev_val && !fm.data[name]) (local.prev_val && !fm.data[name])
@ -30,6 +57,9 @@ export const Field: FC<FieldProp> = (arg) => {
if (arg.on_change) { if (arg.on_change) {
arg.on_change({ value: fm.data[name], name, fm }); arg.on_change({ value: fm.data[name], name, fm });
} }
fm.save_status = "unsaved";
if (!fm.events) { if (!fm.events) {
fm.events = { fm.events = {
on_change(name, new_value) {}, on_change(name, new_value) {},

View File

@ -5,19 +5,30 @@ import { useEffect, useRef } from "react";
export const KeyValue = ({ export const KeyValue = ({
value, value,
onChange, onChange,
index,
}: { }: {
value: any; value: any;
onChange: (val: any) => void; onChange: (val: any) => void;
index?: "preserve" | "auto-sort";
}) => { }) => {
const local = useLocal({ const local = useLocal({
entries: Object.entries(value), entries: [] as [string, string][],
new: { idx: -1, key: "", value: "" }, new: { idx: -1, key: "", value: "" },
}); });
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
let entries: any[] = [];
if (index === "preserve") {
if (Array.isArray(value)) {
local.entries = value;
} else {
local.entries = Object.entries(value);
}
}
if (local.entries.length > 0) { if (local.entries.length > 0) {
Object.entries(value).forEach(([k, v], idx) => { entries.forEach(([k, v], idx) => {
const found = local.entries.find((e) => { const found = local.entries.find((e) => {
if (e[0] === k) return true; if (e[0] === k) return true;
return false; return false;
@ -30,8 +41,9 @@ export const KeyValue = ({
} }
}); });
} else { } else {
local.entries = Object.entries(value); local.entries = entries;
} }
local.render(); local.render();
}, [value]); }, [value]);
@ -87,7 +99,11 @@ export const KeyValue = ({
local.render(); local.render();
}} }}
onBlur={() => { onBlur={() => {
if (index === "preserve") {
onChange([...local.entries]);
} else {
onChange(reverseEntries(local.entries)); onChange(reverseEntries(local.entries));
}
}} }}
/> />
))} ))}
@ -106,7 +122,11 @@ export const KeyValue = ({
local.new.key = ""; local.new.key = "";
local.new.value = ""; local.new.value = "";
local.render(); local.render();
if (index === "preserve") {
onChange([...local.entries]);
} else {
onChange(reverseEntries(local.entries)); onChange(reverseEntries(local.entries));
}
setTimeout(() => { setTimeout(() => {
( (
ref?.current?.querySelector( ref?.current?.querySelector(
@ -186,7 +206,7 @@ const KVRow = ({
onChange={(e) => { onChange={(e) => {
update(idx, k, e.currentTarget.value || ""); update(idx, k, e.currentTarget.value || "");
}} }}
onKeyDown={(e) => { onKeyUp={(e) => {
if (e.key === "Backspace" && !e.currentTarget.value) { if (e.key === "Backspace" && !e.currentTarget.value) {
keyref.current?.focus(); keyref.current?.focus();
} }

View File

@ -217,6 +217,7 @@ export const FieldTypeInput: FC<{
case "key-value": case "key-value":
return ( return (
<KeyValue <KeyValue
index={field.prop.kv?.index}
value={ value={
Object.keys(fm.data[field.name] || {}).length === 0 Object.keys(fm.data[field.name] || {}).length === 0
? field.prop.kv?.default ? field.prop.kv?.default

View File

@ -65,6 +65,8 @@ ${
data: v, data: v,
fk: rel.fk, fk: rel.fk,
}); });
} else {
record[k] = v;
} }
} else { } else {
record[k] = v; record[k] = v;

View File

@ -48,7 +48,7 @@ export type FieldProp = {
label: string; label: string;
desc?: string; desc?: string;
props?: any; props?: any;
kv?: { default: any }; kv?: { default: any; index: "preserve" | "auto-sort" };
upload?: { upload?: {
mode: "single-file" | "multi-file"; mode: "single-file" | "multi-file";
accept: string; accept: string;
@ -137,6 +137,7 @@ export type FMInternal = {
events: { events: {
on_change: (name: string, new_value: any) => void; on_change: (name: string, new_value: any) => void;
}; };
save_status: "init" | "unsaved" | "saved";
fields: Record<string, FieldLocal>; fields: Record<string, FieldLocal>;
field_def: Record<string, GFCol>; field_def: Record<string, GFCol>;
error: { error: {

View File

@ -23,6 +23,8 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
const toastSuccess = (opt: { addNewText: string }) => { const toastSuccess = (opt: { addNewText: string }) => {
const md = fm.deps.md as MDLocal; const md = fm.deps.md as MDLocal;
fm.save_status = "saved";
if (md) { if (md) {
toast.success( toast.success(
<div <div
@ -184,6 +186,7 @@ export const formInit = (fm: FMLocal, props: FMProps) => {
} }
fm.data = result; fm.data = result;
fm.save_status = "saved";
if (result === undefined) fm.data = {}; if (result === undefined) fm.data = {};