@skalfa/skalfa-component 1.0.8 → 1.0.10
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.
- package/dist/accordion/Accordion.component.js +2 -3
- package/dist/breadcrumb/Breadcrumb.component.js +2 -3
- package/dist/button/Button.component.d.ts +2 -1
- package/dist/button/Button.component.js +2 -2
- package/dist/carousel/Carousel.component.js +2 -3
- package/dist/chip/Chip.component.js +2 -3
- package/dist/contexts-mock.d.ts +2 -0
- package/dist/contexts-mock.js +10 -0
- package/dist/input/Checkbox.component.js +2 -3
- package/dist/input/Input.component.d.ts +3 -2
- package/dist/input/Input.component.js +3 -3
- package/dist/input/InputCheckbox.component.js +1 -1
- package/dist/input/InputCurrency.component.d.ts +3 -2
- package/dist/input/InputCurrency.component.js +3 -3
- package/dist/input/InputDate.component.js +4 -5
- package/dist/input/InputDatetime.component.d.ts +3 -2
- package/dist/input/InputDatetime.component.js +3 -3
- package/dist/input/InputDocument.component.js +7 -8
- package/dist/input/InputImage.component.js +3 -4
- package/dist/input/InputNumber.component.js +3 -4
- package/dist/input/InputPassword.component.js +3 -3
- package/dist/input/InputRadio.component.js +1 -1
- package/dist/input/InputTime.component.js +3 -3
- package/dist/input/InputValues.component.js +3 -4
- package/dist/input/Select.component.js +6 -7
- package/dist/modal/FloatingPage.component.d.ts +3 -1
- package/dist/modal/FloatingPage.component.js +7 -3
- package/dist/modal/Modal.component.js +1 -2
- package/dist/modal/ModalConfirm.component.d.ts +2 -2
- package/dist/modal/ModalConfirm.component.js +14 -12
- package/dist/modal/Toast.component.js +1 -2
- package/dist/nav/Bottombar.component.d.ts +2 -2
- package/dist/nav/Bottombar.component.js +7 -8
- package/dist/nav/Footer.component.d.ts +2 -2
- package/dist/nav/Footer.component.js +6 -7
- package/dist/nav/Headbar.component.js +2 -3
- package/dist/nav/Navbar.component.d.ts +2 -2
- package/dist/nav/Navbar.component.js +3 -4
- package/dist/nav/Sidebar.component.d.ts +3 -7
- package/dist/nav/Sidebar.component.js +14 -17
- package/dist/supervision/FormSupervision.component.d.ts +4 -29
- package/dist/supervision/FormSupervision.component.js +84 -136
- package/dist/supervision/TableSupervision.component.d.ts +17 -26
- package/dist/supervision/TableSupervision.component.js +207 -193
- package/dist/table/ControlBar.component.js +15 -16
- package/dist/table/FilterComponent.js +4 -6
- package/dist/table/Pagination.component.js +2 -3
- package/dist/table/Table.component.js +3 -4
- package/dist/wrap/Swipe.component.js +2 -2
- package/package.json +18 -10
- package/src/accordion/Accordion.component.tsx +3 -3
- package/src/breadcrumb/Breadcrumb.component.tsx +4 -4
- package/src/button/Button.component.tsx +3 -3
- package/src/carousel/Carousel.component.tsx +4 -4
- package/src/chip/Chip.component.tsx +3 -4
- package/src/contexts-mock.ts +6 -0
- package/src/input/Checkbox.component.tsx +3 -3
- package/src/input/Input.component.tsx +6 -6
- package/src/input/InputCheckbox.component.tsx +1 -1
- package/src/input/InputCurrency.component.tsx +6 -6
- package/src/input/InputDate.component.tsx +6 -7
- package/src/input/InputDatetime.component.tsx +6 -6
- package/src/input/InputDocument.component.tsx +9 -9
- package/src/input/InputImage.component.tsx +4 -5
- package/src/input/InputNumber.component.tsx +7 -8
- package/src/input/InputPassword.component.tsx +4 -4
- package/src/input/InputRadio.component.tsx +1 -1
- package/src/input/InputTime.component.tsx +4 -4
- package/src/input/InputValues.component.tsx +5 -6
- package/src/input/Select.component.tsx +10 -10
- package/src/modal/FloatingPage.component.tsx +33 -3
- package/src/modal/Modal.component.tsx +1 -2
- package/src/modal/ModalConfirm.component.tsx +34 -49
- package/src/modal/Toast.component.tsx +1 -2
- package/src/nav/Bottombar.component.tsx +9 -10
- package/src/nav/Footer.component.tsx +8 -9
- package/src/nav/Headbar.component.tsx +3 -3
- package/src/nav/Navbar.component.tsx +9 -10
- package/src/nav/Sidebar.component.tsx +55 -46
- package/src/supervision/FormSupervision.component.tsx +203 -224
- package/src/supervision/TableSupervision.component.tsx +420 -455
- package/src/table/ControlBar.component.tsx +16 -16
- package/src/table/FilterComponent.tsx +9 -11
- package/src/table/Pagination.component.tsx +6 -6
- package/src/table/Table.component.tsx +5 -5
- package/src/wrap/Swipe.component.tsx +3 -3
- package/src/types.d.ts +0 -7
|
@@ -1,23 +1,37 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import React, { ReactNode, useEffect,
|
|
4
|
-
import { faSave, faQuestionCircle, faPlus, faTimes } from "@fortawesome/free-solid-svg-icons";
|
|
3
|
+
import React, { ReactNode, useEffect, useState } from "react";
|
|
5
4
|
import { ApiType, cn, pcn, FormErrorType, FormRegisterType, FormValueType, useForm, ValidationRules, DBSchema } from "@utils";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
import {
|
|
6
|
+
InputCheckboxComponent,
|
|
7
|
+
InputComponent,
|
|
8
|
+
InputCurrencyComponent,
|
|
9
|
+
InputDateComponent,
|
|
10
|
+
InputNumberComponent,
|
|
11
|
+
InputOtpComponent,
|
|
12
|
+
InputPasswordComponent,
|
|
13
|
+
InputRadioComponent,
|
|
14
|
+
SelectComponent,
|
|
15
|
+
ButtonComponent,
|
|
16
|
+
ModalConfirmComponent,
|
|
17
|
+
InputProps,
|
|
18
|
+
InputCheckboxProps,
|
|
19
|
+
InputCurrencyProps,
|
|
20
|
+
InputDateProps,
|
|
21
|
+
InputNumberProps,
|
|
22
|
+
InputRadioProps,
|
|
23
|
+
SelectProps,
|
|
24
|
+
InputPasswordProps,
|
|
25
|
+
InputOtpProps,
|
|
26
|
+
InputTimeProps,
|
|
27
|
+
InputImageProps,
|
|
28
|
+
InputDateTimeProps,
|
|
29
|
+
InputDatetimeComponent,
|
|
30
|
+
InputTimeComponent,
|
|
31
|
+
InputImageComponent,
|
|
32
|
+
} from "../";
|
|
33
|
+
import { Icon } from "@skalfa/skalfa-icon";
|
|
34
|
+
import { useLang } from "@skalfa/skalfa-lang";
|
|
21
35
|
|
|
22
36
|
|
|
23
37
|
|
|
@@ -33,7 +47,6 @@ type formCustomConstructionProps = ({
|
|
|
33
47
|
}: {
|
|
34
48
|
formControl : (name: string) => {
|
|
35
49
|
register: (regName: string, regValidations?: ValidationRules | undefined) => void;
|
|
36
|
-
unregister: (regName: string) => void;
|
|
37
50
|
onChange: (e: any) => void;
|
|
38
51
|
value: any;
|
|
39
52
|
invalid: any;
|
|
@@ -47,12 +60,11 @@ type formCustomConstructionProps = ({
|
|
|
47
60
|
}) => ReactNode;
|
|
48
61
|
|
|
49
62
|
type ClusterConstruction = {
|
|
50
|
-
name
|
|
51
|
-
label
|
|
52
|
-
tip
|
|
53
|
-
fields
|
|
54
|
-
wrap
|
|
55
|
-
min ?: number;
|
|
63
|
+
name : string;
|
|
64
|
+
label : string;
|
|
65
|
+
tip : string;
|
|
66
|
+
fields : FormType[];
|
|
67
|
+
wrap : boolean;
|
|
56
68
|
|
|
57
69
|
/** Use custom class with: "label::", "tip::", "error::", "icon::", "suggest::", "suggest-item::". */
|
|
58
70
|
className : string;
|
|
@@ -77,28 +89,12 @@ type ConstructionMap = {
|
|
|
77
89
|
|
|
78
90
|
type TypeKeys = keyof ConstructionMap;
|
|
79
91
|
|
|
80
|
-
export type WatchContext = {
|
|
81
|
-
values : Record<string, any>
|
|
82
|
-
self : string
|
|
83
|
-
prev : WatchAction
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export type WatchAction = {
|
|
87
|
-
disabled ?: boolean
|
|
88
|
-
hidden ?: boolean
|
|
89
|
-
value ?: any
|
|
90
|
-
required ?: boolean
|
|
91
|
-
readonly ?: boolean
|
|
92
|
-
reset ?: boolean
|
|
93
|
-
}
|
|
94
|
-
|
|
95
92
|
export interface FormType<T extends TypeKeys = keyof ConstructionMap> {
|
|
96
93
|
col ?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | string;
|
|
97
94
|
className ?: string;
|
|
98
95
|
construction ?: ConstructionMap[T];
|
|
99
96
|
type ?: T;
|
|
100
97
|
onHide ?: (values: any) => boolean;
|
|
101
|
-
watch ?: (ctx: WatchContext) => WatchAction | undefined;
|
|
102
98
|
}
|
|
103
99
|
|
|
104
100
|
export interface formSupervisionProps {
|
|
@@ -111,7 +107,9 @@ export interface formSupervisionProps {
|
|
|
111
107
|
footerControl ?: ({ loading }: { loading: boolean }) => ReactNode;
|
|
112
108
|
onSuccess ?: (data: any) => void;
|
|
113
109
|
onError ?: (code: number) => void;
|
|
110
|
+
successMessage ?: string;
|
|
114
111
|
className ?: string;
|
|
112
|
+
id ?: string;
|
|
115
113
|
}
|
|
116
114
|
|
|
117
115
|
|
|
@@ -127,135 +125,95 @@ export function FormSupervisionComponent({
|
|
|
127
125
|
footerControl,
|
|
128
126
|
payload,
|
|
129
127
|
className = "",
|
|
128
|
+
successMessage,
|
|
129
|
+
id,
|
|
130
130
|
}: formSupervisionProps) {
|
|
131
|
+
const l = useLang();
|
|
132
|
+
|
|
131
133
|
const [modal, setModal] = useState<boolean | "success" | "failed">(false);
|
|
132
134
|
const [fresh, setFresh] = useState<boolean>(true);
|
|
133
|
-
const [mapGroups, setMapGroups]
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
const [mapGroups, setMapGroups] = useState<Record<string, number[]>>({});
|
|
136
|
+
|
|
137
|
+
const [
|
|
138
|
+
{
|
|
139
|
+
formControl,
|
|
140
|
+
setRegister,
|
|
141
|
+
values,
|
|
142
|
+
setValues,
|
|
143
|
+
errors,
|
|
144
|
+
setErrors,
|
|
145
|
+
setDefaultValues,
|
|
146
|
+
submit,
|
|
147
|
+
loading,
|
|
148
|
+
confirm,
|
|
149
|
+
},
|
|
150
|
+
] = useForm(
|
|
151
|
+
submitControl,
|
|
139
152
|
payload,
|
|
140
153
|
confirmation,
|
|
141
|
-
|
|
154
|
+
(data: any) => {
|
|
142
155
|
onSuccess?.(data);
|
|
143
156
|
setModal("success");
|
|
157
|
+
setTimeout(() => setModal(false), 1000);
|
|
144
158
|
resetFresh();
|
|
145
159
|
},
|
|
146
|
-
|
|
160
|
+
(code: number) => {
|
|
147
161
|
onError?.(code);
|
|
148
162
|
if (code == 422) confirm.onClose();
|
|
149
163
|
else setModal("failed");
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
const resetFresh = () => {
|
|
154
|
-
setFresh(false);
|
|
155
|
-
setTimeout(() => setFresh(true), 300);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
resetFresh();
|
|
160
|
-
}, [fields]);
|
|
161
|
-
|
|
162
|
-
useEffect(() => {
|
|
163
|
-
if (defaultValue) setDefaultValues(defaultValue);
|
|
164
|
-
else {
|
|
165
|
-
setDefaultValues(null);
|
|
166
|
-
resetFresh();
|
|
167
|
-
}
|
|
168
|
-
}, [defaultValue]);
|
|
169
|
-
|
|
170
|
-
// ==============================>
|
|
171
|
-
// ## Watch: collect watchers from fields
|
|
172
|
-
// ==============================>
|
|
173
|
-
const collectWatchers = (fieldList: FormType[], prefix?: string): { name: string, watch: NonNullable<FormType['watch']>, construction: any }[] => {
|
|
174
|
-
const result: { name: string, watch: NonNullable<FormType['watch']>, construction: any }[] = [];
|
|
175
|
-
|
|
176
|
-
for (const f of fieldList) {
|
|
177
|
-
const inputType = f.type || "default";
|
|
178
|
-
const name = prefix ? `${prefix}.${f.construction?.name}` : f.construction?.name || "";
|
|
179
|
-
|
|
180
|
-
if (inputType === "cluster") {
|
|
181
|
-
const cluster = f.construction as ClusterConstruction;
|
|
182
|
-
const groupKey = prefix ? `${prefix}.${cluster.name}` : cluster.name;
|
|
183
|
-
const group = mapGroups[groupKey] || [0];
|
|
184
|
-
|
|
185
|
-
for (const gIndex of group) {
|
|
186
|
-
result.push(...collectWatchers(cluster.fields, `${cluster.name}[${gIndex}]`));
|
|
187
|
-
}
|
|
188
|
-
} else if (f.watch) {
|
|
189
|
-
result.push({ name, watch: f.watch, construction: f.construction });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return result;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// ==============================>
|
|
198
|
-
// ## Watch: execute watchers on value change
|
|
199
|
-
// ==============================>
|
|
200
|
-
useEffect(() => {
|
|
201
|
-
const watchers = collectWatchers(fields);
|
|
202
|
-
if (watchers.length === 0) {
|
|
203
|
-
if (Object.keys(watchRef.current).length > 0) {
|
|
204
|
-
watchRef.current = {};
|
|
205
|
-
setWatchState({});
|
|
206
|
-
}
|
|
207
|
-
return;
|
|
208
164
|
}
|
|
165
|
+
);
|
|
209
166
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const nextState : Record<string, WatchAction> = {};
|
|
213
|
-
const valueUpdates : FormValueType[] = [];
|
|
214
|
-
|
|
215
|
-
for (const { name, watch, construction } of watchers) {
|
|
216
|
-
const prev = watchRef.current[name] || {};
|
|
217
|
-
const action = watch({ values: valMap, self: name, prev });
|
|
218
|
-
|
|
219
|
-
if (!action) continue;
|
|
220
|
-
|
|
221
|
-
nextState[name] = action;
|
|
167
|
+
const GroupsFromDefaults = (defaults: Record<string, any>): Record<string, number[]> => {
|
|
168
|
+
const groups: Record<string, Set<number>> = {};
|
|
222
169
|
|
|
223
|
-
|
|
170
|
+
Object.keys(defaults).forEach((key) => {
|
|
171
|
+
const match = key.match(/^(.+?)\[(\d+)\]/);
|
|
172
|
+
if (!match) return;
|
|
224
173
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const newValidations = action.required ? (baseValidations.includes("required") ? baseValidations : [...baseValidations, "required"]) : baseValidations.filter((v: string) => v !== "required");
|
|
174
|
+
const [, groupKey, indexStr] = match;
|
|
175
|
+
const index = Number(indexStr);
|
|
228
176
|
|
|
229
|
-
|
|
177
|
+
if (!groups[groupKey]) {
|
|
178
|
+
groups[groupKey] = new Set();
|
|
230
179
|
}
|
|
231
180
|
|
|
232
|
-
|
|
233
|
-
|
|
181
|
+
groups[groupKey].add(index);
|
|
182
|
+
});
|
|
234
183
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
184
|
+
return Object.fromEntries(
|
|
185
|
+
Object.entries(groups).map(([key, indexSet]) => [
|
|
186
|
+
key,
|
|
187
|
+
Array.from(indexSet)
|
|
188
|
+
.sort((a, b) => a - b)
|
|
189
|
+
.map((_, i) => i),
|
|
190
|
+
])
|
|
191
|
+
);
|
|
192
|
+
};
|
|
240
193
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
194
|
+
const resetFresh = () => {
|
|
195
|
+
setFresh(false);
|
|
196
|
+
setTimeout(() => setFresh(true), 300);
|
|
197
|
+
};
|
|
245
198
|
|
|
246
|
-
|
|
247
|
-
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
resetFresh();
|
|
201
|
+
}, [fields]);
|
|
248
202
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
else merged.push(upd);
|
|
253
|
-
}
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (defaultValue) {
|
|
205
|
+
setDefaultValues(defaultValue);
|
|
254
206
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}, [values, fields, mapGroups]);
|
|
207
|
+
const derivedGroups = GroupsFromDefaults(defaultValue);
|
|
208
|
+
setMapGroups(derivedGroups);
|
|
258
209
|
|
|
210
|
+
resetFresh();
|
|
211
|
+
} else {
|
|
212
|
+
setDefaultValues(null);
|
|
213
|
+
setMapGroups({});
|
|
214
|
+
resetFresh();
|
|
215
|
+
}
|
|
216
|
+
}, [defaultValue]);
|
|
259
217
|
|
|
260
218
|
const generateColClass = (col: string | number) => String(col).split(" ").map((c) => (c.includes(":") ? `${c.replace(":", ":col-span-")}` : `col-span-${c}`)).join(" ");
|
|
261
219
|
|
|
@@ -282,61 +240,67 @@ export function FormSupervisionComponent({
|
|
|
282
240
|
|
|
283
241
|
if (form?.onHide?.(values)) return null;
|
|
284
242
|
|
|
285
|
-
const ws = watchState[name];
|
|
286
|
-
if (ws?.hidden) return null;
|
|
287
|
-
|
|
288
243
|
if (inputType === "cluster") {
|
|
289
|
-
const { name: mapName, fields: innerForms, label, tip, wrap, className
|
|
244
|
+
const { name: mapName, fields: innerForms, label, tip, wrap, className } = form.construction as ClusterConstruction;
|
|
290
245
|
|
|
291
246
|
const groupKey = prefix ? `${prefix}.${mapName}` : mapName;
|
|
292
|
-
const group = mapGroups[groupKey] ||
|
|
293
|
-
|
|
294
|
-
const addGroup = () => setMapGroups((prev) => ({ ...prev, [groupKey]: [...group, group.length
|
|
295
|
-
|
|
296
|
-
const removeGroup = (
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
247
|
+
const group = mapGroups[groupKey] || [0];
|
|
248
|
+
|
|
249
|
+
const addGroup = () => setMapGroups((prev) => ({ ...prev, [groupKey]: [...group, group.length] }));
|
|
250
|
+
|
|
251
|
+
const removeGroup = (index: number) => {
|
|
252
|
+
const filteredGroup = group.filter((_, i) => i !== index);
|
|
253
|
+
const newGroup = filteredGroup.map((_, i) => i);
|
|
254
|
+
|
|
255
|
+
setMapGroups((prev) => ({ ...prev, [groupKey]: newGroup }));
|
|
256
|
+
|
|
257
|
+
let updatedValues = values.filter((v) => {
|
|
258
|
+
const n = String(v?.name || "");
|
|
259
|
+
if (!n) return true;
|
|
260
|
+
if (n.startsWith(`${groupKey}[${index}]`) || n.startsWith(`${groupKey}.${index}.`)) return false;
|
|
261
|
+
return true;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const regex = new RegExp(`${groupKey}\\[(\\d+)\\]`, 'g');
|
|
265
|
+
updatedValues = updatedValues.map((v) => {
|
|
266
|
+
let name = v.name;
|
|
267
|
+
name = name.replace(regex, (match: string, oldIdx: string) => {
|
|
268
|
+
const oldIndex = parseInt(oldIdx, 10);
|
|
269
|
+
const newIndex = newGroup.indexOf(oldIndex);
|
|
270
|
+
return newIndex >= 0 ? `${groupKey}[${newIndex}]` : match;
|
|
271
|
+
});
|
|
272
|
+
return { ...v, name };
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
setValues(updatedValues);
|
|
300
276
|
};
|
|
301
277
|
|
|
302
278
|
return (
|
|
303
279
|
<div key={key} className={cn("flex flex-col gap-4", generateColClass(form.col || "12"))}>
|
|
304
280
|
{group.map((gIndex) => (
|
|
305
|
-
<div
|
|
306
|
-
key={gIndex}
|
|
307
|
-
className={cn(
|
|
308
|
-
"form-supervision-cluster-item",
|
|
309
|
-
wrap && "form-supervision-cluster-item-wrapped",
|
|
310
|
-
className
|
|
311
|
-
)}
|
|
312
|
-
>
|
|
281
|
+
<div key={gIndex} className={cn("relative pr-8", wrap && "p-4 rounded border", className)}>
|
|
313
282
|
{label && <p className="input-label">{label} {gIndex + 1}</p>}
|
|
314
|
-
{tip && <small className="input-tip">{tip}</small>}
|
|
283
|
+
{tip && <small className={cn("input-tip")}>{tip}</small>}
|
|
315
284
|
{(label || tip) && <div className="mb-2"></div>}
|
|
316
285
|
|
|
317
|
-
<div className="
|
|
286
|
+
<div className="w-full grid grid-cols-12 gap-4">
|
|
318
287
|
{innerForms.map((inner, i) => renderInput(inner, i, `${mapName}[${gIndex}]`))}
|
|
319
288
|
</div>
|
|
320
289
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
wrap && "form-supervision-cluster-remove-btn-wrapped"
|
|
330
|
-
)}
|
|
331
|
-
onClick={() => removeGroup(gIndex)}
|
|
332
|
-
/>
|
|
333
|
-
)}
|
|
290
|
+
<ButtonComponent
|
|
291
|
+
icon={"solid/times"}
|
|
292
|
+
paint="danger"
|
|
293
|
+
variant="outline"
|
|
294
|
+
size="xs"
|
|
295
|
+
className={cn("absolute top-10 right-2 translate-x-[50%] -translate-y-[50%]", wrap && "translate-x-0 -translate-y-0 top-1 right-1")}
|
|
296
|
+
onClick={() => removeGroup(gIndex)}
|
|
297
|
+
/>
|
|
334
298
|
</div>
|
|
335
299
|
))}
|
|
336
300
|
|
|
337
301
|
<div>
|
|
338
302
|
<ButtonComponent
|
|
339
|
-
icon={
|
|
303
|
+
icon={"solid/plus"}
|
|
340
304
|
label={`Tambah ${label || mapName}`}
|
|
341
305
|
variant="outline"
|
|
342
306
|
size="sm"
|
|
@@ -362,8 +326,7 @@ export function FormSupervisionComponent({
|
|
|
362
326
|
<Component
|
|
363
327
|
{...(form.construction as any)}
|
|
364
328
|
{...formControl(name)}
|
|
365
|
-
|
|
366
|
-
readOnly={ws?.readonly}
|
|
329
|
+
// autoFocus={key === 0}
|
|
367
330
|
/>
|
|
368
331
|
</div>
|
|
369
332
|
);
|
|
@@ -371,55 +334,71 @@ export function FormSupervisionComponent({
|
|
|
371
334
|
|
|
372
335
|
return (
|
|
373
336
|
<>
|
|
374
|
-
{title && <h4 className={cn("
|
|
375
|
-
|
|
376
|
-
<form className={cn("form-supervision-base", pcn<CT>(className, "base"))} onSubmit={submit}>
|
|
377
|
-
{fresh && fields.map((f, i) => renderInput(f, i))}
|
|
337
|
+
{title && <h4 className={cn("text-lg font-semibold mb-4", pcn<CT>(className, "title"))}>{title}</h4>}
|
|
378
338
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
icon={faSave}
|
|
386
|
-
loading={loading}
|
|
387
|
-
className={pcn<CT>(className, "submit")}
|
|
388
|
-
/>
|
|
389
|
-
</div>
|
|
390
|
-
)}
|
|
339
|
+
{modal == "success" ? (
|
|
340
|
+
<div className="flex flex-col items-center justify-center h-full py-6 transition-all duration-300 animate-intro-down">
|
|
341
|
+
<div className="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center">
|
|
342
|
+
<Icon icon={"solid/check"} className="text-primary text-2xl" />
|
|
343
|
+
</div>
|
|
344
|
+
<p className="text-primary text-lg font-semibold mt-4">{successMessage || "Berhasil disimpan!"}</p>
|
|
391
345
|
</div>
|
|
392
|
-
|
|
346
|
+
) : (
|
|
347
|
+
<form id={id} className={cn("flex flex-col h-full pb-8")} onSubmit={submit}>
|
|
348
|
+
<div className={cn("grid grid-cols-12 gap-4 flex-1 content-start", pcn<CT>(className, "base"))}>
|
|
349
|
+
{fresh && fields.map((f, i) => renderInput(f, i))}
|
|
350
|
+
|
|
351
|
+
{!footerControl && (
|
|
352
|
+
<div className="hidden md:block col-span-12">
|
|
353
|
+
<div className="flex justify-end mt-4">
|
|
354
|
+
<ButtonComponent
|
|
355
|
+
type="submit"
|
|
356
|
+
label={l.base?.save ? l.base.save() : "Save"}
|
|
357
|
+
icon={"solid/save"}
|
|
358
|
+
loading={loading}
|
|
359
|
+
className={pcn<CT>(className, "submit")}
|
|
360
|
+
/>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
)}
|
|
364
|
+
|
|
365
|
+
{!footerControl && (
|
|
366
|
+
<div className={"md:hidden col-span-12 mt-4"}>
|
|
367
|
+
<ButtonComponent
|
|
368
|
+
label={l.base?.save ? l.base.save() : "Save"}
|
|
369
|
+
icon={"solid/save"}
|
|
370
|
+
type="submit"
|
|
371
|
+
loading={loading}
|
|
372
|
+
block
|
|
373
|
+
className={pcn<CT>(className, "submit")}
|
|
374
|
+
/>
|
|
375
|
+
</div>
|
|
376
|
+
)}
|
|
377
|
+
|
|
378
|
+
{footerControl && (
|
|
379
|
+
<div className="col-span-12">{footerControl?.({ loading })}</div>
|
|
380
|
+
)}
|
|
381
|
+
|
|
382
|
+
{modal == "failed" && (
|
|
383
|
+
<div className="col-span-12 mt-4 w-full p-4 rounded-sm border border-danger bg-light-danger flex gap-4 items-center">
|
|
384
|
+
<div>
|
|
385
|
+
<div className="w-10 h-10 rounded-full bg-danger/20 flex items-center justify-center">
|
|
386
|
+
<Icon icon={"solid/exclamation-triangle"} className="text-danger text-lg" />
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
<p className="text-danger text-sm font-semibold">{"Terjadi Masalah, Coba ulangi lagi!"}</p>
|
|
390
|
+
</div>
|
|
391
|
+
)}
|
|
392
|
+
</div>
|
|
393
|
+
</form>
|
|
394
|
+
)}
|
|
393
395
|
|
|
394
396
|
<ModalConfirmComponent
|
|
395
397
|
show={confirm.show}
|
|
396
398
|
onClose={() => confirm.onClose()}
|
|
397
|
-
|
|
398
|
-
title="Yakin"
|
|
399
|
+
title={l.base?.confirmTitle ? l.base.confirmTitle() : "Yakin"}
|
|
399
400
|
submitControl={{ onSubmit: () => confirm?.onConfirm(), paint: "primary" }}
|
|
400
|
-
|
|
401
|
-
<p className="form-supervision-confirm-text">Yakin semua data sudah benar?</p>
|
|
402
|
-
</ModalConfirmComponent>
|
|
403
|
-
|
|
404
|
-
<ToastComponent
|
|
405
|
-
show={modal == "failed"}
|
|
406
|
-
onClose={() => setModal(false)}
|
|
407
|
-
title="Gagal"
|
|
408
|
-
className="form-supervision-toast-error header::text-danger"
|
|
409
|
-
>
|
|
410
|
-
<p className="form-supervision-toast-text">
|
|
411
|
-
Data gagal disimpan, cek data dan koneksi internet lalu coba kembali!
|
|
412
|
-
</p>
|
|
413
|
-
</ToastComponent>
|
|
414
|
-
|
|
415
|
-
<ToastComponent
|
|
416
|
-
show={modal == "success"}
|
|
417
|
-
onClose={() => setModal(false)}
|
|
418
|
-
title="Berhasil"
|
|
419
|
-
className="form-supervision-toast-success header::text-success"
|
|
420
|
-
>
|
|
421
|
-
<p className="form-supervision-toast-text">Data berhasil disimpan!</p>
|
|
422
|
-
</ToastComponent>
|
|
401
|
+
/>
|
|
423
402
|
</>
|
|
424
403
|
);
|
|
425
404
|
}
|