@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.
Files changed (104) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/Alerts/index.d.ts +0 -1
  3. package/dist/Alerts/index.js +0 -1
  4. package/dist/Chat/ChatLayout.d.ts +2 -2
  5. package/dist/Chat/ChatLayout.js +4 -3
  6. package/dist/Chat/ChatMessageHistory.js +1 -1
  7. package/dist/ConnectionState/ConnectionState.d.ts +2 -0
  8. package/dist/ConnectionState/ConnectionState.js +22 -0
  9. package/dist/ConnectionState/index.d.ts +1 -0
  10. package/dist/ConnectionState/index.js +1 -0
  11. package/dist/DynamicTable/BasicPrintDynamicTable.d.ts +10 -0
  12. package/dist/DynamicTable/BasicPrintDynamicTable.js +27 -0
  13. package/dist/DynamicTable/DynamicPrintTable.d.ts +23 -0
  14. package/dist/DynamicTable/DynamicPrintTable.js +132 -0
  15. package/dist/DynamicTable/GenericDynamicTable.d.ts +21 -0
  16. package/dist/DynamicTable/GenericDynamicTable.js +195 -0
  17. package/dist/DynamicTable/index.d.ts +24 -0
  18. package/dist/DynamicTable/index.js +193 -0
  19. package/dist/Footer/Footer.js +2 -2
  20. package/dist/Form/Checkbox/index.d.ts +17 -0
  21. package/dist/Form/Checkbox/index.js +34 -0
  22. package/dist/Form/Checklist/index.d.ts +14 -0
  23. package/dist/Form/Checklist/index.js +10 -0
  24. package/dist/Form/DatePicker/index.d.ts +18 -0
  25. package/dist/Form/DatePicker/index.js +31 -0
  26. package/dist/Form/DynamicBaculoForm/index.d.ts +18 -0
  27. package/dist/Form/DynamicBaculoForm/index.js +138 -0
  28. package/dist/Form/FieldContainer/DoubleFieldContainer.d.ts +8 -0
  29. package/dist/Form/FieldContainer/DoubleFieldContainer.js +14 -0
  30. package/dist/Form/FieldContainer/QuadrupleFieldContainer.d.ts +7 -0
  31. package/dist/Form/FieldContainer/QuadrupleFieldContainer.js +14 -0
  32. package/dist/Form/FieldContainer/TripleFieldContainer.d.ts +7 -0
  33. package/dist/Form/FieldContainer/TripleFieldContainer.js +14 -0
  34. package/dist/Form/FieldContainer/index.d.ts +3 -0
  35. package/dist/Form/FieldContainer/index.js +3 -0
  36. package/dist/Form/FileUpload/index.d.ts +21 -0
  37. package/dist/Form/FileUpload/index.js +54 -0
  38. package/dist/Form/FormButtons/index.d.ts +16 -0
  39. package/dist/Form/FormButtons/index.js +5 -0
  40. package/dist/Form/FormLayout/index.d.ts +11 -0
  41. package/dist/Form/FormLayout/index.js +7 -0
  42. package/dist/Form/SelectField/index.d.ts +27 -0
  43. package/dist/Form/SelectField/index.js +74 -0
  44. package/dist/Form/TextArea/index.d.ts +23 -0
  45. package/dist/Form/TextArea/index.js +36 -0
  46. package/dist/Form/TextField/index.d.ts +25 -0
  47. package/dist/Form/TextField/index.js +70 -0
  48. package/dist/Form/TimePicker/index.d.ts +16 -0
  49. package/dist/Form/TimePicker/index.js +31 -0
  50. package/dist/Form/YesNo/index.d.ts +12 -0
  51. package/dist/Form/YesNo/index.js +19 -0
  52. package/dist/Form/index.d.ts +13 -0
  53. package/dist/Form/index.js +13 -0
  54. package/dist/NavBar/NavBar.js +2 -2
  55. package/dist/Table/ZauruTable.js +1 -1
  56. package/dist/Zendesk/Chat.d.ts +2 -2
  57. package/dist/Zendesk/Chat.js +2 -1
  58. package/dist/Zendesk/zendesk.config.d.ts +1 -1
  59. package/dist/index.d.ts +4 -0
  60. package/dist/index.js +4 -2
  61. package/package.json +9 -8
  62. package/src/Alerts/index.ts +0 -1
  63. package/src/Chat/ChatLayout.tsx +133 -0
  64. package/src/Chat/ChatMessageHistory.tsx +142 -0
  65. package/src/Chat/index.ts +2 -0
  66. package/src/ConnectionState/ConnectionState.tsx +29 -0
  67. package/src/ConnectionState/index.tsx +1 -0
  68. package/src/DynamicTable/BasicPrintDynamicTable.tsx +73 -0
  69. package/src/DynamicTable/DynamicPrintTable.tsx +290 -0
  70. package/src/DynamicTable/GenericDynamicTable.tsx +455 -0
  71. package/src/DynamicTable/index.tsx +407 -0
  72. package/src/Footer/Footer.tsx +3 -3
  73. package/src/Form/Checkbox/index.tsx +96 -0
  74. package/src/Form/Checklist/index.tsx +35 -0
  75. package/src/Form/DatePicker/index.tsx +132 -0
  76. package/src/Form/DynamicBaculoForm/index.tsx +359 -0
  77. package/src/Form/FieldContainer/DoubleFieldContainer.tsx +35 -0
  78. package/src/Form/FieldContainer/QuadrupleFieldContainer.tsx +36 -0
  79. package/src/Form/FieldContainer/TripleFieldContainer.tsx +35 -0
  80. package/src/Form/FieldContainer/index.ts +3 -0
  81. package/src/Form/FileUpload/index.tsx +184 -0
  82. package/src/Form/FormButtons/index.tsx +78 -0
  83. package/src/Form/FormLayout/index.tsx +37 -0
  84. package/src/Form/SelectField/index.tsx +237 -0
  85. package/src/Form/TextArea/index.tsx +125 -0
  86. package/src/Form/TextField/index.tsx +194 -0
  87. package/src/Form/TimePicker/index.tsx +127 -0
  88. package/src/Form/YesNo/index.tsx +79 -0
  89. package/src/Form/index.ts +13 -0
  90. package/src/NavBar/NavBar.tsx +2 -2
  91. package/src/Table/ZauruTable.tsx +1 -1
  92. package/src/Zendesk/Chat.tsx +85 -0
  93. package/src/Zendesk/index.ts +2 -0
  94. package/src/Zendesk/zendesk.config.ts +40 -0
  95. package/src/index.ts +4 -2
  96. package/dist/Alerts/Alert.d.ts +0 -9
  97. package/dist/Alerts/Alert.js +0 -97
  98. package/dist/Icons/Icons.d.ts +0 -47
  99. package/dist/Icons/Icons.js +0 -110
  100. package/dist/Icons/StylesConstants.d.ts +0 -26
  101. package/dist/Icons/StylesConstants.js +0 -34
  102. package/src/Alerts/Alert.tsx +0 -149
  103. package/src/Icons/Icons.tsx +0 -782
  104. package/src/Icons/StylesConstants.tsx +0 -66
@@ -0,0 +1,359 @@
1
+ import { TextField, TextFieldWithoutValidation } from "../TextField";
2
+ import { TripleFieldContainer } from "../FieldContainer/TripleFieldContainer";
3
+ import { DoubleFieldContainer } from "../FieldContainer/DoubleFieldContainer";
4
+ import YesNo from "../YesNo";
5
+ import { TextArea } from "../TextArea";
6
+ import { SelectField } from "../SelectField";
7
+ import { FileUploadField } from "../FileUpload";
8
+ import { FormDatePicker } from "../DatePicker";
9
+ import { FormTimePicker } from "../TimePicker";
10
+ import {
11
+ FormFieldGraphQL,
12
+ FormGraphQL,
13
+ FormSubmissionValueGraphQL,
14
+ GenericDynamicTableColumn,
15
+ SelectFieldOption,
16
+ } from "@zauru-sdk/types";
17
+ import { LineSeparator, StaticAlert, SubContainer } from "src";
18
+ import { GenericDynamicTable } from "src/DynamicTable/GenericDynamicTable";
19
+ import { getDepSelectOptions, getMunSelectOptions } from "@zauru-sdk/common";
20
+
21
+ type Props = {
22
+ formName?: string;
23
+ form?: FormGraphQL;
24
+ options?: { showTitle: boolean; showDescription: boolean };
25
+ defaultValues?: FormSubmissionValueGraphQL[];
26
+ namesStr?: string;
27
+ showingRules?: { name: string; show: boolean }[];
28
+ readOnly?: boolean;
29
+ };
30
+
31
+ export function DynamicBaculoForm(props: Props) {
32
+ const {
33
+ form,
34
+ options = { showDescription: false, showTitle: false },
35
+ formName = "",
36
+ namesStr = "",
37
+ defaultValues = [],
38
+ showingRules = [],
39
+ readOnly = false,
40
+ } = props;
41
+
42
+ if (!form) {
43
+ return (
44
+ <StaticAlert
45
+ title="No se encontró el formulario dinámico"
46
+ description={`Ocurrió un error encontrando el formulario para ${formName}, contacte al administrador con este mensaje de error.`}
47
+ type="info"
48
+ />
49
+ );
50
+ }
51
+
52
+ const renderFieldComponent = (field: Partial<FormFieldGraphQL>) => {
53
+ const defaultValue = defaultValues?.find(
54
+ (x) => x.settings_form_field.print_var_name === field.print_var_name
55
+ );
56
+ switch (field.field_type) {
57
+ case "fixed_rows_table":
58
+ case "fixed_columns_table": {
59
+ const columns: GenericDynamicTableColumn[] =
60
+ field.settings_form_field_table_headers?.map((x) => {
61
+ return {
62
+ label: x.name,
63
+ name: `${namesStr}${x.id}_${field.id}`,
64
+ type: x.cell_type === "yes_no" ? "checkbox" : "textField",
65
+ } as GenericDynamicTableColumn;
66
+ }) ?? [];
67
+ return (
68
+ <SubContainer key={field.id} title={field.name}>
69
+ <GenericDynamicTable name="fixed_columns_table" columns={columns} />
70
+ </SubContainer>
71
+ );
72
+ }
73
+ case "zauru_data":
74
+ return (
75
+ <TextFieldWithoutValidation
76
+ key={field.id}
77
+ title={`${field.required ? "*" : ""}${field.name}`}
78
+ hint={field.hint}
79
+ defaultValue={defaultValue?.value ?? field.default_value}
80
+ disabled={true}
81
+ />
82
+ );
83
+ case "hour":
84
+ return (
85
+ <FormTimePicker
86
+ key={field.id}
87
+ title={`${field.required ? "*" : ""}${field.name}`}
88
+ name={`${namesStr}${field.form_id}_${field.id}`}
89
+ hint={field.hint}
90
+ disabled={readOnly}
91
+ defaultValue={defaultValue?.value}
92
+ />
93
+ );
94
+ case "date":
95
+ return (
96
+ <FormDatePicker
97
+ key={field.id}
98
+ title={`${field.required ? "*" : ""}${field.name}`}
99
+ name={`${namesStr}${field.form_id}_${field.id}`}
100
+ hint={field.hint}
101
+ disabled={readOnly}
102
+ defaultValue={defaultValue?.value}
103
+ />
104
+ );
105
+ case "file":
106
+ return (
107
+ <FileUploadField
108
+ key={field.id}
109
+ title={`${field.required ? "*" : ""}${field.name}`}
110
+ name={`${namesStr}${field.form_id}_${field.id}`}
111
+ hint={field.hint}
112
+ disabled={readOnly}
113
+ defaultValue={defaultValue?.value}
114
+ download={true}
115
+ />
116
+ );
117
+ case "image":
118
+ return (
119
+ <FileUploadField
120
+ key={field.id}
121
+ title={`${field.required ? "*" : ""}${field.name}`}
122
+ name={`${namesStr}${field.form_id}_${field.id}`}
123
+ hint={field.hint}
124
+ showAvailableTypes
125
+ fileTypes={["png", "jpg", "jpeg"]}
126
+ disabled={readOnly}
127
+ defaultValue={defaultValue?.value}
128
+ />
129
+ );
130
+ case "pdf":
131
+ return (
132
+ <FileUploadField
133
+ key={field.id}
134
+ title={`${field.required ? "*" : ""}${field.name}`}
135
+ name={`${namesStr}${field.form_id}_${field.id}`}
136
+ hint={field.hint}
137
+ showAvailableTypes
138
+ fileTypes={["pdf"]}
139
+ disabled={readOnly}
140
+ defaultValue={defaultValue?.value}
141
+ download={true}
142
+ />
143
+ );
144
+ case "email":
145
+ case "url":
146
+ case "text":
147
+ case "currency":
148
+ case "country":
149
+ return (
150
+ <TextField
151
+ key={field.id}
152
+ title={`${field.required ? "*" : ""}${field.name}`}
153
+ name={`${namesStr}${field.form_id}_${field.id}`}
154
+ hint={field.hint}
155
+ defaultValue={defaultValue?.value ?? field.default_value}
156
+ disabled={readOnly}
157
+ />
158
+ );
159
+ case "percentage":
160
+ case "number":
161
+ return (
162
+ <TextField
163
+ key={field.id}
164
+ title={`${field.required ? "*" : ""}${field.name}`}
165
+ name={`${namesStr}${field.form_id}_${field.id}`}
166
+ hint={field.hint}
167
+ defaultValue={defaultValue?.value ?? field.default_value}
168
+ type="number"
169
+ disabled={readOnly}
170
+ />
171
+ );
172
+ case "yes_no":
173
+ return (
174
+ <YesNo
175
+ key={field.id}
176
+ title={`${field.required ? "*" : ""}${field.name}`}
177
+ name={`${namesStr}${field.form_id}_${field.id}`}
178
+ disabled={readOnly}
179
+ defaultValue={
180
+ defaultValue?.value === "true" ?? field.default_value === "true"
181
+ }
182
+ />
183
+ );
184
+ case "section":
185
+ return (
186
+ <div key={field.id}>
187
+ <LineSeparator />
188
+ <h3 className="mb-10 text-3xl font-bold leading-8 text-gray-900">
189
+ {field.name}
190
+ </h3>
191
+ </div>
192
+ );
193
+ case "multi_line_text":
194
+ return (
195
+ <TextArea
196
+ key={field.id}
197
+ title={`${field.required ? "*" : ""}${field.name}`}
198
+ name={`${namesStr}${field.form_id}_${field.id}`}
199
+ defaultValue={defaultValue?.value ?? field.default_value}
200
+ hint={field.hint}
201
+ disabled={readOnly}
202
+ />
203
+ );
204
+ case "gt_departamentos": {
205
+ const optionsDep = getDepSelectOptions();
206
+ return (
207
+ <SelectField
208
+ key={field.id}
209
+ title={`${field.required ? "*" : ""}${field.name}`}
210
+ name={`${namesStr}${field.form_id}_${field.id}`}
211
+ hint={field.hint}
212
+ isClearable={!field.required}
213
+ options={optionsDep}
214
+ disabled={readOnly}
215
+ defaultValue={optionsDep.find(
216
+ (x) => x.value === defaultValue?.value
217
+ )}
218
+ />
219
+ );
220
+ }
221
+ case "gt_municipios": {
222
+ const options = getMunSelectOptions();
223
+
224
+ return (
225
+ <SelectField
226
+ key={field.id}
227
+ title={`${field.required ? "*" : ""}${field.name}`}
228
+ name={`${namesStr}${field.form_id}_${field.id}`}
229
+ hint={field.hint}
230
+ isClearable={!field.required}
231
+ options={options}
232
+ disabled={readOnly}
233
+ defaultValue={options.find((x) => x.value === defaultValue?.value)}
234
+ />
235
+ );
236
+ }
237
+ case "single_select_options": {
238
+ const formFieldOptions =
239
+ field.settings_form_field_options?.map((x) => {
240
+ return { label: x.label, value: x.value } as SelectFieldOption;
241
+ }) ?? [];
242
+
243
+ return (
244
+ <SelectField
245
+ key={field.id}
246
+ title={`${field.required ? "*" : ""}${field.name}`}
247
+ name={`${namesStr}${field.form_id}_${field.id}`}
248
+ hint={field.hint}
249
+ isClearable={!field.required}
250
+ options={formFieldOptions}
251
+ disabled={readOnly}
252
+ defaultValue={formFieldOptions.find(
253
+ (x) => x.value === defaultValue?.value
254
+ )}
255
+ />
256
+ );
257
+ }
258
+ case "multi_select_options": {
259
+ const formFieldOptions2 =
260
+ field.settings_form_field_options?.map((x) => {
261
+ return { label: x.label, value: x.value } as SelectFieldOption;
262
+ }) ?? [];
263
+
264
+ const defaultValuesMulti = (() => {
265
+ const values =
266
+ defaultValue?.value?.split(",").map((str) => str.trim()) ?? [];
267
+ return formFieldOptions2.filter((x) => values.includes(x.value));
268
+ })();
269
+
270
+ return (
271
+ <SelectField
272
+ key={field.id}
273
+ title={`${field.required ? "*" : ""}${field.name}`}
274
+ name={`${namesStr}${field.form_id}_${field.id}`}
275
+ hint={field.hint}
276
+ isClearable={!field.required}
277
+ isMulti
278
+ options={formFieldOptions2}
279
+ defaultValueMulti={defaultValuesMulti}
280
+ disabled={readOnly}
281
+ />
282
+ );
283
+ }
284
+ default:
285
+ return (
286
+ <div key={field.id}>
287
+ Componente no encontrado para: {field.field_type}
288
+ </div>
289
+ ); // o algún componente por defecto si lo prefieres
290
+ }
291
+ };
292
+
293
+ const renderFields = () => {
294
+ const fields = form.settings_form_fields;
295
+ const fieldGroups: JSX.Element[] = [];
296
+ let tempGroup: JSX.Element[] = [];
297
+
298
+ fields.forEach((field, i) => {
299
+ const rule = showingRules.find((x) => x.name === field.name);
300
+ if (!(rule && !rule.show)) {
301
+ const renderedField = renderFieldComponent(field);
302
+ if (renderedField === null) {
303
+ return;
304
+ }
305
+ tempGroup.push(renderedField);
306
+
307
+ const isLastField = i === fields.length - 1;
308
+ const isSectionField = field.field_type === "section";
309
+
310
+ if (isSectionField) {
311
+ tempGroup.pop();
312
+ if (tempGroup.length === 1) {
313
+ fieldGroups.push(tempGroup[0]);
314
+ } else if (tempGroup.length === 2) {
315
+ fieldGroups.push(
316
+ <DoubleFieldContainer key={i}>{tempGroup}</DoubleFieldContainer>
317
+ );
318
+ } else if (tempGroup.length === 3) {
319
+ fieldGroups.push(
320
+ <TripleFieldContainer key={i}>{tempGroup}</TripleFieldContainer>
321
+ );
322
+ }
323
+ fieldGroups.push(renderedField);
324
+ tempGroup = [];
325
+ } else if (isLastField) {
326
+ if (tempGroup.length === 1) {
327
+ fieldGroups.push(tempGroup[0]);
328
+ } else if (tempGroup.length === 2) {
329
+ fieldGroups.push(
330
+ <DoubleFieldContainer key={i}>{tempGroup}</DoubleFieldContainer>
331
+ );
332
+ } else if (tempGroup.length === 3) {
333
+ fieldGroups.push(
334
+ <TripleFieldContainer key={i}>{tempGroup}</TripleFieldContainer>
335
+ );
336
+ }
337
+ tempGroup = [];
338
+ } else if (tempGroup.length === 3) {
339
+ // Si hay 3 elementos en el grupo temporal y el siguiente campo no es 'section', se agrega a fieldGroups
340
+ fieldGroups.push(
341
+ <TripleFieldContainer key={i}>{tempGroup}</TripleFieldContainer>
342
+ );
343
+ tempGroup = [];
344
+ }
345
+ }
346
+ });
347
+
348
+ return fieldGroups;
349
+ };
350
+
351
+ return (
352
+ <SubContainer
353
+ title={options?.showTitle ? form.name : undefined}
354
+ description={options?.showDescription ? form.description : undefined}
355
+ >
356
+ {renderFields()}
357
+ </SubContainer>
358
+ );
359
+ }
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+
3
+ type Props = {
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ alignCenter?: boolean;
7
+ };
8
+
9
+ export const DoubleFieldContainer = (props: Props) => {
10
+ const { children, className, alignCenter = true } = props;
11
+
12
+ const getChildren = (index: number) => {
13
+ if (children && Array.isArray(children) && children[index]) {
14
+ return children[index];
15
+ }
16
+
17
+ if (children && index === 0) {
18
+ return children;
19
+ }
20
+
21
+ return <></>;
22
+ };
23
+
24
+ return (
25
+ <>
26
+ <div
27
+ className={`grid md:grid-cols-2 sm:grid-cols-1 gap-4 ${className}`}
28
+ style={alignCenter ? { alignItems: "center" } : {}}
29
+ >
30
+ <div className="col-span-1">{getChildren(0)}</div>
31
+ <div className="col-span-1">{getChildren(1)}</div>
32
+ </div>
33
+ </>
34
+ );
35
+ };
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+
3
+ type Props = {
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ };
7
+
8
+ export const QuadrupleFieldContainer = (props: Props) => {
9
+ const { children, className } = props;
10
+
11
+ const getChildren = (index: number) => {
12
+ if (children && Array.isArray(children) && children[index]) {
13
+ return children[index];
14
+ }
15
+
16
+ if (children && index === 0) {
17
+ return children;
18
+ }
19
+
20
+ return <></>;
21
+ };
22
+
23
+ return (
24
+ <>
25
+ <div
26
+ className={`grid lg:grid-cols-4 sm:grid-cols-2 xs:grid-cols-1 gap-4 ${className}`}
27
+ style={{ alignItems: "center" }}
28
+ >
29
+ <div className="col-span-1">{getChildren(0)}</div>
30
+ <div className="col-span-1">{getChildren(1)}</div>
31
+ <div className="col-span-1">{getChildren(2)}</div>
32
+ <div className="col-span-1">{getChildren(3)}</div>
33
+ </div>
34
+ </>
35
+ );
36
+ };
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+
3
+ type Props = {
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ };
7
+
8
+ export const TripleFieldContainer = (props: Props) => {
9
+ const { children, className } = props;
10
+
11
+ const getChildren = (index: number) => {
12
+ if (children && Array.isArray(children) && children[index]) {
13
+ return children[index];
14
+ }
15
+
16
+ if (children && index === 0) {
17
+ return children;
18
+ }
19
+
20
+ return <></>;
21
+ };
22
+
23
+ return (
24
+ <>
25
+ <div
26
+ className={`grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ${className}`}
27
+ style={{ alignItems: "center" }}
28
+ >
29
+ <div className="col-span-1">{getChildren(0)}</div>
30
+ <div className="col-span-1">{getChildren(1)}</div>
31
+ <div className="col-span-1">{getChildren(2)}</div>
32
+ </div>
33
+ </>
34
+ );
35
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./DoubleFieldContainer";
2
+ export * from "./QuadrupleFieldContainer";
3
+ export * from "./TripleFieldContainer";
@@ -0,0 +1,184 @@
1
+ import { DownloadIconSVG, IdeaIconSVG } from "@zauru-sdk/icons";
2
+ import { useAppSelector } from "@zauru-sdk/redux";
3
+ import React, { useState } from "react";
4
+
5
+ type Props = {
6
+ id?: string;
7
+ name: string;
8
+ formName?: string;
9
+ title?: string;
10
+ helpText?: string;
11
+ hint?: string;
12
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
13
+ disabled?: boolean;
14
+ readOnly?: boolean;
15
+ error?: string | undefined;
16
+ fileTypes?: string[];
17
+ showAvailableTypes?: boolean;
18
+ className?: string;
19
+ defaultValue?: string | File;
20
+ download?: boolean;
21
+ };
22
+
23
+ export const FileUploadFieldWithoutValidation = (props: Props) => {
24
+ const {
25
+ id,
26
+ name,
27
+ title,
28
+ helpText,
29
+ hint,
30
+ onChange,
31
+ disabled = false,
32
+ readOnly = false,
33
+ error,
34
+ fileTypes = [],
35
+ showAvailableTypes = false,
36
+ className,
37
+ defaultValue = undefined,
38
+ download = false,
39
+ } = props;
40
+
41
+ const [showTooltip, setShowTooltip] = useState<boolean>(false);
42
+
43
+ if (typeof defaultValue == "string") {
44
+ if (download) {
45
+ return (
46
+ <div
47
+ role="button"
48
+ tabIndex={0}
49
+ onClick={() => {
50
+ window.open(defaultValue, "_blank");
51
+ }}
52
+ onKeyDown={(event) => {
53
+ // Permite que el evento se active con la tecla Enter
54
+ if (event.key === "Enter") {
55
+ window.open(defaultValue, "_blank");
56
+ }
57
+ }}
58
+ >
59
+ {title && (
60
+ <label
61
+ htmlFor={name}
62
+ className="block mb-1 text-sm font-medium text-gray-700"
63
+ >
64
+ {title}
65
+ </label>
66
+ )}{" "}
67
+ <DownloadIconSVG />
68
+ </div>
69
+ );
70
+ }
71
+ return (
72
+ <div className={`col-span-6 sm:col-span-3 ${className}`}>
73
+ {title && (
74
+ <label
75
+ htmlFor={name}
76
+ className={`block mb-1 text-sm font-medium text-gray-700`}
77
+ >
78
+ {title}
79
+ </label>
80
+ )}{" "}
81
+ <div
82
+ role="button"
83
+ tabIndex={0}
84
+ onClick={() => {
85
+ window.open(defaultValue, "_blank");
86
+ }}
87
+ onKeyDown={(event) => {
88
+ // Permite que el evento se active con la tecla Enter
89
+ if (event.key === "Enter") {
90
+ window.open(defaultValue, "_blank");
91
+ }
92
+ }}
93
+ >
94
+ <img
95
+ src={defaultValue}
96
+ alt={name}
97
+ className={`h-48 w-48 inline mr-1 pb-1`}
98
+ style={{
99
+ stroke: "currentColor",
100
+ strokeWidth: 2,
101
+ strokeLinecap: "round",
102
+ strokeLinejoin: "round",
103
+ fill: "none",
104
+ backgroundColor: "transparent",
105
+ }}
106
+ />
107
+ </div>
108
+ </div>
109
+ );
110
+ }
111
+
112
+ const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
113
+ onChange && onChange(event);
114
+ };
115
+
116
+ let hintMessage = hint;
117
+ if (showAvailableTypes && fileTypes.length > 0) {
118
+ hintMessage = `${hint} Archivos permitidos: ${fileTypes.join(", ")}`;
119
+ }
120
+
121
+ const color = error ? "red" : "gray";
122
+ const isReadOnly = disabled || readOnly;
123
+ const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
124
+ const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
125
+ const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-500`;
126
+
127
+ return (
128
+ <div className={`col-span-6 sm:col-span-3 ${className}`}>
129
+ {title && (
130
+ <label
131
+ htmlFor={name}
132
+ className={`block mb-1 text-sm font-medium text-${color}-700`}
133
+ >
134
+ {title}
135
+ </label>
136
+ )}
137
+ <div className="flex relative items-center">
138
+ <input
139
+ type="file"
140
+ name={name}
141
+ id={id ?? name}
142
+ disabled={disabled}
143
+ readOnly={readOnly}
144
+ accept={fileTypes.map((ft) => `.${ft}`).join(", ")}
145
+ onChange={handleInputChange}
146
+ className={`block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`}
147
+ />
148
+ {helpText && (
149
+ <div className="flex items-center relative ml-3">
150
+ <div
151
+ className="relative cursor-pointer"
152
+ onMouseEnter={() => setShowTooltip(true)}
153
+ onMouseLeave={() => setShowTooltip(false)}
154
+ >
155
+ <IdeaIconSVG />
156
+ {showTooltip && (
157
+ <div className="absolute -left-48 top-0 mt-8 p-2 bg-white border rounded shadow text-black z-50">
158
+ {helpText}
159
+ </div>
160
+ )}
161
+ </div>
162
+ </div>
163
+ )}
164
+ </div>
165
+ {error && (
166
+ <p className={`mt-2 text-sm text-${color}-600`}>
167
+ <span className="font-medium">Oops!</span> {error}
168
+ </p>
169
+ )}
170
+ {!error && hintMessage && (
171
+ <p className={`mt-2 italic text-sm text-${color}-500`}>{hintMessage}</p>
172
+ )}
173
+ </div>
174
+ );
175
+ };
176
+
177
+ export const FileUploadField = (props: Props) => {
178
+ const { formValidations } = useAppSelector((state) => state.formValidation);
179
+ const error = formValidations[props.formName ?? "-1"]?.[props.name ?? "-1"];
180
+
181
+ props = { ...props, error };
182
+
183
+ return <FileUploadFieldWithoutValidation {...props} />;
184
+ };