@skalfa/skalfa-component 1.0.8 → 1.0.9

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.
Files changed (87) hide show
  1. package/dist/accordion/Accordion.component.js +2 -3
  2. package/dist/breadcrumb/Breadcrumb.component.js +2 -3
  3. package/dist/button/Button.component.d.ts +2 -1
  4. package/dist/button/Button.component.js +2 -2
  5. package/dist/carousel/Carousel.component.js +2 -3
  6. package/dist/chip/Chip.component.js +2 -3
  7. package/dist/contexts-mock.d.ts +2 -0
  8. package/dist/contexts-mock.js +10 -0
  9. package/dist/input/Checkbox.component.js +2 -3
  10. package/dist/input/Input.component.d.ts +3 -2
  11. package/dist/input/Input.component.js +3 -3
  12. package/dist/input/InputCheckbox.component.js +1 -1
  13. package/dist/input/InputCurrency.component.d.ts +3 -2
  14. package/dist/input/InputCurrency.component.js +3 -3
  15. package/dist/input/InputDate.component.js +4 -5
  16. package/dist/input/InputDatetime.component.d.ts +3 -2
  17. package/dist/input/InputDatetime.component.js +3 -3
  18. package/dist/input/InputDocument.component.js +7 -8
  19. package/dist/input/InputImage.component.js +3 -4
  20. package/dist/input/InputNumber.component.js +3 -4
  21. package/dist/input/InputPassword.component.js +3 -3
  22. package/dist/input/InputRadio.component.js +1 -1
  23. package/dist/input/InputTime.component.js +3 -3
  24. package/dist/input/InputValues.component.js +3 -4
  25. package/dist/input/Select.component.js +6 -7
  26. package/dist/modal/FloatingPage.component.d.ts +3 -1
  27. package/dist/modal/FloatingPage.component.js +7 -3
  28. package/dist/modal/Modal.component.js +1 -2
  29. package/dist/modal/ModalConfirm.component.d.ts +2 -2
  30. package/dist/modal/ModalConfirm.component.js +14 -12
  31. package/dist/modal/Toast.component.js +1 -2
  32. package/dist/nav/Bottombar.component.d.ts +2 -2
  33. package/dist/nav/Bottombar.component.js +7 -8
  34. package/dist/nav/Footer.component.d.ts +2 -2
  35. package/dist/nav/Footer.component.js +6 -7
  36. package/dist/nav/Headbar.component.js +2 -3
  37. package/dist/nav/Navbar.component.d.ts +2 -2
  38. package/dist/nav/Navbar.component.js +3 -4
  39. package/dist/nav/Sidebar.component.d.ts +3 -7
  40. package/dist/nav/Sidebar.component.js +14 -17
  41. package/dist/supervision/FormSupervision.component.d.ts +4 -29
  42. package/dist/supervision/FormSupervision.component.js +84 -136
  43. package/dist/supervision/TableSupervision.component.d.ts +17 -26
  44. package/dist/supervision/TableSupervision.component.js +207 -193
  45. package/dist/table/ControlBar.component.js +15 -16
  46. package/dist/table/FilterComponent.js +4 -6
  47. package/dist/table/Pagination.component.js +2 -3
  48. package/dist/table/Table.component.js +3 -4
  49. package/dist/wrap/Swipe.component.js +2 -2
  50. package/package.json +18 -10
  51. package/src/accordion/Accordion.component.tsx +3 -3
  52. package/src/breadcrumb/Breadcrumb.component.tsx +4 -4
  53. package/src/button/Button.component.tsx +3 -3
  54. package/src/carousel/Carousel.component.tsx +4 -4
  55. package/src/chip/Chip.component.tsx +3 -4
  56. package/src/contexts-mock.ts +6 -0
  57. package/src/input/Checkbox.component.tsx +3 -3
  58. package/src/input/Input.component.tsx +6 -6
  59. package/src/input/InputCheckbox.component.tsx +1 -1
  60. package/src/input/InputCurrency.component.tsx +6 -6
  61. package/src/input/InputDate.component.tsx +6 -7
  62. package/src/input/InputDatetime.component.tsx +6 -6
  63. package/src/input/InputDocument.component.tsx +9 -9
  64. package/src/input/InputImage.component.tsx +4 -5
  65. package/src/input/InputNumber.component.tsx +7 -8
  66. package/src/input/InputPassword.component.tsx +4 -4
  67. package/src/input/InputRadio.component.tsx +1 -1
  68. package/src/input/InputTime.component.tsx +4 -4
  69. package/src/input/InputValues.component.tsx +5 -6
  70. package/src/input/Select.component.tsx +10 -10
  71. package/src/modal/FloatingPage.component.tsx +33 -3
  72. package/src/modal/Modal.component.tsx +1 -2
  73. package/src/modal/ModalConfirm.component.tsx +34 -49
  74. package/src/modal/Toast.component.tsx +1 -2
  75. package/src/nav/Bottombar.component.tsx +9 -10
  76. package/src/nav/Footer.component.tsx +8 -9
  77. package/src/nav/Headbar.component.tsx +3 -3
  78. package/src/nav/Navbar.component.tsx +9 -10
  79. package/src/nav/Sidebar.component.tsx +55 -46
  80. package/src/supervision/FormSupervision.component.tsx +203 -224
  81. package/src/supervision/TableSupervision.component.tsx +420 -455
  82. package/src/table/ControlBar.component.tsx +16 -16
  83. package/src/table/FilterComponent.tsx +9 -11
  84. package/src/table/Pagination.component.tsx +6 -6
  85. package/src/table/Table.component.tsx +5 -5
  86. package/src/wrap/Swipe.component.tsx +3 -3
  87. package/src/types.d.ts +0 -7
@@ -1,24 +1,15 @@
1
1
  "use client"
2
2
 
3
- import { ReactNode, Suspense, useEffect, useMemo } from "react";
4
- import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
5
- import { faEdit, faFileExcel, faFilePdf, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
6
- import { ApiType, cn, conversion, FetchControlType, registry, shortcut, ShortcutHandler, UseResourceIdb, UseResourceProps, useResponsive, useTable } from "@utils";
3
+ import { ReactNode, useEffect, useMemo } from "react";
4
+ import { ApiType, cn, conversion, registry, shortcut, ShortcutHandler, UseResourceIdb, UseResourceProps, useResponsive, useTable } from "@utils";
7
5
  import { useToggleContext } from "@contexts";
8
- import { FloatingPageComponent, FloatingPageProps } from "../modal/FloatingPage.component";
9
- import { ButtonComponent, ButtonProps } from "../button/Button.component";
10
- import { TableColumnType, TableComponent, TableProps } from "../table/Table.component";
11
- import { FormSupervisionComponent, FormType } from "./FormSupervision.component";
12
- import { ModalConfirmComponent, ModalConfirmProps } from "../modal/ModalConfirm.component";
13
- import { TypographyColumnComponent } from "../typography/TypographyColumn.component";
14
- import { ControlBarOptionType } from "../table/ControlBar.component";
15
- import { BottomSheetComponent } from "../modal/BottomSheet.component";
6
+ import { FloatingPageComponent, FloatingPageProps, ButtonComponent, TableColumnType, TableComponent, FormSupervisionComponent, FormType, ModalConfirmComponent, TypographyColumnComponent, ButtonProps, ModalConfirmProps, TableProps, ControlBarOptionType, SwipeActionType, BottomSheetProps } from "../";
7
+ import { useLang } from "@skalfa/skalfa-lang";
16
8
 
17
9
  const ExportExcel = registry.get("ExportExcel");
18
10
  const ImportExcel = registry.get("ImportExcel");
19
11
 
20
12
 
21
-
22
13
  export interface TableSupervisionColumnProps {
23
14
  selector : string;
24
15
  label ?: string;
@@ -34,58 +25,46 @@ export interface TableSupervisionColumnProps {
34
25
  accessCode ?: string;
35
26
  item ?: (data: any) => string | ReactNode;
36
27
  tip ?: string | ((data: any) => string);
37
- exportable ?: boolean | "default" | "optional" | "hidden";
38
- importable ?: boolean;
39
- }
28
+ };
40
29
 
41
30
  export interface TableSupervisionFormProps {
42
31
  fields : string[] | (FormType & { visibility?: "*" | "create" | "update" })[];
43
32
  defaultValue ?: (item: Record<string, any> | null) => Promise<Record<string, any>> | Record<string, any>;
44
33
  payload ?: (values: any) => Promise<Record<string, any>> | object;
45
- modalControl ?: Omit<FloatingPageProps, "show" | "onClose" | "children">;
34
+ modalControl ?: Omit<FloatingPageProps, "show" | "onClose" | "children"> | Omit<BottomSheetProps, "show" | "onClose" | "children">;
46
35
  contentType ?: "application/json" | "multipart/form-data";
47
- }
48
-
36
+ };
49
37
 
50
38
  export type TableSupervisionDetailProps = boolean
51
- | (
52
- | string
53
- | { label: string, item: string | ((data: Record<string, any>) => ReactNode), conversion?: keyof typeof conversion }
54
- | ((data: Record<string, any>) => ReactNode)
55
- )[]
56
- | ((data: Record<string, any>) => void)
57
- | {
58
- modal?: Omit<FloatingPageProps, "show" | "onClose" | "children">;
59
- content?: boolean
60
- | (
61
- | string
62
- | { label: string, item: string | ((data: Record<string, any>) => ReactNode), conversion?: keyof typeof conversion }
63
- | ((data: Record<string, any>) => ReactNode)
64
- )[]
65
- | ((data: Record<string, any>) => ReactNode);
66
- action?: (data: Record<string, any>) => void;
67
- };
39
+ | (
40
+ | string
41
+ | { label: string, item: string | ((data: Record<string, any>) => ReactNode), conversion?: keyof typeof conversion }
42
+ | ((data: Record<string, any>) => ReactNode)
43
+ )[]
44
+ | ((data: Record<string, any>) => ReactNode);
68
45
 
69
46
  export type TableSupervisionProps = {
70
47
  fetchControl : UseResourceProps;
71
48
  title ?: string;
72
49
  id ?: string;
73
50
  accessCode ?: number;
74
- urlParam ?: boolean | { compressed ?: boolean };
51
+ urlParam ?: boolean | { compressed ?: boolean }
52
+ onRowClick ?: (data: Record<string, any>) => void;
75
53
  columnControl ?: string[] | TableSupervisionColumnProps[];
76
54
  formControl ?: TableSupervisionFormProps;
77
55
  detailControl ?: TableSupervisionDetailProps;
78
56
  actionControl ?: boolean | (
79
57
  | 'EDIT' | 'DELETE' | {
80
58
  label : string,
81
- modal ?: Omit<ModalConfirmProps, "show" | "onClose">,
59
+ modal ?: ModalConfirmProps,
82
60
  button ?: ButtonProps,
83
61
  shortcut ?: { key: string, description: string },
84
62
  } | ((
85
- row : Record<string, any>,
86
- setModal : (type: "EDIT" | "DELETE") => void,
63
+ row : object,
64
+ setModal ?: (type: "EDIT" | "DELETE") => void,
87
65
  setDataSelected ?: () => void,
88
- setShortcut ?: (key: string, handler: ShortcutHandler, description?: string) => void
66
+ setShortcut ?: (key: string, handler: ShortcutHandler, description?: string) => void,
67
+ size ?: string,
89
68
  ) => ReactNode)
90
69
  )[];
91
70
  block ?: boolean,
@@ -93,9 +72,12 @@ export type TableSupervisionProps = {
93
72
  actionBulkingControl ?: TableProps["actionBulking"],
94
73
  controlBar ?: (ControlBarOptionType | "CREATE" | "IMPORT" | "EXPORT" | "PRINT")[];
95
74
  responsiveControl ?: {
96
- mobile ?: TableProps["responsiveControl"] extends { mobile?: infer M } ? M | boolean : boolean;
97
- };
98
- importControl ?: FetchControlType;
75
+ mobile ?: boolean | {
76
+ item ?: (item: Record<string, any>, key: number) => ReactNode,
77
+ leftActionControl ?: Omit<SwipeActionType, "onAction"> & { onAction?: (item: Record<string, any>, key?: number) => void },
78
+ rightActionControl ?: Omit<SwipeActionType, "onAction"> & { onAction?: (item: Record<string, any>, key?: number) => void },
79
+ }
80
+ }
99
81
  };
100
82
 
101
83
 
@@ -106,6 +88,7 @@ export function TableSupervisionComponent({
106
88
  fetchControl,
107
89
  columnControl,
108
90
  formControl,
91
+ onRowClick,
109
92
  detailControl,
110
93
  actionControl,
111
94
  actionBulkingControl,
@@ -114,87 +97,66 @@ export function TableSupervisionComponent({
114
97
  noIndex,
115
98
  responsiveControl,
116
99
  urlParam,
117
- importControl,
118
100
  }: TableSupervisionProps) {
119
- const { tableKey, tableControl, data, selected, setSelected, checks, setChecks, reset, focus } = useTable(fetchControl, id, title, (urlParam || true))
101
+ const l = useLang();
102
+
103
+ const { tableKey, tableControl, data, selected, setSelected, checks, setChecks, reset, focus, setFocus } = useTable(fetchControl, id, title, (urlParam || true))
120
104
  const { setToggle, toggle } = useToggleContext()
121
105
  const { isSm } = useResponsive();
122
106
 
123
- const isDetailControlObject = detailControl && typeof detailControl === "object" && !Array.isArray(detailControl);
124
- const detailAction = isDetailControlObject
125
- ? (detailControl as any)?.action
126
- : (typeof detailControl === "function" ? detailControl : undefined);
127
- const detailContent = isDetailControlObject
128
- ? (detailControl as any)?.content
129
- : (typeof detailControl === "function" ? undefined : detailControl);
130
- const detailModalProps = isDetailControlObject
131
- ? (detailControl as any)?.modal
132
- : undefined;
133
-
134
107
  const toggleKey = useMemo(() => conversion.strSnake(tableKey).toUpperCase(), [tableKey])
135
108
 
136
- // ============================
137
- // ## Shortcut register
138
- // ============================
109
+
139
110
  useEffect(() => {
140
- if(!isSm) {
141
- if (controlBar == undefined || controlBar?.includes("CREATE")) {
142
- shortcut.register("alt+n", () => {
111
+ if(data?.data?.length && !toggle[`MODAL_DELETE_${toggleKey}`] && !toggle[`MODAL_DELETE_${toggleKey}`] && !toggle[`MODAL_SHOW_${toggleKey}`]) {
112
+ shortcut.register("arrowdown", () => {
113
+ const max = data?.data?.length - 1;
114
+ setFocus(focus == null ? 0 : focus >= max ? max : (focus + 1))
115
+ }, "Pilih data kebawah")
116
+
117
+ shortcut.register("arrowup", () => {
118
+ setFocus(focus == null ? 0 : focus <= 0 ? 0 : (focus - 1))
119
+ }, "Pilih data keatas")
120
+
121
+ if(focus != null) {
122
+ shortcut.register("delete", () => {
123
+ setSelected(data?.data?.at(focus))
124
+ setToggle(`MODAL_DELETE_${toggleKey}`)
125
+ }, "Delete data yang dipilih")
126
+
127
+ shortcut.register(" ", () => {
128
+ setSelected(data?.data?.at(focus))
143
129
  setToggle(`MODAL_FORM_${toggleKey}`)
144
- setSelected(null)
145
- }, "Tambah Data Baru")
146
- }
147
-
148
- if (controlBar?.includes("IMPORT")) {
149
- shortcut.register("alt+i", () => {
150
- setToggle(`MODAL_IMPORT_${toggleKey}`)
151
- }, "Import Data Dari Excel")
152
- }
130
+ }, "Edit data yang dipilih")
153
131
 
154
- if (controlBar?.includes("EXPORT")) {
155
- shortcut.register("alt+e", () => {
156
- setToggle(`MODAL_EXPORT_${toggleKey}`)
157
- }, "Export Data Ke Excel")
158
- }
159
- }
160
-
161
- return () => {
162
- if(!isSm) {
163
- shortcut.unregister("alt+n")
164
- shortcut.unregister("alt+i")
165
- shortcut.unregister("alt+e")
132
+ shortcut.register("enter", () => {
133
+ setSelected(data?.data?.at(focus))
134
+ setToggle(`MODAL_SHOW_${toggleKey}`)
135
+ }, "Detail data yang dipilih")
136
+
137
+ shortcut.register("escape", () => {
138
+ setFocus(null)
139
+ }, "Kembali")
166
140
  }
167
141
  }
168
- }, [controlBar, isSm])
169
-
170
-
171
- useEffect(() => {
172
- if(actionControl && Array.isArray(actionControl) && selected) {
173
- actionControl.filter((ac) => typeof ac == "object")?.forEach((ac) => {
174
- if(typeof ac == "object" && ac?.shortcut) {
175
- shortcut.register(ac.shortcut.key, () => {
176
- setToggle(`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`)
177
- }, ac.shortcut.description)
178
- }
179
- })
180
- }
181
142
 
182
143
  return () => {
183
- if(actionControl && Array.isArray(actionControl)) {
184
- actionControl.filter((ac) => typeof ac == "object")?.forEach((ac) => {
185
- if(typeof ac == "object" && ac?.shortcut) {
186
- shortcut.unregister(ac.shortcut.key)
187
- }
188
- })
189
- }
144
+ shortcut.unregister("arrowdown")
145
+ shortcut.unregister("arrowup")
146
+ shortcut.unregister("delete")
147
+ shortcut.unregister(" ")
148
+ shortcut.unregister("enter")
149
+ shortcut.unregister("escape")
190
150
  }
191
- }, [actionControl, selected])
192
-
193
-
151
+ }, [data?.data, actionControl, focus, toggle[`MODAL_DELETE_${toggleKey}`], toggle[`MODAL_DELETE_${toggleKey}`], toggle[`MODAL_SHOW_${toggleKey}`]])
152
+
194
153
 
195
- const columns: TableSupervisionColumnProps[] = useMemo(() => {
196
- return columnControl ? columnControl.map((col) => {
197
- if(typeof col == "string") {
154
+ // ============================
155
+ // ## Column preparation
156
+ // ============================
157
+ const columns = useMemo(() => {
158
+ return columnControl?.length ? columnControl.map((col) => {
159
+ if (typeof col === "string") {
198
160
  return {
199
161
  selector : col,
200
162
  label : col,
@@ -221,14 +183,14 @@ export function TableSupervisionComponent({
221
183
  ) => {
222
184
  return (
223
185
  <>
224
- <div className={cn("table-supervision-action-list", options?.className)}>
186
+ <div className={cn("flex items-center gap-2", options?.className)}>
225
187
  {(Array.isArray(actions) ? actions : (actions || actions == undefined) ? ['EDIT', "DELETE"] : [])?.map((action, key) => {
226
188
  if(action == "EDIT") {
227
189
  return (
228
190
  <ButtonComponent
229
191
  key={key}
230
- icon={faEdit}
231
- label={"Ubah"}
192
+ icon={"solid/edit"}
193
+ label={l.base.edit ? l.base.edit() : "Edit"}
232
194
  variant="outline"
233
195
  paint="warning"
234
196
  size={options?.size || "xs"}
@@ -245,8 +207,8 @@ export function TableSupervisionComponent({
245
207
  return (
246
208
  <ButtonComponent
247
209
  key={key}
248
- icon={faTrash}
249
- label={"Hapus"}
210
+ icon={"solid/trash"}
211
+ label={l.base.delete ? l.base.delete() : "Delete"}
250
212
  variant="outline"
251
213
  paint="danger"
252
214
  size={options?.size || "xs"}
@@ -259,38 +221,45 @@ export function TableSupervisionComponent({
259
221
  )
260
222
  }
261
223
 
262
- if (typeof action == "object") {
263
- return (
264
- <ButtonComponent
265
- key={key}
266
- label={action.label}
267
- variant="outline"
268
- paint="primary"
269
- size={options?.size || "xs"}
270
- rounded
271
- onClick={() => {
272
- setToggle(`MODAL_${conversion.strSnake(action.label).toUpperCase()}_${toggleKey}`);
224
+ if(typeof action == "object") {
225
+ <ButtonComponent
226
+ key={`action-object-${key}`}
227
+ label={action?.button?.label || action?.label}
228
+ variant={action?.button?.variant || "outline"}
229
+ paint={action?.button?.paint || "primary"}
230
+ size={action?.button?.size || options?.size || "xs"}
231
+ rounded={action?.button?.rounded || true}
232
+ onClick={() => {
233
+ if (action?.button?.onClick) {
234
+ action?.button?.onClick(item)
235
+ } else {
236
+ setToggle(`MODAL_${conversion.strSnake(action?.label).toUpperCase()}_${toggleKey}`);
273
237
  item && setSelected?.(item);
274
- }}
275
- {...action.button}
276
- />
277
- )
238
+ }
239
+ }}
240
+ {...action.button}
241
+ />
278
242
  }
279
243
 
280
- if (typeof action == "function") {
244
+ if(typeof action == "function") {
281
245
  return (
282
- <div key={key}>
283
- {action(
284
- item || {},
285
- (type) => {
286
- setToggle(`MODAL_${type}_${toggleKey}`)
287
- item && setSelected?.(item)
288
- },
289
- () => item && setSelected?.(item)
290
- )}
291
- </div>
246
+ <span key={`action-fn-${key}`}>
247
+ {action(item || {}, (type: "EDIT" | "DELETE") => {
248
+ if(type == "EDIT") {
249
+ setToggle(`MODAL_FORM_${toggleKey}`);
250
+ item && setSelected?.(item);
251
+ }
252
+
253
+ if (type == "DELETE") {
254
+ setToggle(`MODAL_DELETE_${toggleKey}`);
255
+ item && setSelected?.(item);
256
+ }
257
+ }, () => item && setSelected?.(item), () => {}, options?.size)}
258
+ </span>
292
259
  )
293
260
  }
261
+
262
+ return <span key={`action-default-${key}`}></span>;
294
263
  })}
295
264
  </div>
296
265
  </>
@@ -298,37 +267,46 @@ export function TableSupervisionComponent({
298
267
  }
299
268
 
300
269
 
270
+ // ============================
271
+ // ## Data table preparation
272
+ // ============================
273
+ const dataTables = useMemo(() => {
274
+ return data?.data?.map((row: object) => {
275
+ return {
276
+ ...row,
277
+ action: renderTableAction(actionControl, row),
278
+ };
279
+ });
280
+ }, [actionControl, data]);
301
281
 
302
282
 
303
283
  // ============================
304
284
  // ## Render detail page
305
285
  // ============================
306
286
  const detailPage = useMemo(() => {
307
- if (detailContent === false || detailContent === undefined) return null;
287
+ if (!toggle[`MODAL_SHOW_${toggleKey}`]) return null;
308
288
  return (
309
- <div className="table-supervision-detail-container">
310
- <div className="table-supervision-detail-body">
311
- {!!selected && (typeof detailContent === "object" && Array.isArray(detailContent) ? detailContent?.map((column, key) => {
289
+ <div className="p-4">
290
+ <div className={cn(
291
+ "flex flex-col gap-y-4",
292
+ )}>
293
+ {!!selected && (typeof detailControl === "object" && detailControl?.length ? detailControl?.map((column, key) => {
312
294
  if (typeof column === "string") {
313
295
  return (<TypographyColumnComponent
314
296
  key={key}
315
297
  title={columns?.find((c) => c.selector == column)?.label}
316
298
  content={selected[column]}
317
299
  />)
318
- } else if (typeof column === "object" && column !== null) {
319
- const colObj = column as { label: string, item: string | ((data: Record<string, any>) => ReactNode), conversion?: keyof typeof conversion };
320
- const rawContent = typeof colObj.item === "string" ? selected[colObj.item] : colObj.item(selected);
321
- const conversionKey = colObj.conversion;
322
- const content = conversionKey && conversion[conversionKey] ? (conversion[conversionKey] as any)(rawContent) : rawContent;
300
+ } else if (typeof column === "object") {
323
301
  return (<TypographyColumnComponent
324
302
  key={key}
325
- title={colObj.label}
326
- content={content}
303
+ title={column?.label}
304
+ content={typeof column?.item === "string" ? selected[column?.item] : column?.item(selected)}
327
305
  />)
328
306
  } else {
329
307
  return column?.(selected)
330
308
  }
331
- }) : typeof detailContent === "function" ? (detailContent as any)(selected) : columns?.map((column, key) => (
309
+ }) : typeof detailControl == "function" ? detailControl(selected) : columns?.map((column, key) => (
332
310
  <TypographyColumnComponent
333
311
  key={key}
334
312
  title={column.label}
@@ -338,7 +316,7 @@ export function TableSupervisionComponent({
338
316
  </div>
339
317
  </div>
340
318
  )
341
- }, [selected, detailContent, columns]);
319
+ }, [selected, detailControl]);
342
320
 
343
321
 
344
322
 
@@ -349,43 +327,64 @@ export function TableSupervisionComponent({
349
327
  const fields = useMemo(() => {
350
328
  return formControl?.fields?.length ? formControl?.fields.map((form) => {
351
329
  return typeof form === "string" ? {
352
- label : form,
353
- name : conversion.strSnake(form),
354
- type : "text",
355
- visibility : "*"
356
- } : {
357
- ...form,
358
- visibility : form.visibility || "*"
359
- }
360
- }) as FormType[] : []
361
- }, [formControl]);
330
+ col : 12,
331
+ type : "text",
332
+ construction : {
333
+ name : form,
334
+ label : form,
335
+ },
336
+ } : { ...form };
337
+ }) : data?.forms || data?.columns || columnControl?.map((col) => {
338
+ return {
339
+ col : 12,
340
+ type : "text",
341
+ construction : {
342
+ name : typeof col == "string" ? col : col?.selector,
343
+ label : typeof col == "string" ? col : col?.label,
344
+ placeholder : `Masukkan ${ typeof col == "string" ? col : col?.label}...`,
345
+ },
346
+ };
347
+ }) || (data?.data?.at(0) ? Object.keys(data.data[0]).map((col) => {
348
+ return {
349
+ col : 12,
350
+ type : "text",
351
+ construction : {
352
+ name : col,
353
+ label : col,
354
+ placeholder : `Masukkan ${col}...`,
355
+ },
356
+ };
357
+ })
358
+ : []);
359
+ }, [formControl, data]);
362
360
 
363
361
 
364
362
 
365
- const formPage = useMemo(() => {
363
+ // ============================
364
+ // ## Render form page
365
+ // ============================
366
+ const formPage = useMemo(async () => {
366
367
  return (
367
- <FormSupervisionComponent
368
- fields={fields}
369
- defaultValue={formControl?.defaultValue}
368
+ <FormSupervisionComponent
369
+ submitControl={(fetchControl as ApiType).path ? {
370
+ path: `${(fetchControl as ApiType).path}/${(selected as { id: number })?.id || "" }`,
371
+ method: !(selected as { id: number })?.id ? "POST" : "PUT",
372
+ } : (fetchControl as ApiType).url ? {
373
+ url: `${(fetchControl as ApiType).url}/${(selected as { id: number })?.id || ""}`,
374
+ method: !(selected as { id: number })?.id ? "POST" : "PUT",
375
+ } : { idb: (fetchControl as ({ idb: UseResourceIdb }))?.idb }
376
+ }
377
+ fields={fields?.filter((f: any) => f.visibility ? !(selected as { id: number })?.id ? ["*", "create"]?.includes(f.visibility) : ["*", "update"]?.includes(f.visibility) : true) as FormType[]}
378
+ defaultValue={formControl?.defaultValue ? await formControl?.defaultValue(selected || null) : selected}
370
379
  payload={formControl?.payload}
371
- submitControl={fetchControl}
372
380
  onSuccess={() => {
373
- setToggle(`MODAL_FORM_${toggleKey}`, false)
374
- reset()
381
+ reset();
382
+ setTimeout(() => { setToggle(`MODAL_FORM_${toggleKey}`, false) }, 900);
375
383
  }}
376
384
  />
377
385
  )
378
- }, [selected, fields])
379
-
386
+ }, [selected, fetchControl, formControl]);
380
387
 
381
- const dataTables = useMemo(() => {
382
- return data?.data?.map((item: Record<string, any>) => {
383
- return {
384
- ...item,
385
- action: renderTableAction(actionControl, item)
386
- };
387
- }) || [];
388
- }, [actionControl, data]);
389
388
 
390
389
 
391
390
  useEffect(() => {
@@ -395,131 +394,131 @@ export function TableSupervisionComponent({
395
394
 
396
395
  return (
397
396
  <>
398
- <Suspense fallback={<div>Loading...</div>}>
399
- {title && <h1 className="table-supervision-title">{title}</h1>}
400
-
401
-
402
- <TableComponent
403
- id={tableKey}
404
- controlBar={controlBar?.map((cb) => {
405
- if (cb == "CREATE") {
406
- if (isSm) return
407
- return (
408
- <div className="control-bar-create-wrapper" key="button-add">
409
- <ButtonComponent
410
- icon={faPlus}
411
- label="Tambah Data"
412
- size="sm"
413
- onClick={() => {
414
- setToggle(`MODAL_FORM_${toggleKey}`)
415
- setSelected(null)
416
- }}
417
- />
418
- </div>
419
- )
420
- }
397
+ {title && <h1 className="text-lg lg:text-xl font-bold mb-2 lg:mb-4">{title}</h1>}
421
398
 
422
- if (cb == "IMPORT") {
423
- return (
424
- <div className="control-bar-button-wrapper" key={"import"}>
425
- <ButtonComponent
426
- icon={faFileExcel}
427
- label="Import"
428
- variant="outline"
429
- className="table-supervision-control-button"
430
- onClick={() => setToggle(`MODAL_IMPORT_${toggleKey}`)}
431
- size="sm"
432
- />
433
- </div>
434
- )
435
- }
399
+ <TableComponent
400
+ id={tableKey}
401
+ controlBar={controlBar?.map((cb) => {
402
+ if (cb == "CREATE") {
403
+ if (isSm) return
404
+ return (
405
+ <div className="pl-1.5 pr-3 mr-2 border-r" key="button-add">
406
+ <ButtonComponent
407
+ icon={"solid/plus"}
408
+ label="Tambah Data"
409
+ size="sm"
410
+ onClick={() => {
411
+ setToggle(`MODAL_FORM_${toggleKey}`)
412
+ setSelected(null)
413
+ }}
414
+ />
415
+ </div>
416
+ )
417
+ }
436
418
 
437
- if (cb == "EXPORT") {
438
- return (
439
- <div className="control-bar-button-wrapper" key={"export-excel"}>
440
- <ButtonComponent
441
- icon={faFileExcel}
442
- label="Export"
443
- variant="outline"
444
- className="table-supervision-control-button"
445
- onClick={() => setToggle(`MODAL_EXPORT_${toggleKey}`)}
446
- size="sm"
447
- />
448
- </div>
449
- )
450
- }
419
+ if (cb == "IMPORT") {
420
+ return (
421
+ <div className="px-1.5 rounded-md relative" key={"import"}>
422
+ <ButtonComponent
423
+ icon={"solid/file-excel"}
424
+ label="Import"
425
+ variant="outline"
426
+ className="!text-foreground"
427
+ onClick={() => setToggle(`MODAL_IMPORT_${toggleKey}`)}
428
+ size="sm"
429
+ />
430
+ </div>
431
+ )
432
+ }
451
433
 
452
- if (cb == "PRINT") {
453
- return (
454
- <div className="control-bar-button-wrapper" key={"export-pdf"}>
455
- <ButtonComponent
456
- icon={faFilePdf}
457
- label="Cetak"
458
- variant="outline"
459
- className="table-supervision-control-button"
460
- onClick={() => setToggle(`MODAL_PRINT_${toggleKey}`)}
461
- size="sm"
462
- />
463
- </div>
464
- )
465
- }
434
+ if (cb == "EXPORT") {
435
+ return (
436
+ <div className="px-1.5 rounded-md relative" key={"export-excel"}>
437
+ <ButtonComponent
438
+ icon={"solid/file-excel"}
439
+ label="Export"
440
+ variant="outline"
441
+ className="!text-foreground"
442
+ onClick={() => setToggle(`MODAL_EXPORT_${toggleKey}`)}
443
+ size="sm"
444
+ />
445
+ </div>
446
+ )
447
+ }
466
448
 
467
- return cb
468
- }) || [
469
- ...(!isSm ? [
470
- <div className="control-bar-create-wrapper" key="button-add">
471
- <ButtonComponent
472
- icon={faPlus}
473
- label="Tambah Data"
474
- size="sm"
475
- onClick={() => {
476
- setToggle(`MODAL_FORM_${toggleKey}`)
477
- setSelected(null)
478
- }}
479
- />
480
- </div>
481
- ] : []),
482
- "SEARCH",
483
- ...(columns?.filter((c) => !!(c as { filterable?: any }).filterable)?.length ? ["FILTER"] : []),
484
- ...(columns?.filter((c) => !!(c as { sortable?: any }).sortable)?.length ? ["SORT"] : []),
485
- "SELECTABLE", "REFRESH",
486
- ]}
487
- columns={columns as TableColumnType[]}
488
- data={dataTables}
489
- onRowClick={detailAction ? detailAction : (detailContent !== false && detailContent !== undefined) ? (e) => {
490
- setToggle(`MODAL_SHOW_${toggleKey}`)
491
- setSelected(e)
492
- } : undefined}
493
- actionBulking={actionBulkingControl}
494
- checks={checks || []}
495
- onChangeChecks={(e) => setChecks(e)}
496
- block={block}
497
- focus={focus}
498
- noIndex={noIndex}
499
- responsiveControl={responsiveControl ? {
500
- mobile: responsiveControl?.mobile == true ? {
501
- leftActionControl: (Array.isArray(actionControl) ? actionControl : (actionControl || actionControl == undefined) ? ['EDIT', "DELETE"] : []).includes('EDIT') ? {
502
- icon: faEdit,
503
- onAction: (item) => {
504
- setToggle(`MODAL_FORM_${toggleKey}`);
505
- item && setSelected?.(item);
506
- }
507
- } : undefined,
508
- rightActionControl: (Array.isArray(actionControl) ? actionControl : (actionControl || actionControl == undefined) ? ['EDIT', "DELETE"] : []).includes('DELETE') ? {
509
- icon: faTrash,
510
- onAction: (item) => {
511
- setToggle(`MODAL_DELETE_${toggleKey}`);
512
- item && setSelected?.(item);
513
- }
514
- } : undefined
515
- } : responsiveControl?.mobile || undefined,
516
- } : undefined}
517
- {...tableControl}
518
- />
449
+ if (cb == "PRINT") {
450
+ return (
451
+ <div className="px-1.5 rounded-md relative" key={"export-pdf"}>
452
+ <ButtonComponent
453
+ icon={"solid/file-pdf"}
454
+ label="Cetak"
455
+ variant="outline"
456
+ className="!text-foreground"
457
+ onClick={() => setToggle(`MODAL_PRINT_${toggleKey}`)}
458
+ size="sm"
459
+ />
460
+ </div>
461
+ )
462
+ }
463
+
464
+ return cb
465
+ }) || [
466
+ ...(!isSm ? [
467
+ <div className="pl-1.5 pr-3 mr-2 border-r" key="button-add">
468
+ <ButtonComponent
469
+ icon={"solid/plus"}
470
+ label="Tambah Data"
471
+ size="sm"
472
+ onClick={() => {
473
+ setToggle(`MODAL_FORM_${toggleKey}`)
474
+ setSelected(null)
475
+ }}
476
+ />
477
+ </div>
478
+ ] : []),
479
+ "SEARCH",
480
+ ...(columns?.filter((c) => !!(c as { filterable?: any }).filterable)?.length ? ["FILTER"] : []),
481
+ ...(columns?.filter((c) => !!(c as { sortable?: any }).sortable)?.length ? ["SORT"] : []),
482
+ "SELECTABLE", "REFRESH",
483
+ ]}
484
+ columns={columns as TableColumnType[]}
485
+ data={dataTables}
486
+ onRowClick={onRowClick ? onRowClick : detailControl != false ? (e) => {
487
+ setToggle(`MODAL_SHOW_${toggleKey}`)
488
+ setSelected(e)
489
+ } : undefined}
490
+ actionBulking={actionBulkingControl}
491
+ checks={checks || []}
492
+ onChangeChecks={(e) => setChecks(e)}
493
+ block={block}
494
+ focus={focus}
495
+ noIndex={noIndex}
496
+ responsiveControl={responsiveControl ? {
497
+ mobile: responsiveControl?.mobile ? {
498
+ ...(typeof responsiveControl.mobile === 'object' ? responsiveControl.mobile : {}),
499
+ leftActionControl: (typeof responsiveControl.mobile === 'object' && responsiveControl.mobile.leftActionControl !== undefined) ? responsiveControl.mobile.leftActionControl : (Array.isArray(actionControl) ? actionControl : (actionControl || actionControl == undefined) ? ['EDIT', "DELETE"] : []).includes('EDIT') ? {
500
+ icon: "solid/edit",
501
+ onAction: (item) => {
502
+ setToggle(`MODAL_FORM_${toggleKey}`);
503
+ item && setSelected?.(item);
504
+ }
505
+ } : undefined,
506
+ rightActionControl: (typeof responsiveControl.mobile === 'object' && responsiveControl.mobile.rightActionControl !== undefined) ? responsiveControl.mobile.rightActionControl : (Array.isArray(actionControl) ? actionControl : (actionControl || actionControl == undefined) ? ['EDIT', "DELETE"] : []).includes('DELETE') ? {
507
+ icon: "solid/trash",
508
+ onAction: (item) => {
509
+ setToggle(`MODAL_DELETE_${toggleKey}`);
510
+ item && setSelected?.(item);
511
+ }
512
+ } : undefined
513
+ } : undefined,
514
+ } : undefined}
515
+ {...tableControl}
516
+ />
519
517
 
518
+ {controlBar?.find((cb) => cb == "CREATE") && (
520
519
  <ButtonComponent
521
- icon={faPlus}
522
- className="table-supervision-mobile-add-btn"
520
+ icon={"solid/plus"}
521
+ className="fixed bottom-24 right-4 w-14 h-14 z-20 md:hidden"
523
522
  size="lg"
524
523
  rounded
525
524
  onClick={() => {
@@ -527,162 +526,128 @@ export function TableSupervisionComponent({
527
526
  setSelected(null)
528
527
  }}
529
528
  />
529
+ )}
530
+
531
+
532
+ <FloatingPageComponent
533
+ show={!!toggle[`MODAL_SHOW_${toggleKey}`]}
534
+ onClose={() => setToggle(`MODAL_SHOW_${toggleKey}`, false)}
535
+ title="Detail"
536
+ className="bg-background"
537
+ footer={renderTableAction(actionControl, undefined, {className: isSm ? "justify-end p-2 bg-background" : "justify-end", size: isSm ? "sm" : "md"})}
538
+ >
539
+ {detailPage}
540
+ </FloatingPageComponent>
541
+
542
+
543
+ <FloatingPageComponent
544
+ show={!!toggle[`MODAL_FORM_${toggleKey}`]}
545
+ onClose={() => setToggle(`MODAL_FORM_${toggleKey}`, false)}
546
+ title={!!selected ? "Ubah Data" : "Tambah Data"}
547
+ className={cn("bg-white", formControl?.modalControl?.className)}
548
+ >
549
+ <div className="p-4">
550
+ {formPage}
551
+ </div>
552
+ </FloatingPageComponent>
553
+
554
+
555
+ <FloatingPageComponent
556
+ show={!!toggle[`MODAL_EXPORT_${toggleKey}`]}
557
+ onClose={() => setToggle(`MODAL_EXPORT_${toggleKey}`, false)}
558
+ title="Export Ke Excel"
559
+ className="bg-white md:w-[1200px] max-w-[1200px]"
560
+ >
561
+ <ExportExcel
562
+ fetchControl={fetchControl}
563
+ filename={"Export - " + title}
564
+ columnControl={columns?.map((cc) => ({
565
+ label: cc.label || "",
566
+ selector: cc.selector || "",
567
+ }))}
568
+ />
569
+ </FloatingPageComponent>
570
+
571
+
572
+ <FloatingPageComponent
573
+ show={!!toggle[`MODAL_IMPORT_${toggleKey}`]}
574
+ onClose={() => setToggle(`MODAL_IMPORT_${toggleKey}`, false)}
575
+ title="Import Dari Excel"
576
+ className="bg-white md:w-[1200px] max-w-[1200px]"
577
+ >
578
+ <ImportExcel
579
+ submitControl={{ path: (fetchControl as ApiType)?.path + "/import" }}
580
+ columnControl={columns?.map((cc) => ({
581
+ label: cc.label || "",
582
+ selector: cc.selector || "",
583
+ }))}
584
+ />
585
+ </FloatingPageComponent>
586
+
587
+
588
+ {/* <FloatingPageComponent
589
+ show={!!toggle[`MODAL_PRINT_${toggleKey}`]}
590
+ onClose={() => setToggle(`MODAL_PRINT_${toggleKey}`, false)}
591
+ title="Print PDF"
592
+ className="bg-white md:w-[1200px] max-w-[1200px]"
593
+ >
594
+ <PrintTable
595
+ fetchControl={fetchControl}
596
+ columnControl={columns?.map((cc) => ({
597
+ label: cc.label || "",
598
+ selector: cc.selector || "",
599
+ }))}
600
+ title={"Print - " + title}
601
+ />
602
+ </FloatingPageComponent> */}
603
+
604
+
605
+ <ModalConfirmComponent
606
+ show={!!toggle[`MODAL_DELETE_${toggleKey}`]}
607
+ onClose={() => setToggle(`MODAL_DELETE_${toggleKey}`, false)}
608
+ title={<>Menghapus Data <span className="font-semibold">&quot;{selected?.[columns?.at(0)?.selector || ""]}&quot;</span> ?</>}
609
+ submitControl={{
610
+ onSubmit: {
611
+ ...((fetchControl as ApiType).path
612
+ ? {path: `${(fetchControl as ApiType).path}/${(selected as { id: number })?.id || ""}`}
613
+ : (fetchControl as ApiType).url ? {url: `${(fetchControl as ApiType).url}/${(selected as { id: number })?.id || ""}`}
614
+ : { idb: { ...(fetchControl as ({ idb: UseResourceIdb }))?.idb, id: (selected as { id: number })?.id || "" }}
615
+ ),
616
+ method: "DELETE",
617
+ },
618
+ onSuccess: () => {
619
+ reset();
620
+ setTimeout(() => { setToggle(`MODAL_DELETE_${toggleKey}`, false) }, 900);
621
+ },
622
+ }}
623
+ />
530
624
 
531
-
532
- {(detailContent !== false && detailContent !== undefined) && (isSm ? (
533
- <BottomSheetComponent
534
- show={!!toggle[`MODAL_SHOW_${toggleKey}`]}
535
- onClose={() => setToggle(`MODAL_SHOW_${toggleKey}`, false)}
536
- className="table-supervision-modal"
537
- footer={renderTableAction(actionControl, undefined, {className: isSm ? "justify-end p-2 bg-background" : "justify-end", size: isSm ? "sm" : "md"})}
538
- size="98vh"
539
- {...(detailModalProps as any)}
540
- >
541
- {detailPage}
542
- </BottomSheetComponent>
543
- ) : (
544
- <FloatingPageComponent
545
- show={!!toggle[`MODAL_SHOW_${toggleKey}`]}
546
- onClose={() => setToggle(`MODAL_SHOW_${toggleKey}`, false)}
547
- title="Detail"
548
- className="table-supervision-modal"
549
- footer={renderTableAction(actionControl, undefined, {className: isSm ? "justify-end p-2 bg-background" : "justify-end", size: isSm ? "sm" : "md"})}
550
- {...(detailModalProps as any)}
551
- >
552
- {detailPage}
553
- </FloatingPageComponent>
554
- ))}
555
-
556
-
557
- {isSm ? (
558
- <BottomSheetComponent
559
- show={!!toggle[`MODAL_FORM_${toggleKey}`]}
560
- onClose={() => setToggle(`MODAL_FORM_${toggleKey}`, false)}
561
- className={cn("table-supervision-modal", formControl?.modalControl?.className)}
562
- size="98vh"
563
- >
564
- <div className="table-supervision-form-mobile-container">
565
- {formPage}
566
- </div>
567
- </BottomSheetComponent>
568
- ) : (
569
- <FloatingPageComponent
570
- show={!!toggle[`MODAL_FORM_${toggleKey}`]}
571
- onClose={() => setToggle(`MODAL_FORM_${toggleKey}`, false)}
572
- title={!!selected ? "Ubah Data" : "Tambah Data"}
573
- className={cn("table-supervision-modal", formControl?.modalControl?.className)}
574
- >
575
- <div className="table-supervision-form-container">
576
- {formPage}
577
- </div>
578
- </FloatingPageComponent>
579
- )}
580
-
581
-
582
- {ExportExcel && (
583
- <FloatingPageComponent
584
- show={!!toggle[`MODAL_EXPORT_${toggleKey}`]}
585
- onClose={() => setToggle(`MODAL_EXPORT_${toggleKey}`, false)}
586
- title="Export Ke Excel"
587
- className="table-supervision-large-modal"
588
- >
589
- <ExportExcel
590
- fetchControl={fetchControl as FetchControlType}
591
- filename={"Export - " + title}
592
- columnControl={columns?.map((cc: TableSupervisionColumnProps) => ({
593
- label: cc.label || "",
594
- selector: cc.selector || "",
595
- status: cc.exportable === false ? "hidden" : cc.exportable === true ? "default" : typeof cc.exportable === "string" ? cc.exportable : undefined,
596
- }))}
597
- />
598
- </FloatingPageComponent>
599
- )}
600
-
601
-
602
- {ImportExcel && (
603
- <FloatingPageComponent
604
- show={!!toggle[`MODAL_IMPORT_${toggleKey}`]}
605
- onClose={() => setToggle(`MODAL_IMPORT_${toggleKey}`, false)}
606
- title="Import Dari Excel"
607
- className="table-supervision-large-modal"
608
- >
609
- <ImportExcel
610
- submitControl={importControl}
611
- fetchControl={
612
- (fetchControl as ApiType).path ? {
613
- path: (fetchControl as ApiType).path,
614
- } : undefined
615
- }
616
- columnControl={columns?.filter((cc: TableSupervisionColumnProps) => cc.importable !== false).map((cc: TableSupervisionColumnProps) => ({
617
- label: cc.label || "",
618
- selector: cc.selector || "",
619
- }))}
620
- />
621
- </FloatingPageComponent>
622
- )}
623
-
624
-
625
- <ModalConfirmComponent
626
- show={!!toggle[`MODAL_DELETE_${toggleKey}`]}
627
- onClose={() => setToggle(`MODAL_DELETE_${toggleKey}`, false)}
628
- icon={faQuestionCircle}
629
- title={`Menghapus Data?`}
630
- submitControl={{
631
- onSubmit: {
632
- ...((fetchControl as ApiType).path
633
- ? {path: `${(fetchControl as ApiType).path}/${(selected as { id: number })?.id || ""}`}
634
- : (fetchControl as ApiType).url ? {url: `${(fetchControl as ApiType).url}/${(selected as { id: number })?.id || ""}`}
635
- : { idb: { ...(fetchControl as ({ idb: UseResourceIdb }))?.idb, id: (selected as { id: number })?.id || "" }}
636
- ),
637
- method: "DELETE",
638
- },
639
- onSuccess: () => {
640
- reset();
641
- setToggle(`MODAL_DELETE_${toggleKey}`, false);
642
- },
643
- }}
644
- >
645
- {columns?.at(0)?.selector && selected ? (
646
- <p className="table-supervision-confirm-text">Yakin menghapus <span className="table-supervision-confirm-item-name">&quot;{selected[columns?.at(0)?.selector || ""]}&quot;</span>?</p>
647
- ) : (
648
- <p className="table-supervision-confirm-text">Yakin yang dihapus sudah benar?</p>
649
- )}
650
- </ModalConfirmComponent>
651
-
652
- {actionControl && Array.isArray(actionControl) && actionControl.filter((ac) => typeof ac == "object")?.map((ac, acKey) => {
653
- const submitControl = ac.modal?.submitControl?.onSubmit as ApiType;
654
- return (
655
- <ModalConfirmComponent
656
- key={acKey}
657
- show={!!toggle[`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`]}
658
- onClose={() => setToggle(`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`, false)}
659
- icon={faQuestionCircle}
660
- title={`${ac.label} Data?`}
661
- submitControl={{
662
- onSubmit: {
663
- ...((submitControl as ApiType)?.path
664
- ? {path: `${(submitControl as ApiType).path}/${(selected as { id: number })?.id || ""}`}
665
- : (submitControl as ApiType)?.url ? {url: `${(submitControl as ApiType).url}/${(selected as { id: number })?.id || ""}`}
666
- : { idb: { ...(submitControl as ({ idb: UseResourceIdb }))?.idb, id: (selected as { id: number })?.id || "" }}
667
- ),
668
- ...ac.modal?.submitControl?.onSubmit,
669
- },
670
- onSuccess: () => {
671
- reset();
672
- setToggle(`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`, false);
673
- },
674
- }}
675
- {...ac.modal}
676
- >
677
- {columns?.at(0)?.selector && selected ? (
678
- <p className="table-supervision-confirm-text">Yakin melakukan aksi untuk data <span className="table-supervision-confirm-item-name">&quot;{selected[columns?.at(0)?.selector || ""]}&quot;</span>?</p>
679
- ) : (
680
- <p className="table-supervision-confirm-text">Yakin aksi yang dilakukan sudah benar?</p>
681
- )}
682
- </ModalConfirmComponent>
683
- )
684
- })}
685
- </Suspense>
625
+ {actionControl && Array.isArray(actionControl) && actionControl.filter((ac) => typeof ac == "object")?.map((ac, acKey) => {
626
+ const submitControl = ac.modal?.submitControl?.onSubmit as ApiType;
627
+ return (
628
+ <ModalConfirmComponent
629
+ key={acKey}
630
+ show={!!toggle[`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`]}
631
+ onClose={() => setToggle(`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${toggleKey}`, false)}
632
+ title={ac?.modal?.title || ac.label}
633
+ submitControl={{
634
+ onSubmit: {
635
+ ...(submitControl?.path
636
+ ? {path: `${submitControl?.path}/${(selected as { id: number })?.id || ""}`}
637
+ : {url: `${submitControl?.url}/${(selected as { id: number })?.id || ""}`}
638
+ ),
639
+ method: submitControl?.method || "POST",
640
+ },
641
+ onSuccess: () => {
642
+ reset();
643
+ setToggle(`MODAL_${conversion.strSnake(ac.label).toUpperCase()}_${conversion.strSnake(tableKey).toUpperCase()}`, false);
644
+ setSelected(null)
645
+ ac.modal?.submitControl?.onSuccess?.()
646
+ },
647
+ }}
648
+ >{ac.modal?.children}</ModalConfirmComponent>
649
+ )
650
+ })}
686
651
  </>
687
652
  );
688
653
  }