@zauru-sdk/components 2.0.46 → 2.0.47
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/CHANGELOG.md +8 -0
- package/dist/Alerts/ComponentError/index.d.ts +4 -0
- package/dist/Alerts/index.d.ts +1 -0
- package/dist/DynamicTable/GenericDynamicTable.d.ts +2 -0
- package/dist/Layouts/errorLayout/index.d.ts +2 -1
- package/dist/SidePanel/index.d.ts +2 -2
- package/dist/esm/Alerts/ComponentError/index.js +6 -0
- package/dist/esm/Alerts/index.js +1 -0
- package/dist/esm/DynamicTable/GenericDynamicTable.js +183 -173
- package/dist/esm/Form/SelectField/index.js +7 -17
- package/dist/esm/Layouts/errorLayout/index.js +7 -3
- package/dist/esm/SidePanel/index.js +1 -2
- package/package.json +3 -3
- package/src/Alerts/ComponentError/index.tsx +48 -0
- package/src/Alerts/index.ts +1 -0
- package/src/DynamicTable/GenericDynamicTable.tsx +388 -368
- package/src/Form/SelectField/index.tsx +7 -18
- package/src/Layouts/errorLayout/index.tsx +28 -3
- package/src/SidePanel/index.tsx +1 -3
|
@@ -14,10 +14,12 @@ import { LoadingInputSkeleton } from "../Skeletons/index.js";
|
|
|
14
14
|
import { WithTooltip } from "../WithTooltip/index.js";
|
|
15
15
|
import { TrashSvg } from "@zauru-sdk/icons";
|
|
16
16
|
import { useFormContext } from "react-hook-form";
|
|
17
|
+
import { ComponentError } from "../Alerts/index.js";
|
|
17
18
|
|
|
18
19
|
export type FooterColumnConfig = {
|
|
19
20
|
content: React.ReactNode;
|
|
20
21
|
className?: string;
|
|
22
|
+
name?: string;
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
type Props = {
|
|
@@ -65,6 +67,7 @@ const GenericDynamicTableErrorComponent = ({ name }: { name: string }) => {
|
|
|
65
67
|
name="invoice_details"
|
|
66
68
|
withoutBg
|
|
67
69
|
editable={!show}
|
|
70
|
+
searcheables={[{ value: "id_number", label: "No. Contraseña" }]}
|
|
68
71
|
defaultValue={
|
|
69
72
|
invoiceDetailsDefaultValue ?? [{ id: crypto.randomUUID() }]
|
|
70
73
|
}
|
|
@@ -105,7 +108,6 @@ const GenericDynamicTableErrorComponent = ({ name }: { name: string }) => {
|
|
|
105
108
|
maxRows={2}
|
|
106
109
|
/>
|
|
107
110
|
*/
|
|
108
|
-
|
|
109
111
|
export const GenericDynamicTable = (props: Props) => {
|
|
110
112
|
const {
|
|
111
113
|
columns,
|
|
@@ -127,412 +129,430 @@ export const GenericDynamicTable = (props: Props) => {
|
|
|
127
129
|
maxRows,
|
|
128
130
|
} = props;
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
try {
|
|
133
|
+
const [tableData, setTableData] = useState<RowDataType[]>(defaultValue);
|
|
134
|
+
const [deletedData, setDeletedData] = useState<RowDataType[]>([]);
|
|
135
|
+
const [search, setSearch] = useState("");
|
|
136
|
+
const [filteredTableData, setFilteredTableData] =
|
|
137
|
+
useState<RowDataType[]>(tableData);
|
|
138
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
139
|
+
const [itemsPerPage, setItemsPerPage] = useState(defaultItemsPerPage);
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (defaultValue.length) {
|
|
143
|
+
setTableData(defaultValue);
|
|
144
|
+
}
|
|
145
|
+
}, []);
|
|
143
146
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
setFilteredTableData(tableData);
|
|
149
|
+
}, [tableData]);
|
|
147
150
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
changeFilteredData();
|
|
153
|
+
}, [tableData, search]);
|
|
151
154
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
const totalPages = () => {
|
|
156
|
+
return Math.ceil(filteredTableData.length / itemsPerPage);
|
|
157
|
+
};
|
|
155
158
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
159
|
+
const addRow = () => {
|
|
160
|
+
if (maxRows && tableData.length >= maxRows) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const defs: { [key: string]: any } = {};
|
|
164
|
+
columns.forEach((x) => {
|
|
165
|
+
defs[`${x.name}`] =
|
|
166
|
+
x.type == "label" || x.type == "textField"
|
|
167
|
+
? ""
|
|
168
|
+
: x.type == "selectField"
|
|
169
|
+
? 0
|
|
170
|
+
: x.type == "checkbox"
|
|
171
|
+
? false
|
|
172
|
+
: 0;
|
|
173
|
+
});
|
|
174
|
+
setTableData((prevData) => [
|
|
175
|
+
...prevData,
|
|
176
|
+
{ id: generateClientUUID(), ...defs },
|
|
177
|
+
]);
|
|
178
|
+
};
|
|
176
179
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
const removeRow = (rowId: string) => {
|
|
181
|
+
const newDeletedData = [...deletedData];
|
|
182
|
+
const deletedItem = tableData?.find((x) => x.id === rowId);
|
|
183
|
+
if (deletedItem && !isNaN(deletedItem.id)) {
|
|
184
|
+
newDeletedData.push(deletedItem);
|
|
185
|
+
}
|
|
186
|
+
setDeletedData(newDeletedData);
|
|
187
|
+
setTableData((prevData) => prevData?.filter((x) => x.id !== rowId));
|
|
188
|
+
};
|
|
186
189
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
const handleChange = (name: string, value: any, rowId: string) => {
|
|
191
|
+
setTableData((prevData) => {
|
|
192
|
+
const updatedData = prevData.map((row) => {
|
|
193
|
+
if (row.id === rowId) {
|
|
194
|
+
return { ...row, [name]: value };
|
|
195
|
+
}
|
|
196
|
+
return row;
|
|
197
|
+
});
|
|
198
|
+
onChange && onChange(updatedData);
|
|
199
|
+
return updatedData;
|
|
194
200
|
});
|
|
195
|
-
|
|
196
|
-
return updatedData;
|
|
197
|
-
});
|
|
198
|
-
};
|
|
201
|
+
};
|
|
199
202
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
203
|
+
const renderHeader = () => {
|
|
204
|
+
if (orientation === "horizontal") {
|
|
205
|
+
return (
|
|
206
|
+
<tr style={{ ...thCSSProperties }}>
|
|
207
|
+
{columns.map((column, index) => {
|
|
208
|
+
const ancho =
|
|
209
|
+
column.width ?? (editable ? 94 : 100) / (columns.length ?? 1);
|
|
210
|
+
return (
|
|
211
|
+
<th
|
|
212
|
+
key={index}
|
|
213
|
+
className={`text-left align-middle p-2 ${thElementsClassName} ${
|
|
214
|
+
column.headerClassName || ""
|
|
215
|
+
}`}
|
|
216
|
+
style={{ width: `${ancho}%` }}
|
|
217
|
+
>
|
|
218
|
+
{column.label}
|
|
219
|
+
</th>
|
|
220
|
+
);
|
|
221
|
+
})}
|
|
222
|
+
{editable && <th style={{ width: "4%" }}></th>}
|
|
223
|
+
</tr>
|
|
224
|
+
);
|
|
225
|
+
} else {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
226
229
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
{editable && renderDeleteButton(rowData)}
|
|
236
|
-
</tr>
|
|
237
|
-
);
|
|
238
|
-
} else {
|
|
239
|
-
return columns.map((column) => (
|
|
240
|
-
<tr
|
|
241
|
-
key={`${rowData.id}-${column.name}`}
|
|
242
|
-
className={index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : ""}
|
|
243
|
-
>
|
|
244
|
-
<th
|
|
245
|
-
className={`text-left align-middle p-2 ${thElementsClassName} ${
|
|
246
|
-
column.headerClassName || ""
|
|
247
|
-
}`}
|
|
230
|
+
const renderRow = (rowData: RowDataType, index: number) => {
|
|
231
|
+
if (orientation === "horizontal") {
|
|
232
|
+
return (
|
|
233
|
+
<tr
|
|
234
|
+
key={rowData.id}
|
|
235
|
+
className={
|
|
236
|
+
index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : ""
|
|
237
|
+
}
|
|
248
238
|
>
|
|
249
|
-
{column
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
239
|
+
{columns.map((column) => renderCell(rowData, column))}
|
|
240
|
+
{editable && renderDeleteButton(rowData)}
|
|
241
|
+
</tr>
|
|
242
|
+
);
|
|
243
|
+
} else {
|
|
244
|
+
return columns.map((column) => (
|
|
245
|
+
<tr
|
|
246
|
+
key={`${rowData.id}-${column.name}`}
|
|
247
|
+
className={
|
|
248
|
+
index % 2 === 0 ? `${withoutBg ? "" : "bg-gray-200"}` : ""
|
|
249
|
+
}
|
|
250
|
+
>
|
|
251
|
+
<th
|
|
252
|
+
className={`text-left align-middle p-2 ${thElementsClassName} ${
|
|
253
|
+
column.headerClassName || ""
|
|
254
|
+
}`}
|
|
255
|
+
>
|
|
256
|
+
{column.label}
|
|
257
|
+
</th>
|
|
258
|
+
{renderCell(rowData, column)}
|
|
259
|
+
{editable &&
|
|
260
|
+
column === columns[columns.length - 1] &&
|
|
261
|
+
renderDeleteButton(rowData)}
|
|
262
|
+
</tr>
|
|
263
|
+
));
|
|
264
|
+
}
|
|
265
|
+
};
|
|
259
266
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
267
|
+
const renderCell = (
|
|
268
|
+
rowData: RowDataType,
|
|
269
|
+
column: GenericDynamicTableColumn
|
|
270
|
+
) => {
|
|
271
|
+
if (loading) {
|
|
272
|
+
return (
|
|
273
|
+
<td
|
|
274
|
+
key={`${rowData.id}-${column.name}`}
|
|
275
|
+
className={`align-middle p-1 ${column.cellClassName || ""}`}
|
|
276
|
+
>
|
|
277
|
+
<LoadingInputSkeleton />
|
|
278
|
+
</td>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
const tempVal = rowData[column.name as any];
|
|
282
|
+
|
|
283
|
+
const defaultVal =
|
|
284
|
+
column.type === "selectField"
|
|
285
|
+
? column.options?.find((x) => x.value === tempVal)
|
|
286
|
+
: tempVal;
|
|
287
|
+
|
|
288
|
+
if (column.type === "label") {
|
|
289
|
+
return (
|
|
290
|
+
<td
|
|
291
|
+
key={`${rowData.id}-${column.name}`}
|
|
292
|
+
className={`align-middle p-1 ${column.cellClassName || ""}`}
|
|
293
|
+
>
|
|
294
|
+
<div>{defaultVal}</div>
|
|
295
|
+
</td>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const FieldComponent =
|
|
300
|
+
column.type === "textField"
|
|
301
|
+
? TextField
|
|
302
|
+
: column.type === "checkbox"
|
|
303
|
+
? CheckBox
|
|
304
|
+
: SelectField;
|
|
275
305
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
: tempVal;
|
|
306
|
+
const setTableValue = (columnName: string, newValue: any) => {
|
|
307
|
+
handleChange(columnName, newValue, rowData.id);
|
|
308
|
+
};
|
|
280
309
|
|
|
281
|
-
if (column.type === "label") {
|
|
282
310
|
return (
|
|
283
311
|
<td
|
|
284
312
|
key={`${rowData.id}-${column.name}`}
|
|
285
313
|
className={`align-middle p-1 ${column.cellClassName || ""}`}
|
|
286
314
|
>
|
|
287
|
-
|
|
315
|
+
{column.loadingOptions ? (
|
|
316
|
+
<LoadingInputSkeleton />
|
|
317
|
+
) : (
|
|
318
|
+
<FieldComponent
|
|
319
|
+
key={`${rowData.id}-${column.name}`}
|
|
320
|
+
name={`${rowData.id}-${column.name}`}
|
|
321
|
+
type={column.textFieldType}
|
|
322
|
+
integer={!!column.integer}
|
|
323
|
+
disabled={column.disabled}
|
|
324
|
+
isClearable
|
|
325
|
+
onChange={(value: any) => {
|
|
326
|
+
const sendValue = value?.value ?? value;
|
|
327
|
+
handleChange(column.name, sendValue, rowData.id);
|
|
328
|
+
column.onChange &&
|
|
329
|
+
column.onChange(rowData, sendValue, setTableValue);
|
|
330
|
+
}}
|
|
331
|
+
defaultValue={defaultVal}
|
|
332
|
+
options={column.options ?? []}
|
|
333
|
+
/>
|
|
334
|
+
)}
|
|
288
335
|
</td>
|
|
289
336
|
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const FieldComponent =
|
|
293
|
-
column.type === "textField"
|
|
294
|
-
? TextField
|
|
295
|
-
: column.type === "checkbox"
|
|
296
|
-
? CheckBox
|
|
297
|
-
: SelectField;
|
|
298
|
-
|
|
299
|
-
const setTableValue = (columnName: string, newValue: any) => {
|
|
300
|
-
handleChange(columnName, newValue, rowData.id);
|
|
301
337
|
};
|
|
302
338
|
|
|
303
|
-
|
|
304
|
-
<td
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
column.onChange(rowData, sendValue, setTableValue);
|
|
339
|
+
const renderDeleteButton = (rowData: RowDataType) => (
|
|
340
|
+
<td className="align-middle w-16">
|
|
341
|
+
<WithTooltip text="Eliminar">
|
|
342
|
+
<button
|
|
343
|
+
className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
|
|
344
|
+
onClick={(
|
|
345
|
+
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
346
|
+
) => {
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
event.stopPropagation();
|
|
349
|
+
createModal({
|
|
350
|
+
title: "¿Está seguro que quiere eliminar este registro?",
|
|
351
|
+
description:
|
|
352
|
+
"Una vez eliminada la información no podrá ser recuperada.",
|
|
353
|
+
}).then((response) => {
|
|
354
|
+
if (response === "OK") {
|
|
355
|
+
removeRow(rowData.id);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
323
358
|
}}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
359
|
+
type="button"
|
|
360
|
+
>
|
|
361
|
+
<TrashSvg />
|
|
362
|
+
</button>
|
|
363
|
+
</WithTooltip>
|
|
328
364
|
</td>
|
|
329
365
|
);
|
|
330
|
-
};
|
|
331
366
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
338
|
-
event.preventDefault();
|
|
339
|
-
event.stopPropagation();
|
|
340
|
-
createModal({
|
|
341
|
-
title: "¿Está seguro que quiere eliminar este registro?",
|
|
342
|
-
description:
|
|
343
|
-
"Una vez eliminada la información no podrá ser recuperada.",
|
|
344
|
-
}).then((response) => {
|
|
345
|
-
if (response === "OK") {
|
|
346
|
-
removeRow(rowData.id);
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
}}
|
|
350
|
-
type="button"
|
|
351
|
-
>
|
|
352
|
-
<TrashSvg />
|
|
353
|
-
</button>
|
|
354
|
-
</WithTooltip>
|
|
355
|
-
</td>
|
|
356
|
-
);
|
|
357
|
-
|
|
358
|
-
const renderRows = () => {
|
|
359
|
-
let mapeable = filteredTableData.slice(
|
|
360
|
-
(currentPage - 1) * itemsPerPage,
|
|
361
|
-
currentPage * itemsPerPage
|
|
362
|
-
);
|
|
367
|
+
const renderRows = () => {
|
|
368
|
+
let mapeable = filteredTableData.slice(
|
|
369
|
+
(currentPage - 1) * itemsPerPage,
|
|
370
|
+
currentPage * itemsPerPage
|
|
371
|
+
);
|
|
363
372
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
373
|
+
if (loading) {
|
|
374
|
+
mapeable = [
|
|
375
|
+
{ id: 1 },
|
|
376
|
+
{ id: 2 },
|
|
377
|
+
{ id: 3 },
|
|
378
|
+
{ id: 4 },
|
|
379
|
+
{ id: 5 },
|
|
380
|
+
{ id: 6 },
|
|
381
|
+
{ id: 7 },
|
|
382
|
+
{ id: 8 },
|
|
383
|
+
{ id: 9 },
|
|
384
|
+
{ id: 10 },
|
|
385
|
+
] as RowDataType[];
|
|
386
|
+
}
|
|
378
387
|
|
|
379
|
-
|
|
380
|
-
|
|
388
|
+
return mapeable.map((rowData, index) => renderRow(rowData, index));
|
|
389
|
+
};
|
|
381
390
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
391
|
+
const handleChangeSearch = (newSearch: string) => {
|
|
392
|
+
setSearch(newSearch);
|
|
393
|
+
};
|
|
385
394
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
395
|
+
const changeFilteredData = () => {
|
|
396
|
+
if (search) {
|
|
397
|
+
const filteredData = tableData.filter((rowData) => {
|
|
398
|
+
for (const searchable of searcheables) {
|
|
399
|
+
const column = columns.find((col) => col.name === searchable.value);
|
|
400
|
+
if (column) {
|
|
401
|
+
const tempVal = rowData[column.name as any];
|
|
402
|
+
const defaultVal =
|
|
403
|
+
column.type === "selectField"
|
|
404
|
+
? column.options?.find((x) => x.value === tempVal)?.label
|
|
405
|
+
: tempVal;
|
|
406
|
+
if (
|
|
407
|
+
defaultVal
|
|
408
|
+
?.toString()
|
|
409
|
+
.toLowerCase()
|
|
410
|
+
.includes(search.toLowerCase())
|
|
411
|
+
) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
404
414
|
}
|
|
405
415
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
};
|
|
416
|
+
return false;
|
|
417
|
+
});
|
|
418
|
+
setFilteredTableData(filteredData);
|
|
419
|
+
} else {
|
|
420
|
+
setFilteredTableData(tableData);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
414
423
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
/>
|
|
432
|
-
</>
|
|
433
|
-
)}
|
|
434
|
-
<div className={`${className}`}>
|
|
435
|
-
{searcheables.length > 0 && (
|
|
436
|
-
<div>
|
|
437
|
-
<TextField
|
|
438
|
-
className="mb-2"
|
|
439
|
-
name="search"
|
|
440
|
-
title={`Buscar por: ${searcheables
|
|
441
|
-
.map((x) => x.label)
|
|
442
|
-
.join(", ")}`}
|
|
443
|
-
onChange={handleChangeSearch}
|
|
444
|
-
disabled={loading}
|
|
424
|
+
return (
|
|
425
|
+
<>
|
|
426
|
+
{name && (
|
|
427
|
+
<>
|
|
428
|
+
<GenericDynamicTableErrorComponent name={name} />
|
|
429
|
+
<input
|
|
430
|
+
name={name}
|
|
431
|
+
type="hidden"
|
|
432
|
+
value={JSON.stringify(tableData)}
|
|
433
|
+
hidden
|
|
434
|
+
/>
|
|
435
|
+
<input
|
|
436
|
+
name={`deleted_${name}`}
|
|
437
|
+
type="hidden"
|
|
438
|
+
value={JSON.stringify(deletedData)}
|
|
439
|
+
hidden
|
|
445
440
|
/>
|
|
446
|
-
|
|
441
|
+
</>
|
|
447
442
|
)}
|
|
448
|
-
<
|
|
449
|
-
{
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
<button
|
|
462
|
-
className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
|
|
463
|
-
onClick={(
|
|
464
|
-
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
465
|
-
) => {
|
|
466
|
-
event.preventDefault();
|
|
467
|
-
event.stopPropagation();
|
|
468
|
-
addRow();
|
|
469
|
-
}}
|
|
470
|
-
type="button"
|
|
471
|
-
>
|
|
472
|
-
+
|
|
473
|
-
</button>
|
|
474
|
-
)}
|
|
475
|
-
</td>
|
|
476
|
-
</tr>
|
|
477
|
-
</tfoot>
|
|
443
|
+
<div className={`${className}`}>
|
|
444
|
+
{searcheables.length > 0 && (
|
|
445
|
+
<div>
|
|
446
|
+
<TextField
|
|
447
|
+
className="mb-2"
|
|
448
|
+
name="search"
|
|
449
|
+
title={`Buscar por: ${searcheables
|
|
450
|
+
.map((x) => x.label)
|
|
451
|
+
.join(", ")}`}
|
|
452
|
+
onChange={handleChangeSearch}
|
|
453
|
+
disabled={loading}
|
|
454
|
+
/>
|
|
455
|
+
</div>
|
|
478
456
|
)}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
457
|
+
<table className="w-full">
|
|
458
|
+
{orientation === "horizontal" && <thead>{renderHeader()}</thead>}
|
|
459
|
+
<tbody>{renderRows()}</tbody>
|
|
460
|
+
{editable && (
|
|
461
|
+
<tfoot>
|
|
462
|
+
<tr>
|
|
483
463
|
<td
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
464
|
+
colSpan={
|
|
465
|
+
orientation === "horizontal" ? columns.length + 1 : 2
|
|
466
|
+
}
|
|
467
|
+
className="align-middle"
|
|
487
468
|
>
|
|
488
|
-
{
|
|
469
|
+
{(!maxRows || tableData.length < maxRows) && (
|
|
470
|
+
<button
|
|
471
|
+
className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
|
|
472
|
+
onClick={(
|
|
473
|
+
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
|
474
|
+
) => {
|
|
475
|
+
event.preventDefault();
|
|
476
|
+
event.stopPropagation();
|
|
477
|
+
addRow();
|
|
478
|
+
}}
|
|
479
|
+
type="button"
|
|
480
|
+
>
|
|
481
|
+
+
|
|
482
|
+
</button>
|
|
483
|
+
)}
|
|
489
484
|
</td>
|
|
490
|
-
|
|
491
|
-
</
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
>
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
<div>
|
|
519
|
-
<
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
485
|
+
</tr>
|
|
486
|
+
</tfoot>
|
|
487
|
+
)}
|
|
488
|
+
{footerRow && (
|
|
489
|
+
<tfoot className="border-t-2 border-black">
|
|
490
|
+
<tr>
|
|
491
|
+
{columns.map((column, index) => {
|
|
492
|
+
const footerCell = footerRow.find(
|
|
493
|
+
(fc) => fc.name === column.name
|
|
494
|
+
);
|
|
495
|
+
return (
|
|
496
|
+
<td
|
|
497
|
+
key={index}
|
|
498
|
+
colSpan={orientation === "vertical" ? 2 : 1}
|
|
499
|
+
className={`align-middle ${
|
|
500
|
+
footerCell?.className || ""
|
|
501
|
+
}`}
|
|
502
|
+
>
|
|
503
|
+
{footerCell ? footerCell.content : <></>}
|
|
504
|
+
</td>
|
|
505
|
+
);
|
|
506
|
+
})}
|
|
507
|
+
{editable && <td></td>}
|
|
508
|
+
</tr>
|
|
509
|
+
</tfoot>
|
|
510
|
+
)}
|
|
511
|
+
</table>
|
|
512
|
+
{paginated && totalPages() > 1 && (
|
|
513
|
+
<div className="flex justify-between items-center mt-4">
|
|
514
|
+
<div className="flex items-center">
|
|
515
|
+
<Button
|
|
516
|
+
type="button"
|
|
517
|
+
disabled={currentPage === 1}
|
|
518
|
+
onClickSave={() =>
|
|
519
|
+
setCurrentPage((old) => Math.max(old - 1, 1))
|
|
520
|
+
}
|
|
521
|
+
>
|
|
522
|
+
Anterior
|
|
523
|
+
</Button>
|
|
524
|
+
<span className="mx-2">{`Página ${currentPage} de ${totalPages()}`}</span>
|
|
525
|
+
<Button
|
|
526
|
+
type="button"
|
|
527
|
+
disabled={currentPage === totalPages()}
|
|
528
|
+
onClickSave={() =>
|
|
529
|
+
setCurrentPage((old) => Math.min(old + 1, totalPages()))
|
|
530
|
+
}
|
|
531
|
+
>
|
|
532
|
+
Siguiente
|
|
533
|
+
</Button>
|
|
534
|
+
</div>
|
|
535
|
+
<div>
|
|
536
|
+
<select
|
|
537
|
+
value={itemsPerPage}
|
|
538
|
+
onChange={(e) => {
|
|
539
|
+
setItemsPerPage(Number(e.target.value));
|
|
540
|
+
setCurrentPage(1); // resetear la página al cambiar los elementos por página
|
|
541
|
+
}}
|
|
542
|
+
>
|
|
543
|
+
{itemsPerPageOptions.map((option) => (
|
|
544
|
+
<option key={option} value={option}>
|
|
545
|
+
{option} elementos por página
|
|
546
|
+
</option>
|
|
547
|
+
))}
|
|
548
|
+
</select>
|
|
549
|
+
</div>
|
|
532
550
|
</div>
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
)
|
|
551
|
+
)}
|
|
552
|
+
</div>
|
|
553
|
+
</>
|
|
554
|
+
);
|
|
555
|
+
} catch (error: any) {
|
|
556
|
+
return <ComponentError error={error} componentName="GenericDynamicTable" />;
|
|
557
|
+
}
|
|
538
558
|
};
|