prasi-lib/comps/md/MasterDetail.tsx

151 lines
3.7 KiB
TypeScript
Executable File

import { useLocal } from "@/utils/use-local";
import { parseGenField } from "lib/gen/utils";
import { FC, useEffect, useRef } from "react";
import { ModeFull } from "./mode/full";
import { ModeHSplit } from "./mode/h-split";
import { ModeVSplit } from "./mode/v-split";
import { MDHeader } from "./parts/MDHeader";
import { editorMDInit } from "./utils/editor-init";
import {
masterDetailApplyParams,
masterDetailParseHash as masterDetailParseParams,
} from "./utils/md-hash";
import { mdRenderLoop } from "./utils/md-render-loop";
import { MDLocalInternal, MDProps } from "./utils/typings";
export const MasterDetail: FC<MDProps> = (arg) => {
const {
PassProp,
name,
mode,
show_head,
tab_mode,
editor_tab,
gen_fields,
footer,
gen_table,
on_init,
_item,
title,
detail_size,
} = arg;
const _ref = useRef({ PassProp, item: _item, childs: {} });
const mdr = _ref.current;
const md = useLocal<MDLocalInternal>({
name,
title,
status: isEditor ? "init" : "ready",
actions: [],
header: {
loading: false,
breadcrumb: [],
render: () => {},
master: { prefix: null, suffix: null },
child: { prefix: null, suffix: null },
},
selected: null,
tab: {
active: "",
list: [],
},
internal: { action_should_refresh: false, reset_detail: false },
childs: {},
props: {
mode,
show_head,
tab_mode,
editor_tab,
gen_fields,
gen_table,
on_init,
item: _item,
},
params: {
links: [],
hash: {},
tabs: {},
parse: () => {
masterDetailParseParams(md);
},
apply: () => {
masterDetailApplyParams(md);
},
},
detail_size: Number(detail_size || "400"),
master: { render() {}, reload() {} },
});
mdr.PassProp = PassProp;
mdr.item = _item;
mdRenderLoop(md, mdr, arg);
md.deps = arg.deps || {};
if (isEditor) {
md.tab.active = editor_tab;
editorMDInit(md, mdr, arg);
} else {
md.status = "ready";
const fields = parseGenField(gen_fields);
const pk = fields.find((e) => e.is_pk);
md.pk = pk;
md.params.parse();
if (pk) {
const value = md.params.hash[md.name];
if (!value && md.selected && Object.keys(md.selected).length === 0) {
md.params.hash[md.name] = "+";
md.params.apply();
}
if (value) {
if (value === "+") {
md.tab.active = "detail";
if (!md.selected) {
md.selected = {};
} else if (md.selected && md.selected[pk.name]) {
md.params.hash[md.name] = md.selected[pk.name];
md.params.apply();
}
} else {
if (md.selected && md.selected[pk.name] === value) {
} else {
md.selected = { [pk.name]: value };
}
const tab = md.params.tabs[md.name];
if (tab && md.tab.list.includes(tab)) {
md.tab.active = tab;
} else {
md.tab.active = "detail";
}
}
}
}
}
if (isEditor) {
useEffect(() => {
md.title = title;
md.header.render();
}, [title]);
}
return (
<div
className={cx(
"master-detail c-flex-1 c-flex-col c-flex c-w-full c-h-full"
)}
>
{md.props.show_head === "always" && <MDHeader md={md} mdr={mdr} />}
{md.status === "ready" && (
<>
{md.props.mode === "full" && <ModeFull md={md} mdr={mdr} />}
{md.props.mode === "v-split" && <ModeVSplit md={md} mdr={mdr} />}
{md.props.mode === "h-split" && <ModeHSplit md={md} mdr={mdr} />}
{arg.show_footer !== "hidden" && (
<PassProp md={md}>{[footer]}</PassProp>
)}
</>
)}
</div>
);
};