@zauru-sdk/components 1.0.12 → 1.0.14
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 +16 -0
- package/dist/Alerts/index.d.ts +0 -1
- package/dist/Alerts/index.js +0 -1
- package/dist/Chat/ChatLayout.d.ts +2 -2
- package/dist/Chat/ChatLayout.js +4 -3
- package/dist/Chat/ChatMessageHistory.js +1 -1
- package/dist/ConnectionState/ConnectionState.d.ts +2 -0
- package/dist/ConnectionState/ConnectionState.js +22 -0
- package/dist/ConnectionState/index.d.ts +1 -0
- package/dist/ConnectionState/index.js +1 -0
- package/dist/DynamicTable/BasicPrintDynamicTable.d.ts +10 -0
- package/dist/DynamicTable/BasicPrintDynamicTable.js +27 -0
- package/dist/DynamicTable/DynamicPrintTable.d.ts +23 -0
- package/dist/DynamicTable/DynamicPrintTable.js +132 -0
- package/dist/DynamicTable/GenericDynamicTable.d.ts +21 -0
- package/dist/DynamicTable/GenericDynamicTable.js +195 -0
- package/dist/DynamicTable/index.d.ts +24 -0
- package/dist/DynamicTable/index.js +193 -0
- package/dist/Footer/Footer.js +2 -2
- package/dist/Form/Checkbox/index.d.ts +17 -0
- package/dist/Form/Checkbox/index.js +34 -0
- package/dist/Form/Checklist/index.d.ts +14 -0
- package/dist/Form/Checklist/index.js +10 -0
- package/dist/Form/DatePicker/index.d.ts +18 -0
- package/dist/Form/DatePicker/index.js +31 -0
- package/dist/Form/DynamicBaculoForm/index.d.ts +18 -0
- package/dist/Form/DynamicBaculoForm/index.js +138 -0
- package/dist/Form/FieldContainer/DoubleFieldContainer.d.ts +8 -0
- package/dist/Form/FieldContainer/DoubleFieldContainer.js +14 -0
- package/dist/Form/FieldContainer/QuadrupleFieldContainer.d.ts +7 -0
- package/dist/Form/FieldContainer/QuadrupleFieldContainer.js +14 -0
- package/dist/Form/FieldContainer/TripleFieldContainer.d.ts +7 -0
- package/dist/Form/FieldContainer/TripleFieldContainer.js +14 -0
- package/dist/Form/FieldContainer/index.d.ts +3 -0
- package/dist/Form/FieldContainer/index.js +3 -0
- package/dist/Form/FileUpload/index.d.ts +21 -0
- package/dist/Form/FileUpload/index.js +54 -0
- package/dist/Form/FormButtons/index.d.ts +16 -0
- package/dist/Form/FormButtons/index.js +5 -0
- package/dist/Form/FormLayout/index.d.ts +11 -0
- package/dist/Form/FormLayout/index.js +7 -0
- package/dist/Form/SelectField/index.d.ts +27 -0
- package/dist/Form/SelectField/index.js +74 -0
- package/dist/Form/TextArea/index.d.ts +23 -0
- package/dist/Form/TextArea/index.js +36 -0
- package/dist/Form/TextField/index.d.ts +25 -0
- package/dist/Form/TextField/index.js +70 -0
- package/dist/Form/TimePicker/index.d.ts +16 -0
- package/dist/Form/TimePicker/index.js +31 -0
- package/dist/Form/YesNo/index.d.ts +12 -0
- package/dist/Form/YesNo/index.js +19 -0
- package/dist/Form/index.d.ts +13 -0
- package/dist/Form/index.js +13 -0
- package/dist/NavBar/NavBar.js +2 -2
- package/dist/Table/ZauruTable.js +1 -1
- package/dist/Zendesk/Chat.d.ts +2 -2
- package/dist/Zendesk/Chat.js +2 -1
- package/dist/Zendesk/zendesk.config.d.ts +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -2
- package/package.json +9 -8
- package/src/Alerts/index.ts +0 -1
- package/src/Chat/ChatLayout.tsx +133 -0
- package/src/Chat/ChatMessageHistory.tsx +142 -0
- package/src/Chat/index.ts +2 -0
- package/src/ConnectionState/ConnectionState.tsx +29 -0
- package/src/ConnectionState/index.tsx +1 -0
- package/src/DynamicTable/BasicPrintDynamicTable.tsx +73 -0
- package/src/DynamicTable/DynamicPrintTable.tsx +290 -0
- package/src/DynamicTable/GenericDynamicTable.tsx +455 -0
- package/src/DynamicTable/index.tsx +407 -0
- package/src/Footer/Footer.tsx +3 -3
- package/src/Form/Checkbox/index.tsx +96 -0
- package/src/Form/Checklist/index.tsx +35 -0
- package/src/Form/DatePicker/index.tsx +132 -0
- package/src/Form/DynamicBaculoForm/index.tsx +359 -0
- package/src/Form/FieldContainer/DoubleFieldContainer.tsx +35 -0
- package/src/Form/FieldContainer/QuadrupleFieldContainer.tsx +36 -0
- package/src/Form/FieldContainer/TripleFieldContainer.tsx +35 -0
- package/src/Form/FieldContainer/index.ts +3 -0
- package/src/Form/FileUpload/index.tsx +184 -0
- package/src/Form/FormButtons/index.tsx +78 -0
- package/src/Form/FormLayout/index.tsx +37 -0
- package/src/Form/SelectField/index.tsx +237 -0
- package/src/Form/TextArea/index.tsx +125 -0
- package/src/Form/TextField/index.tsx +194 -0
- package/src/Form/TimePicker/index.tsx +127 -0
- package/src/Form/YesNo/index.tsx +79 -0
- package/src/Form/index.ts +13 -0
- package/src/NavBar/NavBar.tsx +2 -2
- package/src/Table/ZauruTable.tsx +1 -1
- package/src/Zendesk/Chat.tsx +85 -0
- package/src/Zendesk/index.ts +2 -0
- package/src/Zendesk/zendesk.config.ts +40 -0
- package/src/index.ts +4 -2
- package/dist/Alerts/Alert.d.ts +0 -9
- package/dist/Alerts/Alert.js +0 -97
- package/dist/Icons/Icons.d.ts +0 -47
- package/dist/Icons/Icons.js +0 -110
- package/dist/Icons/StylesConstants.d.ts +0 -26
- package/dist/Icons/StylesConstants.js +0 -34
- package/src/Alerts/Alert.tsx +0 -149
- package/src/Icons/Icons.tsx +0 -782
- package/src/Icons/StylesConstants.tsx +0 -66
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { TextAreaWithoutValidation } from "../Form/TextArea";
|
|
3
|
+
import { TextFieldWithoutValidation } from "../Form/TextField";
|
|
4
|
+
import { CheckboxWithoutValidation } from "../Form/Checkbox";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
cellInputs?: boolean;
|
|
8
|
+
intersectionTitle?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
onChange?: (data: string) => void;
|
|
11
|
+
defaultValue?: string;
|
|
12
|
+
onValidate?: (headerValue: string, rowValue: string) => boolean;
|
|
13
|
+
onRemove?: () => void;
|
|
14
|
+
margins?: {
|
|
15
|
+
marginLeft?: number;
|
|
16
|
+
marginTop?: number;
|
|
17
|
+
verticalGap?: number;
|
|
18
|
+
horizontalGap?: number;
|
|
19
|
+
};
|
|
20
|
+
forwardedRef?: React.RefObject<{
|
|
21
|
+
getTotalForRows: () => number;
|
|
22
|
+
getTotalForColumns: () => number;
|
|
23
|
+
getColumnsCount: () => number;
|
|
24
|
+
getRowsCount: () => number;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const DynamicTable = (
|
|
29
|
+
{ forwardedRef, ...props }: Props,
|
|
30
|
+
ref: React.ForwardedRef<any>
|
|
31
|
+
) => {
|
|
32
|
+
const [tableData, setTableData] = useState<Record<string, any>>({});
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
cellInputs,
|
|
36
|
+
intersectionTitle,
|
|
37
|
+
className,
|
|
38
|
+
onChange,
|
|
39
|
+
defaultValue,
|
|
40
|
+
margins,
|
|
41
|
+
} = props;
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (onChange) {
|
|
45
|
+
onChange(JSON.stringify(tableData));
|
|
46
|
+
}
|
|
47
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
48
|
+
}, [tableData]);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (defaultValue) {
|
|
52
|
+
initializeTable(defaultValue);
|
|
53
|
+
} else {
|
|
54
|
+
initializeTableWithDefaults();
|
|
55
|
+
}
|
|
56
|
+
}, [defaultValue]);
|
|
57
|
+
|
|
58
|
+
const getRows = () => {
|
|
59
|
+
const rowsIds = Object.keys(tableData)
|
|
60
|
+
.filter((key) => key.startsWith("row"))
|
|
61
|
+
.map((key) => parseInt(key.slice(3)));
|
|
62
|
+
return rowsIds.sort().map((id) => ({ id }));
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const getCols = () => {
|
|
66
|
+
const colsIds = Object.keys(tableData)
|
|
67
|
+
.filter((key) => key.startsWith("column"))
|
|
68
|
+
.map((key) => parseInt(key.slice(6)));
|
|
69
|
+
return colsIds.sort().map((id) => ({ id }));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const addRow = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
const rows = getRows();
|
|
76
|
+
const lastId = rows[rows.length - 1].id;
|
|
77
|
+
handleInputChange(`row${lastId + 1}`, 1);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const addCol = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
|
81
|
+
event.stopPropagation();
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
const cols = getCols();
|
|
84
|
+
const lastId = cols[cols.length - 1].id;
|
|
85
|
+
handleInputChange(`column${lastId + 1}`, 1);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const removeRow = (rowId: number) => {
|
|
89
|
+
const newRowData = { ...tableData };
|
|
90
|
+
for (const key in newRowData) {
|
|
91
|
+
if (key.startsWith(`row${rowId}`) || key.startsWith(`cell-${rowId}-`)) {
|
|
92
|
+
delete newRowData[key];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
setTableData(newRowData);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const removeCol = (colId: number) => {
|
|
99
|
+
const newRowData = { ...tableData };
|
|
100
|
+
for (const key in newRowData) {
|
|
101
|
+
if (key.startsWith(`column${colId}`) || key.endsWith(`-${colId}`)) {
|
|
102
|
+
delete newRowData[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
setTableData(newRowData);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getTotalForRow = (rowId: number) => {
|
|
109
|
+
return Number(tableData[`row${rowId}`] ?? 0) ?? 0;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const getTotalForColumn = (colId: number) => {
|
|
113
|
+
return Number(tableData[`column${colId}`] ?? 0) ?? 0;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const getTotalForRows = (): number => {
|
|
117
|
+
return getRows()
|
|
118
|
+
.map((row) => getTotalForRow(row.id))
|
|
119
|
+
.reduce((a, b) => a + b, 0);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const getTotalForColumns = (): number => {
|
|
123
|
+
return getCols()
|
|
124
|
+
.map((col) => getTotalForColumn(col.id))
|
|
125
|
+
.reduce((a, b) => a + b, 0);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const getRowsCount = (): number => {
|
|
129
|
+
return getRows().length;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const getColumnsCount = (): number => {
|
|
133
|
+
return getCols().length;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleInputChange = (name: string, value: any) => {
|
|
137
|
+
setTableData((prevData) => ({ ...prevData, [name]: value }));
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const handleValidation = (
|
|
141
|
+
cellId: string,
|
|
142
|
+
colId: number,
|
|
143
|
+
rowId: number
|
|
144
|
+
): { stopUIChange: boolean } | void => {
|
|
145
|
+
const headerValue = tableData[`column${colId}`];
|
|
146
|
+
const rowValue = tableData[`row${rowId}`];
|
|
147
|
+
|
|
148
|
+
if (props.onValidate && props.onValidate(headerValue, rowValue)) {
|
|
149
|
+
return handleInputChange(cellId, true);
|
|
150
|
+
}
|
|
151
|
+
return { stopUIChange: true };
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleRemoveValidation = (cellId: string) => {
|
|
155
|
+
handleInputChange(cellId, false);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const initializeTableWithDefaults = () => {
|
|
159
|
+
const initialData = { row0: 1, column0: 1 };
|
|
160
|
+
setTableData(initialData);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const initializeTable = (tableJson: string) => {
|
|
164
|
+
try {
|
|
165
|
+
const initialData = JSON.parse(tableJson);
|
|
166
|
+
setTableData(initialData);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error("Error al inicializar la tabla:", error);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const cellBordered = {
|
|
173
|
+
border: "1px solid #ccc",
|
|
174
|
+
} as React.CSSProperties;
|
|
175
|
+
|
|
176
|
+
const pastelGrayBackground = {
|
|
177
|
+
backgroundColor: "#B69E99",
|
|
178
|
+
} as React.CSSProperties;
|
|
179
|
+
|
|
180
|
+
const cellCenteredContent = {
|
|
181
|
+
textAlign: "center",
|
|
182
|
+
verticalAlign: "middle",
|
|
183
|
+
} as React.CSSProperties;
|
|
184
|
+
|
|
185
|
+
const renderTotalHeight = () => {
|
|
186
|
+
const sumaFilas = getRows()
|
|
187
|
+
.map((row) => getTotalForRow(row.id))
|
|
188
|
+
.reduce((a, b) => a + b, 0);
|
|
189
|
+
|
|
190
|
+
const sumTotalFilas =
|
|
191
|
+
sumaFilas +
|
|
192
|
+
(margins?.marginTop ?? 0) +
|
|
193
|
+
(getRows().length - 1) * (margins?.verticalGap ?? 0);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div className="ml-4 inline-block">
|
|
197
|
+
<strong>Total alto: {sumTotalFilas} </strong>
|
|
198
|
+
{margins && (
|
|
199
|
+
<>
|
|
200
|
+
(Celdas: {sumaFilas} + Márgen superior: {margins?.marginTop ?? 0} +{" "}
|
|
201
|
+
{getRows().length - 1} Brechas verticales:{" "}
|
|
202
|
+
{Math.round((getRows().length - 1) * (margins?.verticalGap ?? 0))})
|
|
203
|
+
</>
|
|
204
|
+
)}
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const renderTotalWidth = () => {
|
|
210
|
+
const cols = getCols();
|
|
211
|
+
const sumaColumnas = cols
|
|
212
|
+
.map((col) => getTotalForColumn(col.id))
|
|
213
|
+
.reduce((a, b) => a + b, 0);
|
|
214
|
+
const sumaTotal =
|
|
215
|
+
sumaColumnas +
|
|
216
|
+
(margins?.marginLeft ?? 0) +
|
|
217
|
+
(getCols().length - 1) * (margins?.horizontalGap ?? 0);
|
|
218
|
+
return (
|
|
219
|
+
<div className="ml-4 inline-block">
|
|
220
|
+
<strong>Total ancho: {sumaTotal} </strong>
|
|
221
|
+
{margins && (
|
|
222
|
+
<>
|
|
223
|
+
(Celdas: {sumaColumnas} + Márgen izquierdo:{" "}
|
|
224
|
+
{margins?.marginLeft ?? 0} + {getCols().length - 1} Brechas
|
|
225
|
+
horizontales:{" "}
|
|
226
|
+
{Math.round((getCols().length - 1) * (margins?.horizontalGap ?? 0))}
|
|
227
|
+
)
|
|
228
|
+
</>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const renderHeader = () => {
|
|
235
|
+
const cols = getCols();
|
|
236
|
+
return (
|
|
237
|
+
<tr>
|
|
238
|
+
<th
|
|
239
|
+
className="align-middle py-2 text-center"
|
|
240
|
+
style={{
|
|
241
|
+
...cellBordered,
|
|
242
|
+
...pastelGrayBackground,
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{intersectionTitle ?? ""}
|
|
246
|
+
</th>
|
|
247
|
+
{cols.map((col) => (
|
|
248
|
+
<th
|
|
249
|
+
key={col.id}
|
|
250
|
+
className="align-middle py-2 text-center"
|
|
251
|
+
style={{ ...cellBordered, ...pastelGrayBackground }}
|
|
252
|
+
>
|
|
253
|
+
<div className="inline-flex">
|
|
254
|
+
<TextFieldWithoutValidation
|
|
255
|
+
style={{ maxWidth: "45%", minWidth: "45%" }}
|
|
256
|
+
name={`column${col.id}`}
|
|
257
|
+
defaultValue={tableData[`column${col.id}`] || 1}
|
|
258
|
+
type="number"
|
|
259
|
+
onChange={(value) =>
|
|
260
|
+
handleInputChange(`column${col.id}`, value)
|
|
261
|
+
}
|
|
262
|
+
/>
|
|
263
|
+
{col.id > 0 && (
|
|
264
|
+
<button
|
|
265
|
+
className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
|
|
266
|
+
onClick={() => removeCol(col.id)}
|
|
267
|
+
>
|
|
268
|
+
x
|
|
269
|
+
</button>
|
|
270
|
+
)}
|
|
271
|
+
</div>
|
|
272
|
+
</th>
|
|
273
|
+
))}
|
|
274
|
+
<th>
|
|
275
|
+
<button
|
|
276
|
+
className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
|
|
277
|
+
onClick={addCol}
|
|
278
|
+
>
|
|
279
|
+
+
|
|
280
|
+
</button>
|
|
281
|
+
</th>
|
|
282
|
+
</tr>
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const renderRow = (rowId: number) => {
|
|
287
|
+
const cols = getCols();
|
|
288
|
+
return (
|
|
289
|
+
<tr key={rowId}>
|
|
290
|
+
<td
|
|
291
|
+
className="align-middle"
|
|
292
|
+
style={{
|
|
293
|
+
...cellBordered,
|
|
294
|
+
...pastelGrayBackground,
|
|
295
|
+
textOverflow: "ellipsis",
|
|
296
|
+
msTextOverflow: "ellipsis",
|
|
297
|
+
maxWidth: "200px",
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
<div className="inline-flex">
|
|
301
|
+
<TextFieldWithoutValidation
|
|
302
|
+
style={{ maxWidth: "45%", minWidth: "45%" }}
|
|
303
|
+
name={`row${rowId}`}
|
|
304
|
+
defaultValue={tableData[`row${rowId}`] || 1}
|
|
305
|
+
type="number"
|
|
306
|
+
onChange={(value) => handleInputChange(`row${rowId}`, value)}
|
|
307
|
+
/>
|
|
308
|
+
{rowId > 0 && (
|
|
309
|
+
<button
|
|
310
|
+
className="bg-red-500 hover:bg-red-600 font-bold py-1 px-2 rounded ml-2"
|
|
311
|
+
onClick={() => {
|
|
312
|
+
removeRow(rowId);
|
|
313
|
+
}}
|
|
314
|
+
>
|
|
315
|
+
x
|
|
316
|
+
</button>
|
|
317
|
+
)}
|
|
318
|
+
</div>
|
|
319
|
+
</td>
|
|
320
|
+
{cols.map((col) => {
|
|
321
|
+
const cellId = `cell-${rowId}-${col.id}`;
|
|
322
|
+
const cellValidation = tableData[cellId] === true;
|
|
323
|
+
if (!cellInputs) tableData[cellId] = cellValidation;
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<td
|
|
327
|
+
key={col.id}
|
|
328
|
+
id={cellId}
|
|
329
|
+
style={{ ...cellBordered, ...cellCenteredContent }}
|
|
330
|
+
>
|
|
331
|
+
{cellInputs ? (
|
|
332
|
+
<TextAreaWithoutValidation
|
|
333
|
+
name={cellId}
|
|
334
|
+
defaultValue={tableData[cellId] || ""}
|
|
335
|
+
onChange={(value) => handleInputChange(cellId, value)}
|
|
336
|
+
/>
|
|
337
|
+
) : (
|
|
338
|
+
<CheckboxWithoutValidation
|
|
339
|
+
name={cellId}
|
|
340
|
+
defaultValue={cellValidation}
|
|
341
|
+
onChange={(value) => {
|
|
342
|
+
if (value) {
|
|
343
|
+
return handleValidation(cellId, col.id, rowId);
|
|
344
|
+
} else {
|
|
345
|
+
handleRemoveValidation(cellId);
|
|
346
|
+
}
|
|
347
|
+
}}
|
|
348
|
+
/>
|
|
349
|
+
)}
|
|
350
|
+
</td>
|
|
351
|
+
);
|
|
352
|
+
})}
|
|
353
|
+
{rowId === 0 && (
|
|
354
|
+
<td rowSpan={getRows().length} style={{ maxWidth: "100px" }}>
|
|
355
|
+
{renderTotalHeight()}
|
|
356
|
+
</td>
|
|
357
|
+
)}
|
|
358
|
+
</tr>
|
|
359
|
+
);
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const renderRows = () => {
|
|
363
|
+
const rows = getRows();
|
|
364
|
+
return rows.map((row) => renderRow(row.id));
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Use el "useImperativeHandle" para que el componente padre pueda acceder a los métodos deseados
|
|
368
|
+
React.useImperativeHandle(forwardedRef, () => ({
|
|
369
|
+
getTotalForRows,
|
|
370
|
+
getTotalForColumns,
|
|
371
|
+
getColumnsCount,
|
|
372
|
+
getRowsCount,
|
|
373
|
+
}));
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
<div className={`${className}`}>
|
|
377
|
+
<table className="border-collapse">
|
|
378
|
+
<thead>{renderHeader()}</thead>
|
|
379
|
+
<tbody>{renderRows()}</tbody>
|
|
380
|
+
<tfoot>
|
|
381
|
+
<tr>
|
|
382
|
+
<td>
|
|
383
|
+
<button
|
|
384
|
+
className="bg-blue-500 hover:bg-blue-600 font-bold py-2 px-4 rounded"
|
|
385
|
+
onClick={addRow}
|
|
386
|
+
>
|
|
387
|
+
+
|
|
388
|
+
</button>
|
|
389
|
+
</td>
|
|
390
|
+
<td
|
|
391
|
+
colSpan={getCols().length + 1}
|
|
392
|
+
className="text-left align-middle"
|
|
393
|
+
style={{
|
|
394
|
+
textOverflow: "ellipsis",
|
|
395
|
+
msTextOverflow: "ellipsis",
|
|
396
|
+
}}
|
|
397
|
+
>
|
|
398
|
+
{renderTotalWidth()}
|
|
399
|
+
</td>
|
|
400
|
+
</tr>
|
|
401
|
+
</tfoot>
|
|
402
|
+
</table>
|
|
403
|
+
</div>
|
|
404
|
+
);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
export default React.forwardRef(DynamicTable);
|
package/src/Footer/Footer.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from "react";
|
|
2
|
-
//import ConnectionState from "../ConnectionState";
|
|
3
2
|
import { LoadingInputSkeleton } from "src";
|
|
3
|
+
import ConnectionState from "src/ConnectionState/ConnectionState";
|
|
4
4
|
|
|
5
5
|
type FooterProps = {
|
|
6
6
|
href: string;
|
|
@@ -50,11 +50,11 @@ export const Footer = ({
|
|
|
50
50
|
{`Creado en `} <a href={href}>Zauru</a>{" "}
|
|
51
51
|
{`con ❤️ ${new Date().getFullYear()} v.3.2`}
|
|
52
52
|
</p>
|
|
53
|
-
{
|
|
53
|
+
{showConnection && (
|
|
54
54
|
<div className="ml-5">
|
|
55
55
|
<ConnectionState />
|
|
56
56
|
</div>
|
|
57
|
-
)}
|
|
57
|
+
)}
|
|
58
58
|
</div>
|
|
59
59
|
</footer>
|
|
60
60
|
);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { useAppSelector } from "@zauru-sdk/redux";
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
id?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
formName?: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
defaultValue?: boolean;
|
|
10
|
+
onChange?: (
|
|
11
|
+
value: boolean,
|
|
12
|
+
event: React.ChangeEvent<HTMLInputElement>
|
|
13
|
+
) => { stopUIChange: boolean } | void;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
error?: string | undefined;
|
|
16
|
+
borderColor?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const CheckboxWithoutValidation = (props: Props) => {
|
|
20
|
+
const {
|
|
21
|
+
id,
|
|
22
|
+
name,
|
|
23
|
+
defaultValue = false,
|
|
24
|
+
onChange,
|
|
25
|
+
disabled = false,
|
|
26
|
+
error,
|
|
27
|
+
label,
|
|
28
|
+
} = props;
|
|
29
|
+
|
|
30
|
+
const [checked, setChecked] = useState(defaultValue);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
setChecked(defaultValue);
|
|
34
|
+
}, [defaultValue]);
|
|
35
|
+
|
|
36
|
+
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
37
|
+
const isChecked = event.target.checked;
|
|
38
|
+
if (onChange) {
|
|
39
|
+
const result = onChange(isChecked, event);
|
|
40
|
+
if (result?.stopUIChange) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
setChecked(isChecked);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const color = error ? "red" : "gray";
|
|
48
|
+
const borderColor = disabled ? "border-gray-300" : `border-${color}-500`;
|
|
49
|
+
|
|
50
|
+
const inputComponent = (
|
|
51
|
+
<input
|
|
52
|
+
type="checkbox"
|
|
53
|
+
id={id ?? name}
|
|
54
|
+
name={name}
|
|
55
|
+
checked={checked}
|
|
56
|
+
onChange={handleInputChange}
|
|
57
|
+
className={`form-checkbox h-4 w-4 text-indigo-600 ${borderColor} focus:border-indigo-500 focus:ring-indigo-500`}
|
|
58
|
+
disabled={disabled}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (!error && !label) {
|
|
63
|
+
return inputComponent;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className="col-span-6 sm:col-span-3">
|
|
68
|
+
<div className={`flex items-center ${borderColor}`}>
|
|
69
|
+
{inputComponent}
|
|
70
|
+
{label && (
|
|
71
|
+
<label
|
|
72
|
+
htmlFor={id ?? name}
|
|
73
|
+
className={`ml-2 block text-sm font-medium text-${color}-700 dark:text-${color}-500`}
|
|
74
|
+
>
|
|
75
|
+
{label}
|
|
76
|
+
</label>
|
|
77
|
+
)}
|
|
78
|
+
</div>
|
|
79
|
+
{error && (
|
|
80
|
+
<p className={`mt-2 text-sm text-${color}-600 dark:text-${color}-500`}>
|
|
81
|
+
<span className="font-medium">Oops!</span> {error}
|
|
82
|
+
</p>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
//<reference> https://tailwindui.com/components/application-ui/forms/form-layouts
|
|
89
|
+
export const CheckBox = (props: Props) => {
|
|
90
|
+
const { formValidations } = useAppSelector((state) => state.formValidation);
|
|
91
|
+
const error = formValidations[props.formName ?? "-1"]?.[props.name ?? "-1"];
|
|
92
|
+
|
|
93
|
+
props = { ...props, error };
|
|
94
|
+
|
|
95
|
+
return <CheckboxWithoutValidation {...props} />;
|
|
96
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CheckboxWithoutValidation } from "../Checkbox";
|
|
3
|
+
|
|
4
|
+
export type ChecklistItem = {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
label: string;
|
|
8
|
+
defaultValue?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type ChecklistProps = {
|
|
13
|
+
items: ChecklistItem[];
|
|
14
|
+
onChange?: (name: string, value: boolean) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const Checklist: React.FC<ChecklistProps> = ({ items, onChange }) => {
|
|
18
|
+
const handleCheckboxChange = (name: string, value: boolean) => {
|
|
19
|
+
if (onChange) {
|
|
20
|
+
onChange(name, value);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div>
|
|
26
|
+
{items.map((item) => (
|
|
27
|
+
<CheckboxWithoutValidation
|
|
28
|
+
key={item.id}
|
|
29
|
+
{...item}
|
|
30
|
+
onChange={(value) => handleCheckboxChange(item.name, value)}
|
|
31
|
+
/>
|
|
32
|
+
))}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { CalendarIconSVG, CloseSvgIcon, IdeaIconSVG } from "@zauru-sdk/icons";
|
|
3
|
+
import { useAppSelector } from "@zauru-sdk/redux";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
id?: string;
|
|
7
|
+
name: string;
|
|
8
|
+
formName?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
hint?: string;
|
|
11
|
+
helpText?: string;
|
|
12
|
+
defaultValue?: string;
|
|
13
|
+
onChange?: (value: string) => void;
|
|
14
|
+
isClearable?: boolean;
|
|
15
|
+
tabIndex?: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const FormDatePickerWithoutValidation = (props: Props) => {
|
|
22
|
+
const {
|
|
23
|
+
id,
|
|
24
|
+
name,
|
|
25
|
+
title,
|
|
26
|
+
defaultValue = "",
|
|
27
|
+
hint,
|
|
28
|
+
helpText,
|
|
29
|
+
onChange,
|
|
30
|
+
tabIndex,
|
|
31
|
+
error,
|
|
32
|
+
disabled = false,
|
|
33
|
+
className = "",
|
|
34
|
+
isClearable = false,
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
const [value, setValue] = useState<string | null>(defaultValue);
|
|
38
|
+
const [showTooltip, setShowTooltip] = useState<boolean>(false);
|
|
39
|
+
|
|
40
|
+
const color = error ? "red" : "gray";
|
|
41
|
+
|
|
42
|
+
const isReadOnly = disabled;
|
|
43
|
+
const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
|
|
44
|
+
const textColor = isReadOnly ? "text-gray-500" : `text-${color}-500`;
|
|
45
|
+
const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
setValue(defaultValue);
|
|
49
|
+
}, [defaultValue]);
|
|
50
|
+
|
|
51
|
+
const clearValue = () => {
|
|
52
|
+
setValue("");
|
|
53
|
+
onChange && onChange("");
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
{title && (
|
|
59
|
+
<label
|
|
60
|
+
htmlFor={error ? `${name}-error` : `${name}-success`}
|
|
61
|
+
className={`block text-sm font-medium ${textColor} ${className}`}
|
|
62
|
+
>
|
|
63
|
+
{title}
|
|
64
|
+
</label>
|
|
65
|
+
)}
|
|
66
|
+
<div className="flex relative items-center">
|
|
67
|
+
<div className="absolute left-0 flex items-center pl-3 pointer-events-none">
|
|
68
|
+
<CalendarIconSVG />
|
|
69
|
+
</div>
|
|
70
|
+
<input
|
|
71
|
+
id={id}
|
|
72
|
+
name={name}
|
|
73
|
+
tabIndex={tabIndex}
|
|
74
|
+
type="date"
|
|
75
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
76
|
+
setValue(e.target.value);
|
|
77
|
+
onChange && onChange(e.target.value);
|
|
78
|
+
}}
|
|
79
|
+
value={value ?? ""}
|
|
80
|
+
pattern="\d{4}-\d{2}-\d{2}"
|
|
81
|
+
className={`${bgColor} ${borderColor} ${textColor} text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5`}
|
|
82
|
+
></input>
|
|
83
|
+
{value && isClearable && (
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
onClick={clearValue}
|
|
87
|
+
className="absolute right-0 mr-10"
|
|
88
|
+
>
|
|
89
|
+
<CloseSvgIcon />
|
|
90
|
+
</button>
|
|
91
|
+
)}
|
|
92
|
+
{helpText && (
|
|
93
|
+
<div className="flex items-center relative ml-3">
|
|
94
|
+
<div
|
|
95
|
+
className="relative cursor-pointer"
|
|
96
|
+
onMouseEnter={() => setShowTooltip(true)}
|
|
97
|
+
onMouseLeave={() => setShowTooltip(false)}
|
|
98
|
+
>
|
|
99
|
+
<IdeaIconSVG />
|
|
100
|
+
{showTooltip && (
|
|
101
|
+
<div className="absolute -left-48 top-0 mt-8 p-2 bg-white border rounded shadow text-black">
|
|
102
|
+
{helpText}
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
{error && (
|
|
110
|
+
<p className={`mt-2 text-sm text-${color}-600 dark:text-${color}-500`}>
|
|
111
|
+
<span className="font-medium">Oops!</span> {error}
|
|
112
|
+
</p>
|
|
113
|
+
)}
|
|
114
|
+
{!error && hint && (
|
|
115
|
+
<p
|
|
116
|
+
className={`mt-2 italic text-sm text-${color}-500 dark:text-${color}-400`}
|
|
117
|
+
>
|
|
118
|
+
{hint}
|
|
119
|
+
</p>
|
|
120
|
+
)}
|
|
121
|
+
</>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const FormDatePicker = (props: Props) => {
|
|
126
|
+
const { formValidations } = useAppSelector((state) => state.formValidation);
|
|
127
|
+
const error = formValidations[props.formName ?? "-1"]?.[props.name ?? "-1"];
|
|
128
|
+
|
|
129
|
+
props = { ...props, error };
|
|
130
|
+
|
|
131
|
+
return <FormDatePickerWithoutValidation {...props} />;
|
|
132
|
+
};
|