@skalfa/skalfa-component 1.0.54 → 1.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.TableSupervisionComponent = TableSupervisionComponent;
|
|
5
5
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
6
|
const react_1 = require("react");
|
|
7
|
+
const navigation_1 = require("next/navigation");
|
|
7
8
|
const _utils_1 = require("@utils");
|
|
8
9
|
const _contexts_1 = require("@contexts");
|
|
9
10
|
const __1 = require("../");
|
|
@@ -14,10 +15,60 @@ const ImportExcel = _utils_1.registry.get("ImportExcel");
|
|
|
14
15
|
;
|
|
15
16
|
function TableSupervisionComponent({ title, id, fetchControl, columnControl, formControl, onRowClick, detailControl, actionControl, actionBulkingControl, block, controlBar, filterBar, noIndex, responsiveControl, urlParam, }) {
|
|
16
17
|
const l = (0, skalfa_lang_1.useLang)();
|
|
18
|
+
const router = (0, navigation_1.useRouter)();
|
|
19
|
+
const searchParams = (0, navigation_1.useSearchParams)();
|
|
17
20
|
const { tableKey, tableControl, data, selected, setSelected, checks, setChecks, reset, focus, setFocus } = (0, _utils_1.useTable)(fetchControl, id, title, (urlParam || true));
|
|
18
21
|
const { setToggle, toggle } = (0, _contexts_1.useToggleContext)();
|
|
19
22
|
const { isSm } = (0, _utils_1.useResponsive)();
|
|
20
23
|
const toggleKey = (0, react_1.useMemo)(() => _utils_1.conversion.strSnake(tableKey).toUpperCase(), [tableKey]);
|
|
24
|
+
const detailQueryId = searchParams.get("detail") || searchParams.get("openDetail");
|
|
25
|
+
const editQueryId = searchParams.get("edit");
|
|
26
|
+
const [directLoading, setDirectLoading] = (0, react_1.useState)(false);
|
|
27
|
+
// Auto-open floating detail or edit modal if query parameter is present in URL
|
|
28
|
+
(0, react_1.useEffect)(() => {
|
|
29
|
+
if (detailControl === false && !editQueryId)
|
|
30
|
+
return;
|
|
31
|
+
const targetId = detailQueryId || editQueryId;
|
|
32
|
+
const isEdit = !!editQueryId && !detailQueryId;
|
|
33
|
+
if (!targetId)
|
|
34
|
+
return;
|
|
35
|
+
if (!selected || String(selected?.id) !== String(targetId)) {
|
|
36
|
+
setDirectLoading(true);
|
|
37
|
+
if (isEdit) {
|
|
38
|
+
setToggle(`MODAL_FORM_${toggleKey}`, true);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
setToggle(`MODAL_SHOW_${toggleKey}`, true);
|
|
42
|
+
}
|
|
43
|
+
const basePath = fetchControl?.path;
|
|
44
|
+
if (basePath) {
|
|
45
|
+
(0, _utils_1.api)({
|
|
46
|
+
path: `${basePath}/${targetId}`,
|
|
47
|
+
method: "GET",
|
|
48
|
+
params: fetchControl?.params || {},
|
|
49
|
+
})
|
|
50
|
+
.then((res) => {
|
|
51
|
+
const item = res?.data?.data || res?.data || res;
|
|
52
|
+
if (item) {
|
|
53
|
+
setSelected(item);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
setSelected({ id: Number(targetId) });
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
.catch(() => {
|
|
60
|
+
setSelected({ id: Number(targetId) });
|
|
61
|
+
})
|
|
62
|
+
.finally(() => {
|
|
63
|
+
setDirectLoading(false);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
setSelected({ id: Number(targetId) });
|
|
68
|
+
setDirectLoading(false);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}, [detailQueryId, editQueryId, fetchControl, toggleKey]);
|
|
21
72
|
(0, react_1.useEffect)(() => {
|
|
22
73
|
if (data?.data?.length && !toggle[`MODAL_DELETE_${toggleKey}`] && !toggle[`MODAL_DELETE_${toggleKey}`] && !toggle[`MODAL_SHOW_${toggleKey}`]) {
|
|
23
74
|
_utils_1.shortcut.register("arrowdown", () => {
|
|
@@ -136,7 +187,12 @@ function TableSupervisionComponent({ title, id, fetchControl, columnControl, for
|
|
|
136
187
|
const detailPage = (0, react_1.useMemo)(() => {
|
|
137
188
|
if (!toggle[`MODAL_SHOW_${toggleKey}`])
|
|
138
189
|
return null;
|
|
139
|
-
|
|
190
|
+
if (directLoading && !selected) {
|
|
191
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "p-12 text-center text-slate-400 space-y-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "inline-block animate-spin w-6 h-6 border-2 border-primary border-t-transparent rounded-full" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs font-semibold", children: l?.base?.loading ? l.base.loading() : "Memuat detail..." })] }));
|
|
192
|
+
}
|
|
193
|
+
if (!selected)
|
|
194
|
+
return null;
|
|
195
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "p-4", children: (0, jsx_runtime_1.jsx)("div", { className: (0, _utils_1.cn)("flex flex-col gap-y-4"), children: typeof detailControl === "object" && typeof detailControl.content === "object" && detailControl?.content?.length ? detailControl?.content?.map((column, key) => {
|
|
140
196
|
if (typeof column === "string") {
|
|
141
197
|
return ((0, jsx_runtime_1.jsx)(__1.TypographyColumnComponent, { title: columns?.find((c) => c.selector == column)?.label, content: selected[column] }, key));
|
|
142
198
|
}
|
|
@@ -146,8 +202,8 @@ function TableSupervisionComponent({ title, id, fetchControl, columnControl, for
|
|
|
146
202
|
else {
|
|
147
203
|
return column?.(selected);
|
|
148
204
|
}
|
|
149
|
-
}) : typeof detailControl === "object" && typeof detailControl.content === "function" ? detailControl?.content?.(selected) : columns?.map((column, key) => ((0, jsx_runtime_1.jsx)(__1.TypographyColumnComponent, { title: column.label, content: selected[column.selector] }, key)))
|
|
150
|
-
}, [selected, detailControl]);
|
|
205
|
+
}) : typeof detailControl === "object" && typeof detailControl.content === "function" ? detailControl?.content?.(selected) : columns?.map((column, key) => ((0, jsx_runtime_1.jsx)(__1.TypographyColumnComponent, { title: column.label, content: selected[column.selector] }, key))) }) }));
|
|
206
|
+
}, [selected, detailControl, toggle[`MODAL_SHOW_${toggleKey}`], directLoading, columns]);
|
|
151
207
|
// ============================
|
|
152
208
|
// ## Form preparation
|
|
153
209
|
// ============================
|
|
@@ -206,6 +262,14 @@ function TableSupervisionComponent({ title, id, fetchControl, columnControl, for
|
|
|
206
262
|
},
|
|
207
263
|
} : { idb: fetchControl?.idb }, fields: fields?.filter((f) => f.visibility ? !selected?.id ? ["*", "create"]?.includes(f.visibility) : ["*", "update"]?.includes(f.visibility) : true), defaultValue: formControl?.defaultValue ? await formControl?.defaultValue(selected || null) : selected, payload: formControl?.payload, onSuccess: () => {
|
|
208
264
|
reset();
|
|
265
|
+
if (typeof window !== "undefined") {
|
|
266
|
+
const url = new URL(window.location.href);
|
|
267
|
+
if (url.searchParams.has("edit")) {
|
|
268
|
+
url.searchParams.delete("edit");
|
|
269
|
+
const nextSearch = url.searchParams.toString();
|
|
270
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
209
273
|
setTimeout(() => { setToggle(`MODAL_FORM_${toggleKey}`, false); }, 900);
|
|
210
274
|
} }));
|
|
211
275
|
}, [selected, fetchControl, formControl]);
|
|
@@ -267,7 +331,29 @@ function TableSupervisionComponent({ title, id, fetchControl, columnControl, for
|
|
|
267
331
|
} : undefined, ...tableControl }), controlBar?.find((cb) => cb == "CREATE") && ((0, jsx_runtime_1.jsx)(__1.ButtonComponent, { icon: "solid/plus", className: "fixed bottom-16 right-4 w-14 h-14 z-20 md:hidden table-supervision-mobile-create", size: "lg", rounded: true, onClick: () => {
|
|
268
332
|
setToggle(`MODAL_FORM_${toggleKey}`);
|
|
269
333
|
setSelected(null);
|
|
270
|
-
} })), (0, jsx_runtime_1.jsx)(__1.FloatingPageComponent, { show: !!toggle[`MODAL_SHOW_${toggleKey}`], onClose: () =>
|
|
334
|
+
} })), (0, jsx_runtime_1.jsx)(__1.FloatingPageComponent, { show: !!toggle[`MODAL_SHOW_${toggleKey}`], onClose: () => {
|
|
335
|
+
setToggle(`MODAL_SHOW_${toggleKey}`, false);
|
|
336
|
+
setSelected(null);
|
|
337
|
+
if (typeof window !== "undefined") {
|
|
338
|
+
const url = new URL(window.location.href);
|
|
339
|
+
if (url.searchParams.has("detail") || url.searchParams.has("openDetail")) {
|
|
340
|
+
url.searchParams.delete("detail");
|
|
341
|
+
url.searchParams.delete("openDetail");
|
|
342
|
+
const nextSearch = url.searchParams.toString();
|
|
343
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}, title: l.base.detailTitle ? l.base.detailTitle() : "Detail", className: "bg-background", footer: renderTableAction(actionControl, undefined, { className: isSm ? "justify-end p-2 bg-background" : "justify-end", size: isSm ? "sm" : "md" }), ...(typeof detailControl === "object" ? detailControl?.modalControl || {} : {}), children: detailPage }), (0, jsx_runtime_1.jsx)(__1.FloatingPageComponent, { show: !!toggle[`MODAL_FORM_${toggleKey}`], onClose: () => {
|
|
347
|
+
setToggle(`MODAL_FORM_${toggleKey}`, false);
|
|
348
|
+
if (typeof window !== "undefined") {
|
|
349
|
+
const url = new URL(window.location.href);
|
|
350
|
+
if (url.searchParams.has("edit")) {
|
|
351
|
+
url.searchParams.delete("edit");
|
|
352
|
+
const nextSearch = url.searchParams.toString();
|
|
353
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}, title: !!selected ? (l.base.editTitle ? l.base.editTitle() : "Edit") : (l.base.addTitle ? l.base.addTitle() : "Add"), className: (0, _utils_1.cn)("bg-white", formControl?.modalControl?.className), ...formControl?.modalControl, children: (0, jsx_runtime_1.jsx)("div", { className: "p-4", children: formPage }) }), (0, jsx_runtime_1.jsx)(__1.FloatingPageComponent, { show: !!toggle[`MODAL_EXPORT_${toggleKey}`], onClose: () => setToggle(`MODAL_EXPORT_${toggleKey}`, false), title: l.base.exportTitle ? l.base.exportTitle() : "Export", className: "bg-white md:w-[1200px] max-w-[1200px]", children: (0, jsx_runtime_1.jsx)(ExportExcel, { fetchControl: fetchControl, filename: "export", columnControl: columns?.map((cc) => ({
|
|
271
357
|
label: cc.label || "",
|
|
272
358
|
selector: cc.selector || "",
|
|
273
359
|
})) }) }), (0, jsx_runtime_1.jsx)(__1.FloatingPageComponent, { show: !!toggle[`MODAL_IMPORT_${toggleKey}`], onClose: () => setToggle(`MODAL_IMPORT_${toggleKey}`, false), title: l.base.importTitle ? l.base.importTitle() : "Import", className: "bg-white md:w-[1200px] max-w-[1200px]", children: (0, jsx_runtime_1.jsx)(ImportExcel, { submitControl: { path: fetchControl?.path + "/import" }, columnControl: columns?.map((cc) => ({
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { Fragment, ReactNode, useEffect, useMemo } from "react";
|
|
4
|
-
import {
|
|
3
|
+
import { Fragment, ReactNode, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
5
|
+
import { api, ApiType, cn, conversion, registry, shortcut, ShortcutHandler, UseResourceIdb, UseResourceProps, useResponsive, useTable } from "@utils";
|
|
5
6
|
import { useToggleContext } from "@contexts";
|
|
6
7
|
import { FloatingPageComponent, FloatingPageProps, ButtonComponent, TableColumnType, TableComponent, FormSupervisionComponent, FormType, ModalConfirmComponent, TypographyColumnComponent, ButtonProps, ModalConfirmProps, TableProps, ControlBarOptionType, SwipeActionType, BottomSheetProps } from "../";
|
|
7
8
|
import { useLang } from "@skalfa/skalfa-lang";
|
|
@@ -105,12 +106,61 @@ export function TableSupervisionComponent({
|
|
|
105
106
|
urlParam,
|
|
106
107
|
}: TableSupervisionProps) {
|
|
107
108
|
const l = useLang();
|
|
109
|
+
const router = useRouter();
|
|
110
|
+
const searchParams = useSearchParams();
|
|
108
111
|
|
|
109
112
|
const { tableKey, tableControl, data, selected, setSelected, checks, setChecks, reset, focus, setFocus } = useTable(fetchControl, id, title, (urlParam || true))
|
|
110
113
|
const { setToggle, toggle } = useToggleContext()
|
|
111
114
|
const { isSm } = useResponsive();
|
|
112
115
|
|
|
113
116
|
const toggleKey = useMemo(() => conversion.strSnake(tableKey).toUpperCase(), [tableKey])
|
|
117
|
+
const detailQueryId = searchParams.get("detail") || searchParams.get("openDetail");
|
|
118
|
+
const editQueryId = searchParams.get("edit");
|
|
119
|
+
const [directLoading, setDirectLoading] = useState(false);
|
|
120
|
+
|
|
121
|
+
// Auto-open floating detail or edit modal if query parameter is present in URL
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (detailControl === false && !editQueryId) return;
|
|
124
|
+
|
|
125
|
+
const targetId = detailQueryId || editQueryId;
|
|
126
|
+
const isEdit = !!editQueryId && !detailQueryId;
|
|
127
|
+
if (!targetId) return;
|
|
128
|
+
|
|
129
|
+
if (!selected || String((selected as any)?.id) !== String(targetId)) {
|
|
130
|
+
setDirectLoading(true);
|
|
131
|
+
if (isEdit) {
|
|
132
|
+
setToggle(`MODAL_FORM_${toggleKey}`, true);
|
|
133
|
+
} else {
|
|
134
|
+
setToggle(`MODAL_SHOW_${toggleKey}`, true);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const basePath = (fetchControl as ApiType)?.path;
|
|
138
|
+
if (basePath) {
|
|
139
|
+
api({
|
|
140
|
+
path: `${basePath}/${targetId}`,
|
|
141
|
+
method: "GET",
|
|
142
|
+
params: (fetchControl as ApiType)?.params || {},
|
|
143
|
+
})
|
|
144
|
+
.then((res: any) => {
|
|
145
|
+
const item = res?.data?.data || res?.data || res;
|
|
146
|
+
if (item) {
|
|
147
|
+
setSelected(item);
|
|
148
|
+
} else {
|
|
149
|
+
setSelected({ id: Number(targetId) });
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
.catch(() => {
|
|
153
|
+
setSelected({ id: Number(targetId) });
|
|
154
|
+
})
|
|
155
|
+
.finally(() => {
|
|
156
|
+
setDirectLoading(false);
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
setSelected({ id: Number(targetId) });
|
|
160
|
+
setDirectLoading(false);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}, [detailQueryId, editQueryId, fetchControl, toggleKey]);
|
|
114
164
|
|
|
115
165
|
|
|
116
166
|
useEffect(() => {
|
|
@@ -297,23 +347,35 @@ export function TableSupervisionComponent({
|
|
|
297
347
|
// ============================
|
|
298
348
|
const detailPage = useMemo(() => {
|
|
299
349
|
if (!toggle[`MODAL_SHOW_${toggleKey}`]) return null;
|
|
350
|
+
|
|
351
|
+
if (directLoading && !selected) {
|
|
352
|
+
return (
|
|
353
|
+
<div className="p-12 text-center text-slate-400 space-y-2">
|
|
354
|
+
<div className="inline-block animate-spin w-6 h-6 border-2 border-primary border-t-transparent rounded-full" />
|
|
355
|
+
<p className="text-xs font-semibold">{l?.base?.loading ? l.base.loading() : "Memuat detail..."}</p>
|
|
356
|
+
</div>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (!selected) return null;
|
|
361
|
+
|
|
300
362
|
return (
|
|
301
363
|
<div className="p-4">
|
|
302
364
|
<div className={cn(
|
|
303
365
|
"flex flex-col gap-y-4",
|
|
304
366
|
)}>
|
|
305
|
-
{
|
|
367
|
+
{typeof detailControl === "object" && typeof detailControl.content === "object" && detailControl?.content?.length ? detailControl?.content?.map((column, key) => {
|
|
306
368
|
if (typeof column === "string") {
|
|
307
369
|
return (<TypographyColumnComponent
|
|
308
370
|
key={key}
|
|
309
371
|
title={columns?.find((c) => c.selector == column)?.label}
|
|
310
|
-
content={selected[column]}
|
|
372
|
+
content={(selected as any)[column]}
|
|
311
373
|
/>)
|
|
312
374
|
} else if (typeof column === "object") {
|
|
313
375
|
return (<TypographyColumnComponent
|
|
314
376
|
key={key}
|
|
315
377
|
title={column?.label}
|
|
316
|
-
content={typeof column?.item === "string" ? selected[column?.item] : column?.item(selected)}
|
|
378
|
+
content={typeof column?.item === "string" ? (selected as any)[column?.item] : column?.item(selected)}
|
|
317
379
|
/>)
|
|
318
380
|
} else {
|
|
319
381
|
return column?.(selected)
|
|
@@ -322,13 +384,13 @@ export function TableSupervisionComponent({
|
|
|
322
384
|
<TypographyColumnComponent
|
|
323
385
|
key={key}
|
|
324
386
|
title={column.label}
|
|
325
|
-
content={selected[column.selector]}
|
|
387
|
+
content={(selected as any)[column.selector]}
|
|
326
388
|
/>
|
|
327
|
-
))
|
|
389
|
+
))}
|
|
328
390
|
</div>
|
|
329
391
|
</div>
|
|
330
392
|
)
|
|
331
|
-
}, [selected, detailControl]);
|
|
393
|
+
}, [selected, detailControl, toggle[`MODAL_SHOW_${toggleKey}`], directLoading, columns]);
|
|
332
394
|
|
|
333
395
|
|
|
334
396
|
|
|
@@ -401,6 +463,14 @@ export function TableSupervisionComponent({
|
|
|
401
463
|
payload={formControl?.payload}
|
|
402
464
|
onSuccess={() => {
|
|
403
465
|
reset();
|
|
466
|
+
if (typeof window !== "undefined") {
|
|
467
|
+
const url = new URL(window.location.href);
|
|
468
|
+
if (url.searchParams.has("edit")) {
|
|
469
|
+
url.searchParams.delete("edit");
|
|
470
|
+
const nextSearch = url.searchParams.toString();
|
|
471
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
472
|
+
}
|
|
473
|
+
}
|
|
404
474
|
setTimeout(() => { setToggle(`MODAL_FORM_${toggleKey}`, false) }, 900);
|
|
405
475
|
}}
|
|
406
476
|
/>
|
|
@@ -553,7 +623,19 @@ export function TableSupervisionComponent({
|
|
|
553
623
|
|
|
554
624
|
<FloatingPageComponent
|
|
555
625
|
show={!!toggle[`MODAL_SHOW_${toggleKey}`]}
|
|
556
|
-
onClose={() =>
|
|
626
|
+
onClose={() => {
|
|
627
|
+
setToggle(`MODAL_SHOW_${toggleKey}`, false);
|
|
628
|
+
setSelected(null);
|
|
629
|
+
if (typeof window !== "undefined") {
|
|
630
|
+
const url = new URL(window.location.href);
|
|
631
|
+
if (url.searchParams.has("detail") || url.searchParams.has("openDetail")) {
|
|
632
|
+
url.searchParams.delete("detail");
|
|
633
|
+
url.searchParams.delete("openDetail");
|
|
634
|
+
const nextSearch = url.searchParams.toString();
|
|
635
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}}
|
|
557
639
|
title={l.base.detailTitle ? l.base.detailTitle() : "Detail"}
|
|
558
640
|
className="bg-background"
|
|
559
641
|
footer={renderTableAction(actionControl, undefined, {className: isSm ? "justify-end p-2 bg-background" : "justify-end", size: isSm ? "sm" : "md"})}
|
|
@@ -565,7 +647,17 @@ export function TableSupervisionComponent({
|
|
|
565
647
|
|
|
566
648
|
<FloatingPageComponent
|
|
567
649
|
show={!!toggle[`MODAL_FORM_${toggleKey}`]}
|
|
568
|
-
onClose={() =>
|
|
650
|
+
onClose={() => {
|
|
651
|
+
setToggle(`MODAL_FORM_${toggleKey}`, false);
|
|
652
|
+
if (typeof window !== "undefined") {
|
|
653
|
+
const url = new URL(window.location.href);
|
|
654
|
+
if (url.searchParams.has("edit")) {
|
|
655
|
+
url.searchParams.delete("edit");
|
|
656
|
+
const nextSearch = url.searchParams.toString();
|
|
657
|
+
router.replace(url.pathname + (nextSearch ? `?${nextSearch}` : ""), { scroll: false });
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}}
|
|
569
661
|
title={!!selected ? (l.base.editTitle ? l.base.editTitle() : "Edit") : (l.base.addTitle ? l.base.addTitle() : "Add")}
|
|
570
662
|
className={cn("bg-white", formControl?.modalControl?.className)}
|
|
571
663
|
{...formControl?.modalControl}
|