@visiion/forms-library 1.4.18 → 1.4.19

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/index.js CHANGED
@@ -23202,6 +23202,1269 @@ var GenericForm = function (_a) {
23202
23202
  return formContent;
23203
23203
  };
23204
23204
 
23205
+ // se convierte tags a mayúsculas excepto (h) que debe preservarse
23206
+ var convertTagsToUppercase$1 = function (text) {
23207
+ return text.replace(/\(([a-z]\d*)\)/g, function (match, tag) {
23208
+ if (tag === 'h')
23209
+ return match; // se preserva (h) minúscula
23210
+ return "(".concat(tag.toUpperCase(), ")");
23211
+ });
23212
+ };
23213
+ var SelectorComponent = function (_a) {
23214
+ var value = _a.value, onChange = _a.onChange, options = _a.options, placeholder = _a.placeholder;
23215
+ var _b = React.useState(false), isOpen = _b[0], setIsOpen = _b[1];
23216
+ var dropdownRef = React.useRef(null);
23217
+ // Encontrar la opción seleccionada
23218
+ // Comparar normalizando los tags a mayúsculas para ambos valores
23219
+ var selectedOption = options.find(function (option) { return convertTagsToUppercase$1(option.texto_visible) === convertTagsToUppercase$1(value); });
23220
+ // Cerrar dropdown al hacer click fuera
23221
+ React.useEffect(function () {
23222
+ var handleClickOutside = function (event) {
23223
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
23224
+ setIsOpen(false);
23225
+ }
23226
+ };
23227
+ document.addEventListener('mousedown', handleClickOutside);
23228
+ return function () {
23229
+ document.removeEventListener('mousedown', handleClickOutside);
23230
+ };
23231
+ }, []);
23232
+ return (jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [jsxRuntime.jsx("button", { type: "button", onClick: function () { return setIsOpen(!isOpen); }, className: "w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-left focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500", children: selectedOption ? convertTagsToUppercase$1(selectedOption.texto_visible) : placeholder }), isOpen && (jsxRuntime.jsx("div", { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg", children: options.map(function (option) { return (jsxRuntime.jsx("button", { type: "button", onClick: function () {
23233
+ onChange(option.texto_visible);
23234
+ setIsOpen(false);
23235
+ }, className: "w-full px-3 py-2 text-left hover:bg-gray-100 focus:bg-gray-100 focus:outline-none", children: convertTagsToUppercase$1(option.texto_visible) }, option.id)); }) }))] }));
23236
+ };
23237
+
23238
+ // se convierte tags dentro del texto (excepto el tag principal H/h)
23239
+ var convertInnerTagsToUppercase = function (text) {
23240
+ return text.replace(/\(([a-z]\d*)\)/g, function (match, tag) {
23241
+ // si el tag es 'h' solo (sin número), no convertir
23242
+ if (tag === 'h')
23243
+ return match;
23244
+ return "(".concat(tag.toUpperCase(), ")");
23245
+ });
23246
+ };
23247
+ var MultiSelectorComponent = function (_a) {
23248
+ var value = _a.value, onChange = _a.onChange, options = _a.options, placeholder = _a.placeholder;
23249
+ var _b = React.useState(false), isOpen = _b[0], setIsOpen = _b[1];
23250
+ var dropdownRef = React.useRef(null);
23251
+ // se parsean los valores seleccionados (separados por " y ")
23252
+ var parseSelectedValues = function (val) {
23253
+ if (!val || val.trim() === '')
23254
+ return [];
23255
+ return val
23256
+ .split(' y ')
23257
+ .map(function (v) { return v.trim(); })
23258
+ .filter(Boolean);
23259
+ };
23260
+ var selectedValues = parseSelectedValues(value);
23261
+ // se verifica si una opción está seleccionada
23262
+ var isSelected = function (option) {
23263
+ var normalizedOption = convertInnerTagsToUppercase(option.texto_visible);
23264
+ return selectedValues.some(function (sv) { return convertInnerTagsToUppercase(sv) === normalizedOption; });
23265
+ };
23266
+ // se maneja el toggle de una opción
23267
+ var handleToggle = function (option) {
23268
+ var newSelected;
23269
+ if (isSelected(option)) {
23270
+ // se remueve
23271
+ newSelected = selectedValues.filter(function (sv) {
23272
+ return convertInnerTagsToUppercase(sv) !== convertInnerTagsToUppercase(option.texto_visible);
23273
+ });
23274
+ }
23275
+ else {
23276
+ // se agrega
23277
+ newSelected = __spreadArray(__spreadArray([], selectedValues, true), [option.texto_visible], false);
23278
+ }
23279
+ // se ordena según el orden de las opciones
23280
+ var sortedSelected = newSelected.sort(function (a, b) {
23281
+ var _a, _b;
23282
+ var optA = options.find(function (o) { return convertInnerTagsToUppercase(o.texto_visible) === convertInnerTagsToUppercase(a); });
23283
+ var optB = options.find(function (o) { return convertInnerTagsToUppercase(o.texto_visible) === convertInnerTagsToUppercase(b); });
23284
+ return ((_a = optA === null || optA === void 0 ? void 0 : optA.orden) !== null && _a !== void 0 ? _a : 0) - ((_b = optB === null || optB === void 0 ? void 0 : optB.orden) !== null && _b !== void 0 ? _b : 0);
23285
+ });
23286
+ // se unen con " y "
23287
+ onChange(sortedSelected.join(' y '));
23288
+ };
23289
+ // se cierra dropdown al hacer click fuera
23290
+ React.useEffect(function () {
23291
+ var handleClickOutside = function (event) {
23292
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
23293
+ setIsOpen(false);
23294
+ }
23295
+ };
23296
+ document.addEventListener('mousedown', handleClickOutside);
23297
+ return function () {
23298
+ document.removeEventListener('mousedown', handleClickOutside);
23299
+ };
23300
+ }, []);
23301
+ // se muestra el texto de selección
23302
+ var displayText = selectedValues.length > 0
23303
+ ? selectedValues.map(function (v) { return convertInnerTagsToUppercase(v); }).join(' y ')
23304
+ : placeholder;
23305
+ return (jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [jsxRuntime.jsx("button", { type: "button", onClick: function () { return setIsOpen(!isOpen); }, className: "w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-left focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500", children: jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsx("span", { className: selectedValues.length === 0 ? 'text-gray-400' : '', children: displayText }), jsxRuntime.jsx("span", { className: "ml-2 text-xs text-gray-500", children: selectedValues.length > 0 && "(".concat(selectedValues.length, ")") })] }) }), isOpen && (jsxRuntime.jsx("div", { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg", children: options.map(function (option) {
23306
+ var selected = isSelected(option);
23307
+ return (jsxRuntime.jsx("button", { type: "button", onClick: function () { return handleToggle(option); }, className: "flex w-full items-center px-3 py-2 text-left hover:bg-gray-100 focus:bg-gray-100 focus:outline-none ".concat(selected ? 'bg-sky-50' : ''), children: jsxRuntime.jsxs("div", { className: "flex flex-1 items-center", children: [jsxRuntime.jsx("div", { className: "mr-2 flex h-4 w-4 flex-shrink-0 items-center justify-center rounded border-2 ".concat(selected ? 'border-sky-600 bg-sky-600' : 'border-gray-300'), children: selected && (jsxRuntime.jsx("svg", { className: "h-3 w-3 text-white", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", stroke: "currentColor", children: jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7" }) })) }), jsxRuntime.jsx("span", { children: convertInnerTagsToUppercase(option.texto_visible) })] }) }, option.id));
23308
+ }) }))] }));
23309
+ };
23310
+
23311
+ // Función auxiliar para convertir tags a mayúsculas
23312
+ var convertTagsToUppercase = function (text) {
23313
+ return text.replace(/\(([a-z]\d*)\)/g, function (_, tag) { return "(".concat(tag.toUpperCase(), ")"); });
23314
+ };
23315
+ var TextComponent = function (_a) {
23316
+ var label = _a.label, value = _a.value, onChange = _a.onChange, placeholder = _a.placeholder, _b = _a.rows, rows = _b === void 0 ? 3 : _b;
23317
+ // Manejar cambios en el textarea y convertir tags a mayúsculas
23318
+ var handleChange = function (e) {
23319
+ var newValue = e.target.value;
23320
+ var normalizedValue = convertTagsToUppercase(newValue);
23321
+ onChange(normalizedValue);
23322
+ };
23323
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("label", { className: "inline-block px-2 py-1 text-sm font-medium rounded ".concat(value ? 'text-green-800 bg-green-100' : 'text-orange-800'), style: value ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: label }), jsxRuntime.jsx("textarea", { value: value, onChange: handleChange, placeholder: placeholder, className: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400 resize-none", rows: rows })] }));
23324
+ };
23325
+
23326
+ // Función para detectar el tipo de período según el formato de valores presentes
23327
+ var detectDateType = function (valor) {
23328
+ if (!valor)
23329
+ return 'dia';
23330
+ var first = valor.split('|').map(function (p) { return p.split(' - ')[0].trim(); }).find(Boolean) || '';
23331
+ if (/^\d{2}\/\d{2}\/\d{4}$/.test(first))
23332
+ return 'dia';
23333
+ if (/^\d{2}\/\d{4}$/.test(first))
23334
+ return 'mes';
23335
+ if (/^\d{4}$/.test(first))
23336
+ return 'año';
23337
+ return 'dia';
23338
+ };
23339
+ // Función para formatear fecha a YYYY-MM-DD
23340
+ var formatDateToYYYYMMDD = function (date) {
23341
+ if (!date)
23342
+ return '';
23343
+ var parts = date.split('/');
23344
+ if (parts.length === 3) {
23345
+ return "".concat(parts[2], "-").concat(parts[1].padStart(2, '0'), "-").concat(parts[0].padStart(2, '0'));
23346
+ }
23347
+ return date;
23348
+ };
23349
+ // Función para formatear fecha a dd/mm/yyyy
23350
+ var formatDateToDDMMYYYY = function (date) {
23351
+ if (!date)
23352
+ return '';
23353
+ // Si ya está en formato dd/mm/yyyy, devolverlo tal como está
23354
+ if (/^\d{2}\/\d{2}\/\d{4}$/.test(date)) {
23355
+ return date;
23356
+ }
23357
+ // Si está en formato YYYY-MM-DD, convertir a dd/mm/yyyy
23358
+ if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
23359
+ var parts = date.split('-');
23360
+ return "".concat(parts[2], "/").concat(parts[1], "/").concat(parts[0]);
23361
+ }
23362
+ return date;
23363
+ };
23364
+ // Mes: MM/YYYY <-> YYYY-MM
23365
+ var formatMonthToYYYYMM = function (mmYYYY) {
23366
+ if (!mmYYYY)
23367
+ return '';
23368
+ var _a = mmYYYY.split('/'), mm = _a[0], yyyy = _a[1];
23369
+ if (mm && yyyy)
23370
+ return "".concat(yyyy, "-").concat(mm.padStart(2, '0'));
23371
+ return mmYYYY;
23372
+ };
23373
+ var formatMonthToMMYYYY = function (yyyyMM) {
23374
+ if (!yyyyMM)
23375
+ return '';
23376
+ var _a = yyyyMM.split('-'), yyyy = _a[0], mm = _a[1];
23377
+ if (yyyy && mm)
23378
+ return "".concat(mm, "/").concat(yyyy);
23379
+ return yyyyMM;
23380
+ };
23381
+ // Comparador genérico para rangos
23382
+ var toComparable = function (v, tipo) {
23383
+ if (!v)
23384
+ return '';
23385
+ if (tipo === 'dia')
23386
+ return formatDateToYYYYMMDD(v);
23387
+ if (tipo === 'mes')
23388
+ return formatMonthToYYYYMM(v);
23389
+ return v; // año ya está en YYYY
23390
+ };
23391
+ var isValidRange = function (desde, hasta, tipo) {
23392
+ if (!desde || !hasta)
23393
+ return true;
23394
+ return toComparable(desde, tipo) <= toComparable(hasta, tipo);
23395
+ };
23396
+ // Función para parsear períodos
23397
+ var parsePeriods = function (valor) {
23398
+ if (!valor)
23399
+ return [{ desde: '', hasta: '' }];
23400
+ var periods = valor.split('|').map(function (period) {
23401
+ var parts = period.split(' - ');
23402
+ return {
23403
+ desde: parts[0] || '',
23404
+ hasta: parts[1] || ''
23405
+ };
23406
+ });
23407
+ return periods.length > 0 ? periods : [{ desde: '', hasta: '' }];
23408
+ };
23409
+ // Función para formatear períodos para reemplazo
23410
+ var formatPeriodsForReplacement = function (valor) {
23411
+ if (!valor)
23412
+ return '';
23413
+ // Si el valor no contiene '|' ni ' - ', es una fecha única
23414
+ if (!valor.includes('|') && !valor.includes(' - ')) {
23415
+ return valor; // Devolver la fecha tal como está
23416
+ }
23417
+ var periods = parsePeriods(valor);
23418
+ var validPeriods = periods.filter(function (p) { return p.desde && p.hasta; });
23419
+ if (validPeriods.length === 0)
23420
+ return '';
23421
+ // se formatea especial para:
23422
+ // - día: "del 01 de febrero del 2024 al 25 de marzo del 2024"
23423
+ // - mes: "de marzo del 2024 a mayo del 2024"
23424
+ var dayPattern = /^\d{2}\/\d{2}\/\d{4}$/;
23425
+ var monthPattern = /^\d{2}\/\d{4}$/;
23426
+ var monthNames = [
23427
+ 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio',
23428
+ 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'
23429
+ ];
23430
+ var formatLongDay = function (ddmmyyyy) {
23431
+ var _a = ddmmyyyy.split('/'), dd = _a[0], mm = _a[1], yyyy = _a[2];
23432
+ var monthIdx = Math.max(0, Math.min(11, Number(mm) - 1));
23433
+ var monthName = monthNames[monthIdx] || mm;
23434
+ return "".concat(dd, " de ").concat(monthName, " del ").concat(yyyy);
23435
+ };
23436
+ var formatLongMonth = function (mmyyyy) {
23437
+ var _a = mmyyyy.split('/'), mm = _a[0], yyyy = _a[1];
23438
+ var monthIdx = Math.max(0, Math.min(11, Number(mm) - 1));
23439
+ var monthName = monthNames[monthIdx] || mm;
23440
+ return "".concat(monthName, " del ").concat(yyyy);
23441
+ };
23442
+ var periodStrings = validPeriods.map(function (p) {
23443
+ var isDayRange = dayPattern.test(p.desde) && dayPattern.test(p.hasta);
23444
+ if (isDayRange) {
23445
+ return "del ".concat(formatLongDay(p.desde), " al ").concat(formatLongDay(p.hasta));
23446
+ }
23447
+ var isMonthRange = monthPattern.test(p.desde) && monthPattern.test(p.hasta);
23448
+ if (isMonthRange) {
23449
+ return "de ".concat(formatLongMonth(p.desde), " a ").concat(formatLongMonth(p.hasta));
23450
+ }
23451
+ var isYearRange = /^\d{4}$/.test(p.desde) && /^\d{4}$/.test(p.hasta);
23452
+ if (isYearRange) {
23453
+ return "desde el ".concat(p.desde, " al ").concat(p.hasta);
23454
+ }
23455
+ return "".concat(p.desde, " al ").concat(p.hasta);
23456
+ });
23457
+ if (periodStrings.length === 1) {
23458
+ return periodStrings[0];
23459
+ }
23460
+ else if (periodStrings.length === 2) {
23461
+ return "".concat(periodStrings[0], " y ").concat(periodStrings[1]);
23462
+ }
23463
+ else {
23464
+ var lastPeriod = periodStrings.pop();
23465
+ return "".concat(periodStrings.join(', '), " y ").concat(lastPeriod);
23466
+ }
23467
+ };
23468
+ var PeriodComponent = function (_a) {
23469
+ var label = _a.label, value = _a.value, onChange = _a.onChange;
23470
+ // Estados internos del componente
23471
+ var _b = React.useState('dia'), dateType = _b[0], setDateType = _b[1];
23472
+ // se inicializa el tipo una sola vez a partir del valor inicial; luego solo cambia por acción del usuario
23473
+ var initializedTypeRef = React.useRef(false);
23474
+ React.useEffect(function () {
23475
+ if (!initializedTypeRef.current) {
23476
+ var detectedType = detectDateType(value);
23477
+ setDateType(detectedType);
23478
+ initializedTypeRef.current = true;
23479
+ }
23480
+ }, [value]);
23481
+ // Handlers internos
23482
+ var handleTypeChange = function (newType) {
23483
+ setDateType(newType);
23484
+ onChange(''); // Limpiar el valor al cambiar tipo
23485
+ };
23486
+ // se maneja mediante rangos para todos los tipos (día, mes, año)
23487
+ var periods = parsePeriods(value);
23488
+ // detección de rangos duplicados (según tipo actual)
23489
+ var comparableRanges = periods.map(function (p) { return "".concat(toComparable(p.desde, dateType), "|").concat(toComparable(p.hasta, dateType)); });
23490
+ var seenKeys = new Set();
23491
+ var duplicateFlags = comparableRanges.map(function (key) {
23492
+ // evita marcar como duplicado si el rango está incompleto
23493
+ if (!key || key === '|' || key.startsWith('|') || key.endsWith('|'))
23494
+ return false;
23495
+ var isDup = seenKeys.has(key);
23496
+ seenKeys.add(key);
23497
+ return isDup;
23498
+ });
23499
+ var addPeriod = function () {
23500
+ var newPeriods = __spreadArray(__spreadArray([], periods, true), [{ desde: '', hasta: '' }], false);
23501
+ var newValor = newPeriods.map(function (p) { return "".concat(p.desde, " - ").concat(p.hasta); }).join('|');
23502
+ onChange(newValor);
23503
+ };
23504
+ var removePeriod = function (index) {
23505
+ var newPeriods = periods.filter(function (_, i) { return i !== index; });
23506
+ var newValor = newPeriods.map(function (p) { return "".concat(p.desde, " - ").concat(p.hasta); }).join('|');
23507
+ onChange(newValor);
23508
+ };
23509
+ var updatePeriod = function (index, field, value) {
23510
+ var _a;
23511
+ var newPeriods = __spreadArray([], periods, true);
23512
+ newPeriods[index] = __assign(__assign({}, newPeriods[index]), (_a = {}, _a[field] = value, _a));
23513
+ var newValor = newPeriods.map(function (p) { return "".concat(p.desde, " - ").concat(p.hasta); }).join('|');
23514
+ onChange(newValor);
23515
+ };
23516
+ // validaciones para habilitar/deshabilitar agregar rango
23517
+ var isPeriodComplete = function (p) { return !!(p.desde && p.hasta && isValidRange(p.desde, p.hasta, dateType)); };
23518
+ var lastPeriod = periods[periods.length - 1] || { desde: '', hasta: '' };
23519
+ var allRangesOrderValid = periods.every(function (p) { return !p.desde || !p.hasta || isValidRange(p.desde, p.hasta, dateType); })
23520
+ && periods.every(function (p, idx) { return idx === 0 || !periods[idx - 1].hasta || !p.desde || isValidRange(periods[idx - 1].hasta, p.desde, dateType); });
23521
+ var canAddAnother = isPeriodComplete(lastPeriod) && !duplicateFlags[periods.length - 1] && allRangesOrderValid;
23522
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsxs("label", { className: "inline-block px-2 py-1 text-sm font-medium rounded ".concat(value ? 'text-green-800 bg-green-100' : 'text-orange-800'), style: value ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: ["(", label, ")"] }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: function () { return handleTypeChange('dia'); }, className: "px-3 py-2 text-sm rounded-md border transition-colors ".concat(dateType === 'dia'
23523
+ ? 'bg-gray-300 text-gray-900 border-gray-500 shadow-sm'
23524
+ : 'bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200'), children: "D\u00EDa" }), jsxRuntime.jsx("button", { type: "button", onClick: function () { return handleTypeChange('mes'); }, className: "px-3 py-2 text-sm rounded-md border transition-colors ".concat(dateType === 'mes'
23525
+ ? 'bg-gray-300 text-gray-900 border-gray-500 shadow-sm'
23526
+ : 'bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200'), children: "Mes" }), jsxRuntime.jsx("button", { type: "button", onClick: function () { return handleTypeChange('año'); }, className: "px-3 py-2 text-sm rounded-md border transition-colors ".concat(dateType === 'año'
23527
+ ? 'bg-gray-300 text-gray-900 border-gray-500 shadow-sm'
23528
+ : 'bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200'), children: "A\u00F1o" })] }), (dateType === 'dia' || dateType === 'mes') && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [periods.map(function (period, index) {
23529
+ var _a;
23530
+ return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx("input", { type: dateType === 'mes' ? 'month' : 'date', min: (function () {
23531
+ var _a;
23532
+ if (index === 0)
23533
+ return undefined;
23534
+ var prevHasta = ((_a = periods[index - 1]) === null || _a === void 0 ? void 0 : _a.hasta) || '';
23535
+ if (!prevHasta)
23536
+ return undefined;
23537
+ return dateType === 'mes' ? formatMonthToYYYYMM(prevHasta) : formatDateToYYYYMMDD(prevHasta);
23538
+ })(), max: (function () {
23539
+ var today = new Date();
23540
+ if (dateType === 'mes') {
23541
+ var yyyy = today.getFullYear();
23542
+ var mm = String(today.getMonth() + 1).padStart(2, '0');
23543
+ return "".concat(yyyy, "-").concat(mm);
23544
+ }
23545
+ else {
23546
+ var yyyy = today.getFullYear();
23547
+ var mm = String(today.getMonth() + 1).padStart(2, '0');
23548
+ var dd = String(today.getDate()).padStart(2, '0');
23549
+ return "".concat(yyyy, "-").concat(mm, "-").concat(dd);
23550
+ }
23551
+ })(), value: dateType === 'mes'
23552
+ ? (period.desde ? formatMonthToYYYYMM(period.desde) : '')
23553
+ : (period.desde ? formatDateToYYYYMMDD(period.desde) : ''), onChange: function (e) {
23554
+ var newDesde = dateType === 'mes'
23555
+ ? formatMonthToMMYYYY(e.target.value)
23556
+ : formatDateToDDMMYYYY(e.target.value);
23557
+ updatePeriod(index, 'desde', newDesde);
23558
+ }, className: "w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400" }) }), jsxRuntime.jsx("span", { className: "text-sm text-gray-600 font-medium", children: "al" }), jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("input", { type: dateType === 'mes' ? 'month' : 'date', min: period.desde ? (dateType === 'mes' ? formatMonthToYYYYMM(period.desde) : formatDateToYYYYMMDD(period.desde)) : undefined, max: index === periods.length - 1 ? (function () {
23559
+ var today = new Date();
23560
+ if (dateType === 'mes') {
23561
+ var yyyy = today.getFullYear();
23562
+ var mm = String(today.getMonth() + 1).padStart(2, '0');
23563
+ return "".concat(yyyy, "-").concat(mm);
23564
+ }
23565
+ else {
23566
+ var yyyy = today.getFullYear();
23567
+ var mm = String(today.getMonth() + 1).padStart(2, '0');
23568
+ var dd = String(today.getDate()).padStart(2, '0');
23569
+ return "".concat(yyyy, "-").concat(mm, "-").concat(dd);
23570
+ }
23571
+ })() : undefined, value: dateType === 'mes'
23572
+ ? (period.hasta ? formatMonthToYYYYMM(period.hasta) : '')
23573
+ : (period.hasta ? formatDateToYYYYMMDD(period.hasta) : ''), onChange: function (e) {
23574
+ var newHasta = dateType === 'mes'
23575
+ ? formatMonthToMMYYYY(e.target.value)
23576
+ : formatDateToDDMMYYYY(e.target.value);
23577
+ updatePeriod(index, 'hasta', newHasta);
23578
+ }, className: "w-full px-3 py-2 pr-10 border rounded-lg focus:outline-none focus:ring-2 focus:border-transparent transition-all duration-200 hover:border-gray-400 ".concat(period.desde && period.hasta && !isValidRange(period.desde, period.hasta, dateType)
23579
+ ? 'border-red-500 focus:ring-red-500'
23580
+ : 'border-gray-300 focus:ring-blue-500') }), periods.length > 1 && (jsxRuntime.jsx("button", { type: "button", onClick: function () { return removePeriod(index); }, className: "absolute right-2 top-1/2 transform -translate-y-1/2 text-red-500 hover:text-red-700 transition-colors", title: "Eliminar per\u00EDodo", children: jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }) })] }), index > 0 && ((_a = periods[index - 1]) === null || _a === void 0 ? void 0 : _a.hasta) && period.desde && !isValidRange(periods[index - 1].hasta, period.desde, dateType) && (jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: "El inicio debe ser posterior o igual al final del rango anterior" })), duplicateFlags[index] && (jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: "El rango est\u00E1 duplicado" })), period.desde && period.hasta && !isValidRange(period.desde, period.hasta, dateType) && (jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: "La fecha final debe ser posterior a la fecha inicial" }))] }, index));
23581
+ }), jsxRuntime.jsx("div", { className: "w-full", children: jsxRuntime.jsx("button", { type: "button", onClick: addPeriod, disabled: !canAddAnother, className: "w-full px-3 py-2 text-sm border rounded-md transition-colors ".concat(canAddAnother
23582
+ ? 'bg-gray-100 text-gray-700 border-gray-300 hover:bg-gray-200'
23583
+ : 'bg-gray-200 text-gray-400 border-gray-300 cursor-not-allowed'), title: !canAddAnother ? 'Completa y corrige el rango actual antes de agregar otro' : '', children: "+ Agregar rango" }) })] })), dateType === 'año' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [periods.map(function (period, index) {
23584
+ var _a;
23585
+ return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx("input", { type: "number", min: (function () {
23586
+ var _a;
23587
+ if (index === 0)
23588
+ return '1900';
23589
+ var prevHasta = ((_a = periods[index - 1]) === null || _a === void 0 ? void 0 : _a.hasta) || '';
23590
+ return prevHasta || '1900';
23591
+ })(), max: new Date().getFullYear().toString(), value: period.desde || '', onChange: function (e) {
23592
+ var value = e.target.value;
23593
+ var numValue = Number(value);
23594
+ var currentYear = new Date().getFullYear();
23595
+ // se valida que no sea mayor al año actual
23596
+ if (value && numValue > currentYear) {
23597
+ return; // no actualizar si supera el año actual
23598
+ }
23599
+ updatePeriod(index, 'desde', value);
23600
+ }, className: "w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400" }) }), jsxRuntime.jsx("span", { className: "text-sm text-gray-600 font-medium", children: "al" }), jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("input", { type: "number", min: period.desde || '1900', max: index === periods.length - 1 ? new Date().getFullYear().toString() : '2100', value: period.hasta || '', onChange: function (e) {
23601
+ var value = e.target.value;
23602
+ var numValue = Number(value);
23603
+ var currentYear = new Date().getFullYear();
23604
+ var isLastPeriod = index === periods.length - 1;
23605
+ // se valida que el último período no supere el año actual
23606
+ if (isLastPeriod && value && numValue > currentYear) {
23607
+ return; // no actualizar si supera el año actual
23608
+ }
23609
+ updatePeriod(index, 'hasta', value);
23610
+ }, className: "w-full px-3 py-2 pr-10 border rounded-lg focus:outline-none focus:ring-2 focus:border-transparent transition-all duration-200 hover:border-gray-400 ".concat(period.desde && period.hasta && !isValidRange(period.desde, period.hasta, dateType)
23611
+ ? 'border-red-500 focus:ring-red-500'
23612
+ : 'border-gray-300 focus:ring-blue-500') }), periods.length > 1 && (jsxRuntime.jsx("button", { type: "button", onClick: function () { return removePeriod(index); }, className: "absolute right-2 top-1/2 transform -translate-y-1/2 text-red-500 hover:text-red-700 transition-colors", title: "Eliminar per\u00EDodo", children: jsxRuntime.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }) })] }), index > 0 && ((_a = periods[index - 1]) === null || _a === void 0 ? void 0 : _a.hasta) && period.desde && !isValidRange(periods[index - 1].hasta, period.desde, dateType) && (jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: "El inicio debe ser posterior o igual al final del rango anterior" })), period.desde && period.hasta && !isValidRange(period.desde, period.hasta, dateType) && (jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: "El a\u00F1o final debe ser posterior o igual al inicial" }))] }, index));
23613
+ }), jsxRuntime.jsx("div", { className: "w-full", children: jsxRuntime.jsx("button", { type: "button", onClick: addPeriod, className: "w-full px-3 py-2 text-sm bg-gray-100 text-gray-700 border border-gray-300 rounded-md hover:bg-gray-200 transition-colors", children: "+ Agregar rango" }) })] }))] }));
23614
+ };
23615
+ // se calcula la cantidad total de meses de los períodos seleccionados (para tags P)
23616
+ function calcularMesesDePeriodos(valor) {
23617
+ console.log('@@@calcularMesesDePeriodos valor:', valor);
23618
+ if (!valor)
23619
+ return 0;
23620
+ var dayPattern = /^\d{2}\/\d{2}\/\d{4}$/;
23621
+ var monthPattern = /^\d{2}\/\d{4}$/;
23622
+ var yearPattern = /^\d{4}$/;
23623
+ var parseDay = function (s) {
23624
+ var _a = s.split('/').map(function (x) { return Number(x); }), dd = _a[0], mm = _a[1], yyyy = _a[2];
23625
+ return { y: yyyy, m: mm, d: dd };
23626
+ };
23627
+ var monthsDiffInclusive = function (y1, m1, y2, m2) { return (y2 - y1) * 12 + (m2 - m1) + 1; };
23628
+ var parts = valor.split('|').map(function (p) { return p.trim(); }).filter(Boolean);
23629
+ var total = 0;
23630
+ for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
23631
+ var p = parts_1[_i];
23632
+ var _a = p.split(' - ').map(function (x) { return (x || '').trim(); }), desde = _a[0], hasta = _a[1];
23633
+ if (!desde || !hasta)
23634
+ continue;
23635
+ if (dayPattern.test(desde) && dayPattern.test(hasta)) {
23636
+ var a = parseDay(desde);
23637
+ var b = parseDay(hasta);
23638
+ total += monthsDiffInclusive(a.y, a.m, b.y, b.m);
23639
+ }
23640
+ else if (monthPattern.test(desde) && monthPattern.test(hasta)) {
23641
+ var _b = desde.split('/').map(Number), m1 = _b[0], y1 = _b[1];
23642
+ var _c = hasta.split('/').map(Number), m2 = _c[0], y2 = _c[1];
23643
+ total += monthsDiffInclusive(y1, m1, y2, m2);
23644
+ }
23645
+ else if (yearPattern.test(desde) && yearPattern.test(hasta)) {
23646
+ var y1 = Number(desde);
23647
+ var y2 = Number(hasta);
23648
+ total += (y2 - y1 + 1) * 12;
23649
+ }
23650
+ }
23651
+ console.log('@@@calcularMesesDePeriodos meses:', total);
23652
+ return total;
23653
+ }
23654
+ // se verifica si un período está completo (tiene ambas fechas)
23655
+ function isPeriodComplete(valor) {
23656
+ if (!valor)
23657
+ return false;
23658
+ // patrones válidos: día (dd/mm/yyyy), mes (mm/yyyy), año (yyyy)
23659
+ var dayPattern = /^\d{2}\/\d{2}\/\d{4}$/;
23660
+ var monthPattern = /^\d{2}\/\d{4}$/;
23661
+ var yearPattern = /^\d{4}$/;
23662
+ // si es un valor único (no contiene ' - ' ni '|'), está completo si coincide con alguno de los formatos
23663
+ if (!valor.includes(' - ') && !valor.includes('|')) {
23664
+ var v = valor.trim();
23665
+ return dayPattern.test(v) || monthPattern.test(v) || yearPattern.test(v);
23666
+ }
23667
+ // si contiene períodos, se verifica que cada uno tenga ambas fechas
23668
+ var periods = valor.split('|');
23669
+ return periods.every(function (period) {
23670
+ var trimmedPeriod = period.trim();
23671
+ if (!trimmedPeriod.includes(' - '))
23672
+ return false;
23673
+ var _a = trimmedPeriod.split(' - '), desde = _a[0], hasta = _a[1];
23674
+ var d = (desde || '').trim();
23675
+ var h = (hasta || '').trim();
23676
+ var isValidSide = function (s) { return dayPattern.test(s) || monthPattern.test(s) || yearPattern.test(s); };
23677
+ return !!d && !!h && isValidSide(d) && isValidSide(h);
23678
+ });
23679
+ }
23680
+
23681
+ // se normaliza el input a números y una sola coma
23682
+ var normalizeAmount = function (text) {
23683
+ // permite dígitos y comas
23684
+ var onlyNumbersAndComma = text.replace(/[^0-9,]/g, '');
23685
+ // deja solo la primera coma si hubiera más de una
23686
+ var seenComma = false;
23687
+ var result = '';
23688
+ for (var _i = 0, onlyNumbersAndComma_1 = onlyNumbersAndComma; _i < onlyNumbersAndComma_1.length; _i++) {
23689
+ var ch = onlyNumbersAndComma_1[_i];
23690
+ if (ch === ',') {
23691
+ if (!seenComma) {
23692
+ result += ch;
23693
+ seenComma = true;
23694
+ }
23695
+ }
23696
+ else {
23697
+ result += ch;
23698
+ }
23699
+ }
23700
+ return result;
23701
+ };
23702
+ var AmountComponent = function (_a) {
23703
+ var label = _a.label, value = _a.value, onChange = _a.onChange, placeholder = _a.placeholder;
23704
+ var handleChange = React.useCallback(function (e) {
23705
+ var normalized = normalizeAmount(e.target.value);
23706
+ onChange(normalized);
23707
+ }, [onChange]);
23708
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("label", { className: "inline-block px-2 py-1 text-sm font-medium rounded ".concat(value ? 'text-green-800 bg-green-100' : 'text-orange-800'), style: value ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: label }), jsxRuntime.jsx("input", { type: "text", inputMode: "decimal", value: value, onChange: handleChange, placeholder: placeholder, className: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400" })] }));
23709
+ };
23710
+
23711
+ // se convierte YYYY-MM-DD -> dd/mm/yyyy
23712
+ var toDDMMYYYY = function (yyyyMMdd) {
23713
+ if (!yyyyMMdd)
23714
+ return '';
23715
+ var _a = yyyyMMdd.split('-'), yyyy = _a[0], mm = _a[1], dd = _a[2];
23716
+ if (!yyyy || !mm || !dd)
23717
+ return yyyyMMdd;
23718
+ return "".concat(dd.padStart(2, '0'), "/").concat(mm.padStart(2, '0'), "/").concat(yyyy);
23719
+ };
23720
+ // se convierte dd/mm/yyyy -> YYYY-MM-DD
23721
+ var toYYYYMMDD = function (ddMMyyyy) {
23722
+ if (!ddMMyyyy)
23723
+ return '';
23724
+ var _a = ddMMyyyy.split('/'), dd = _a[0], mm = _a[1], yyyy = _a[2];
23725
+ if (!dd || !mm || !yyyy)
23726
+ return ddMMyyyy;
23727
+ return "".concat(yyyy, "-").concat(mm.padStart(2, '0'), "-").concat(dd.padStart(2, '0'));
23728
+ };
23729
+ var DateComponent = function (_a) {
23730
+ var label = _a.label, value = _a.value, onChange = _a.onChange;
23731
+ var inputValue = value ? toYYYYMMDD(value) : '';
23732
+ var handleChange = function (e) {
23733
+ var v = e.target.value; // YYYY-MM-DD
23734
+ onChange(toDDMMYYYY(v)); // guarda dd/mm/yyyy
23735
+ };
23736
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("label", { className: "inline-block px-2 py-1 text-sm font-medium rounded ".concat(value ? 'text-green-800 bg-green-100' : 'text-orange-800'), style: value ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: label }), jsxRuntime.jsx("input", { type: "date", value: inputValue, onChange: handleChange, className: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400" })] }));
23737
+ };
23738
+
23739
+ // se normaliza a entero positivo (> 0)
23740
+ var normalizePositiveInt = function (text) {
23741
+ var digits = text.replace(/[^0-9]/g, '');
23742
+ if (!digits)
23743
+ return '';
23744
+ // elimina ceros a la izquierda
23745
+ var normalized = String(parseInt(digits, 10));
23746
+ // si parseInt da NaN o 0, devolver vacío (no válido)
23747
+ if (!normalized || normalized === '0' || normalized === 'NaN')
23748
+ return '';
23749
+ return normalized;
23750
+ };
23751
+ var NumberComponent = function (_a) {
23752
+ var label = _a.label, value = _a.value, onChange = _a.onChange, placeholder = _a.placeholder;
23753
+ var handleChange = React.useCallback(function (e) {
23754
+ var normalized = normalizePositiveInt(e.target.value);
23755
+ onChange(normalized);
23756
+ }, [onChange]);
23757
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("label", { className: "inline-block px-2 py-1 text-sm font-medium rounded ".concat(value ? 'text-green-800 bg-green-100' : 'text-orange-800'), style: value ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: label }), jsxRuntime.jsx("input", { type: "number", min: 1, step: 1, inputMode: "numeric", value: value, onChange: handleChange, placeholder: placeholder, className: "w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 hover:border-gray-400" })] }));
23758
+ };
23759
+
23760
+ var ConstruirHechoInfraccionalModal = function (_a) {
23761
+ var isOpen = _a.isOpen, onClose = _a.onClose, onSave = _a.onSave, nombreTrabajador = _a.nombreTrabajador, hechoInfraccionalDataProp = _a.hechoInfraccionalData, loading = _a.loading, hechoInfraccionalDataSaved = _a.hechoInfraccionalDataSaved, _b = _a.numeroTrabajadoresConstatados, numeroTrabajadoresConstatados = _b === void 0 ? 0 : _b;
23762
+ console.log('hechoInfraccionalDataProp:', hechoInfraccionalDataProp);
23763
+ // se manejan los estados internos para la carga de datos
23764
+ var _c = React.useState(null), hechoInfraccionalData = _c[0], setHechoInfraccionalData = _c[1];
23765
+ var _d = React.useState(false), isSaving = _d[0], setIsSaving = _d[1];
23766
+ var _e = React.useState({
23767
+ previsualizacion: '',
23768
+ elementos: {},
23769
+ }), formData = _e[0], setFormData = _e[1];
23770
+ var _f = React.useState(''), textoOriginal = _f[0], setTextoOriginal = _f[1];
23771
+ // se guarda un mapeo de código en mayúscula -> case original del texto_base
23772
+ var _g = React.useState({}), tagCaseMap = _g[0], setTagCaseMap = _g[1];
23773
+ var ensureObservationTag = function (data) {
23774
+ var _a, _b;
23775
+ if (!(data === null || data === void 0 ? void 0 : data.data))
23776
+ return data;
23777
+ var clonedData = data;
23778
+ var currentText = clonedData.data.texto_base || '';
23779
+ var hasObservationInText = /\(O\)/.test(currentText);
23780
+ if (!hasObservationInText) {
23781
+ var needsSpace = currentText && !currentText.endsWith(' ');
23782
+ clonedData.data.texto_base = "".concat(currentText).concat(needsSpace ? ' ' : '', "(O)");
23783
+ }
23784
+ if (!Array.isArray(clonedData.data.elementos)) {
23785
+ clonedData.data.elementos = [];
23786
+ }
23787
+ var hasObservationElement = clonedData.data.elementos.some(function (elemento) { return elemento.codigo === 'O'; });
23788
+ if (!hasObservationElement) {
23789
+ var lastElement = clonedData.data.elementos[clonedData.data.elementos.length - 1];
23790
+ var newId = lastElement ? lastElement.id + 1 : 1;
23791
+ var newHechoId = lastElement ? lastElement.hecho_id : ((_b = (_a = clonedData.data) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null);
23792
+ clonedData.data.elementos.push({
23793
+ id: newId,
23794
+ hecho_id: newHechoId,
23795
+ codigo: 'O',
23796
+ texto_placeholder: 'Ingrese observaciones generales... ',
23797
+ tipo_dato: 'texto',
23798
+ es_multiple: false,
23799
+ es_obligatorio: false,
23800
+ opciones: [],
23801
+ });
23802
+ }
23803
+ return clonedData;
23804
+ };
23805
+ // se sincroniza el dato entregado por el padre
23806
+ React.useEffect(function () {
23807
+ if (isOpen) {
23808
+ var dataClone = hechoInfraccionalDataProp
23809
+ ? JSON.parse(JSON.stringify(hechoInfraccionalDataProp))
23810
+ : null;
23811
+ var enhancedData = dataClone ? ensureObservationTag(dataClone) : null;
23812
+ setHechoInfraccionalData(enhancedData);
23813
+ }
23814
+ }, [isOpen, hechoInfraccionalDataProp]);
23815
+ // se limpian los datos cuando el modal se cierra
23816
+ React.useEffect(function () {
23817
+ if (!isOpen) {
23818
+ setHechoInfraccionalData(null);
23819
+ setFormData({
23820
+ previsualizacion: '',
23821
+ elementos: {},
23822
+ });
23823
+ setTextoOriginal('');
23824
+ setTagCaseMap({});
23825
+ setIsSaving(false);
23826
+ }
23827
+ }, [isOpen]);
23828
+ // se extraen los tags del texto base preservando mayúsculas/minúsculas
23829
+ var extractTagsFromText = function (text) {
23830
+ // se usa un regex más específico que NO detecta (a) cuando está dentro de una palabra
23831
+ // busca patrones como (H1), (P), (T1) pero NO (a) dentro de "trabajador(a)"
23832
+ var tagRegex = /(?<!\w)\(([A-Za-z]\d*)\)(?!\w)/g;
23833
+ var matches = [];
23834
+ var match;
23835
+ while ((match = tagRegex.exec(text)) !== null) {
23836
+ matches.push(match[1]); // se preserva el case original
23837
+ }
23838
+ return matches;
23839
+ };
23840
+ // se extraen todos los tags del estado actual (incluyendo opciones seleccionadas)
23841
+ var extractAllTagsFromCurrentState = function () {
23842
+ var allTags = new Set();
23843
+ // se agregan los tags del texto base
23844
+ var baseTags = extractTagsFromText(textoOriginal);
23845
+ baseTags.forEach(function (tag) { return allTags.add(tag); });
23846
+ // se agregan los tags de las opciones seleccionadas
23847
+ Object.values(formData.elementos).forEach(function (valor) {
23848
+ if (valor) {
23849
+ var tagsInValue = extractTagsFromText(valor);
23850
+ tagsInValue.forEach(function (tag) { return allTags.add(tag); });
23851
+ }
23852
+ });
23853
+ return Array.from(allTags);
23854
+ };
23855
+ // se resetea cuando se abre el modal
23856
+ React.useEffect(function () {
23857
+ if (isOpen) {
23858
+ // se resetea inmediatamente cuando se abre el modal
23859
+ setFormData({
23860
+ previsualizacion: '',
23861
+ elementos: {},
23862
+ });
23863
+ setTextoOriginal('');
23864
+ }
23865
+ }, [isOpen]);
23866
+ // se cargan los datos cuando se abre el modal
23867
+ React.useEffect(function () {
23868
+ if (hechoInfraccionalData === null || hechoInfraccionalData === void 0 ? void 0 : hechoInfraccionalData.data) {
23869
+ var elementosIniciales_1 = {};
23870
+ var textoBase = hechoInfraccionalData.data.texto_base || '';
23871
+ var caseMap_1 = {};
23872
+ // se extrae el mapeo de case del texto_base
23873
+ var tagsInText = extractTagsFromText(textoBase);
23874
+ tagsInText.forEach(function (tag) {
23875
+ var upperTag = tag.toUpperCase();
23876
+ // se guarda el case original del texto_base usando la clave en mayúscula
23877
+ caseMap_1[upperTag] = tag;
23878
+ });
23879
+ // se inicializan todos los elementos disponibles (se muestran dinámicamente según necesidad)
23880
+ if (hechoInfraccionalData.data.elementos) {
23881
+ hechoInfraccionalData.data.elementos.forEach(function (elemento) {
23882
+ // la API devuelve el código en mayúscula, se usa como clave
23883
+ elementosIniciales_1[elemento.codigo.toUpperCase()] = '';
23884
+ // se reemplaza [TRABAJADOR] y [FECHA] en las opciones del elemento
23885
+ if (elemento.opciones) {
23886
+ elemento.opciones.forEach(function (opcion) {
23887
+ opcion.texto_visible = replaceTrabajadorTag(opcion.texto_visible);
23888
+ opcion.texto_visible = replaceFechaTag(opcion.texto_visible);
23889
+ opcion.texto_visible = replaceNumeroTrabajadoresConstatadosTag(opcion.texto_visible);
23890
+ // Tags como (T1)(T2) solo en opciones: inicializar claves y case como en front002
23891
+ extractTagsFromText(opcion.texto_visible).forEach(function (tag) {
23892
+ var upperTag = tag.toUpperCase();
23893
+ if (!elementosIniciales_1[upperTag]) {
23894
+ elementosIniciales_1[upperTag] = '';
23895
+ }
23896
+ if (!caseMap_1[upperTag]) {
23897
+ caseMap_1[upperTag] = tag;
23898
+ }
23899
+ });
23900
+ });
23901
+ }
23902
+ });
23903
+ }
23904
+ // se agregan elementos especiales (como P, M, F y N) que no están en la API
23905
+ tagsInText.forEach(function (tag) {
23906
+ var upperTag = tag.toUpperCase();
23907
+ var treatAsDate = isDateOverrideForPeriodTag(tag);
23908
+ var isSpecial = treatAsDate ||
23909
+ isPeriodTag(tag) ||
23910
+ isAmountTag(tag) ||
23911
+ isDateTag(tag) ||
23912
+ /^N\d*$/i.test(tag);
23913
+ if (isSpecial && !elementosIniciales_1[upperTag]) {
23914
+ elementosIniciales_1[upperTag] = '';
23915
+ }
23916
+ });
23917
+ // si hay data previamente guardada, sobreescribir valores
23918
+ console.log('hechoInfraccionalDataSaved:', { hechoInfraccionalDataSaved: hechoInfraccionalDataSaved });
23919
+ var elementosFinales = __assign({}, elementosIniciales_1);
23920
+ if (hechoInfraccionalDataSaved === null || hechoInfraccionalDataSaved === void 0 ? void 0 : hechoInfraccionalDataSaved.elementos) {
23921
+ elementosFinales = __assign(__assign({}, elementosIniciales_1), Object.fromEntries(Object.entries(hechoInfraccionalDataSaved.elementos).map(function (_a) {
23922
+ var k = _a[0], v = _a[1];
23923
+ return [
23924
+ k.toUpperCase(),
23925
+ String(v),
23926
+ ];
23927
+ })));
23928
+ }
23929
+ // reconstruir previsualización desde el texto base y elementos finales
23930
+ var previsualizacionInicial = rebuildTextFromOriginal(textoBase, elementosFinales);
23931
+ // se mantiene el texto base con los tags especiales para el coloreado
23932
+ setFormData({
23933
+ previsualizacion: previsualizacionInicial,
23934
+ elementos: elementosFinales,
23935
+ });
23936
+ setTextoOriginal(textoBase);
23937
+ setTagCaseMap(caseMap_1);
23938
+ }
23939
+ else {
23940
+ // se resetea cuando no hay datos
23941
+ setFormData({
23942
+ previsualizacion: '',
23943
+ elementos: {},
23944
+ });
23945
+ setTextoOriginal('');
23946
+ setTagCaseMap({});
23947
+ }
23948
+ }, [hechoInfraccionalData, hechoInfraccionalDataSaved]);
23949
+ // se detecta si un tag es de período
23950
+ var isPeriodTag = function (tag) {
23951
+ return /^P\d*$/i.test(tag);
23952
+ };
23953
+ // se detecta si un tag es de monto
23954
+ var isAmountTag = function (tag) {
23955
+ return /^M\d*$/i.test(tag);
23956
+ };
23957
+ // se detecta si un tag es de fecha específica (F)
23958
+ var isDateTag = function (tag) {
23959
+ return /^F\d*$/i.test(tag);
23960
+ };
23961
+ // si aparece "fecha(tag)" o "día(tag)" y el tag es de período (P), se interpreta como fecha (F)
23962
+ var isDateOverrideForPeriodTag = function (tag) {
23963
+ if (!isPeriodTag(tag))
23964
+ return false;
23965
+ var baseTag = tag.replace(/\d+$/, ''); // P2, P3 -> P
23966
+ var pattern = new RegExp("(?:fecha|(?:el\\s+)?d[i\u00ED]a)\\s*\\(\\s*".concat(baseTag, "\\s*\\)"), 'i');
23967
+ // buscar en el texto base
23968
+ if (pattern.test(textoOriginal)) {
23969
+ return true;
23970
+ }
23971
+ // buscar en los valores seleccionados (por ejemplo dentro de H2)
23972
+ for (var _i = 0, _a = Object.values(formData.elementos); _i < _a.length; _i++) {
23973
+ var valor = _a[_i];
23974
+ if (typeof valor === 'string' && pattern.test(valor)) {
23975
+ return true;
23976
+ }
23977
+ }
23978
+ return false;
23979
+ };
23980
+ // si aparece "año(tag)" y el tag es de período (P), se interpreta como número (año)
23981
+ var isYearOverrideForPeriodTag = function (tag) {
23982
+ if (!isPeriodTag(tag))
23983
+ return false;
23984
+ var baseTag = tag.replace(/\d+$/, ''); // P2, P3 -> P
23985
+ var pattern = new RegExp("a(?:\u00F1|n)os*(s*".concat(baseTag, "s*)"), 'i');
23986
+ // prueba directa con acento y sin acento
23987
+ if (pattern.test(textoOriginal))
23988
+ return true;
23989
+ var normalize = function (s) { return s.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); };
23990
+ var textoSinAcentos = normalize(textoOriginal);
23991
+ var patternNoAccent = new RegExp("anos*(s*".concat(baseTag, "s*)"), 'i');
23992
+ if (patternNoAccent.test(textoSinAcentos))
23993
+ return true;
23994
+ // fallback por inclusión simple
23995
+ var low = textoOriginal.toLowerCase();
23996
+ if (low.includes("a\u00F1o (".concat(baseTag.toLowerCase(), ")")) ||
23997
+ low.includes("a\u00F1o(".concat(baseTag.toLowerCase(), ")")))
23998
+ return true;
23999
+ var lowNoAccent = textoSinAcentos.toLowerCase();
24000
+ if (lowNoAccent.includes("ano (".concat(baseTag.toLowerCase(), ")")) ||
24001
+ lowNoAccent.includes("ano(".concat(baseTag.toLowerCase(), ")")))
24002
+ return true;
24003
+ for (var _i = 0, _a = Object.values(formData.elementos); _i < _a.length; _i++) {
24004
+ var valor = _a[_i];
24005
+ if (typeof valor === 'string') {
24006
+ if (pattern.test(valor))
24007
+ return true;
24008
+ var valorSinAcentos = normalize(valor);
24009
+ if (patternNoAccent.test(valorSinAcentos))
24010
+ return true;
24011
+ var vlow = valor.toLowerCase();
24012
+ if (vlow.includes("a\u00F1o (".concat(baseTag.toLowerCase(), ")")) ||
24013
+ vlow.includes("a\u00F1o(".concat(baseTag.toLowerCase(), ")")))
24014
+ return true;
24015
+ var vlowNoAccent = valorSinAcentos.toLowerCase();
24016
+ if (vlowNoAccent.includes("ano (".concat(baseTag.toLowerCase(), ")")) ||
24017
+ vlowNoAccent.includes("ano(".concat(baseTag.toLowerCase(), ")")))
24018
+ return true;
24019
+ }
24020
+ }
24021
+ return false;
24022
+ };
24023
+ // se detecta si un tag es numérico (N)
24024
+ var isNumberTag = function (tag) {
24025
+ return /^N\d*$/i.test(tag);
24026
+ };
24027
+ // se reemplaza el tag [TRABAJADOR] con el nombre del trabajador
24028
+ var replaceTrabajadorTag = function (text) {
24029
+ return text.replace(/\[TRABAJADOR\]/g, nombreTrabajador);
24030
+ };
24031
+ var replaceNumeroTrabajadoresConstatadosTag = function (text) {
24032
+ return text.replace(/\[NUMEROTRABAJADORESCONSTATADOS\]/g, String(numeroTrabajadoresConstatados));
24033
+ };
24034
+ // se obtiene la fecha actual en formato dd/mm/yyyy
24035
+ var getFechaActual = function () {
24036
+ var hoy = new Date();
24037
+ var dia = hoy.getDate().toString().padStart(2, '0');
24038
+ var mes = (hoy.getMonth() + 1).toString().padStart(2, '0');
24039
+ var año = hoy.getFullYear();
24040
+ return "".concat(dia, "/").concat(mes, "/").concat(año);
24041
+ };
24042
+ function formatearMilesSinDecimales(valor) {
24043
+ var numero = Number(String(valor)
24044
+ .replace(/\./g, '') // quita puntos
24045
+ .replace(',', ''));
24046
+ return numero.toLocaleString('es-CL', {
24047
+ minimumFractionDigits: 0,
24048
+ maximumFractionDigits: 0,
24049
+ });
24050
+ }
24051
+ // se calcula la suma de meses considerando todos los tags P del formulario (excluye overrides a fecha o año)
24052
+ var calcularMesesTotales = function () {
24053
+ var tags = extractAllTagsFromCurrentState().filter(function (t) { return isPeriodTag(t) && !isDateOverrideForPeriodTag(t) && !isYearOverrideForPeriodTag(t); });
24054
+ var total = 0;
24055
+ tags.forEach(function (t) {
24056
+ var v = formData.elementos[t.toUpperCase()];
24057
+ if (v)
24058
+ total += calcularMesesDePeriodos(v);
24059
+ });
24060
+ return total;
24061
+ };
24062
+ // se reemplaza el tag [FECHA] con la fecha actual
24063
+ var replaceFechaTag = function (text) {
24064
+ return text.replace(/\[FECHA\]/g, getFechaActual());
24065
+ };
24066
+ // se manejan los cambios en elementos
24067
+ var handleElementoChange = function (codigo, valor) {
24068
+ setFormData(function (prev) {
24069
+ var nuevosElementos = __assign({}, prev.elementos);
24070
+ // se preserva el valor tal cual, sin normalizar a mayúsculas
24071
+ // solo se normalizan tags internos que NO son 'h' o 'H' solos
24072
+ var valorProcesado = valor;
24073
+ if (!isPeriodTag(codigo)) {
24074
+ // se convierten tags a mayúsculas excepto (h) que debe preservarse
24075
+ valorProcesado = valor.replace(/\(([a-z]\d*)\)/g, function (match, tag) {
24076
+ if (tag === 'h')
24077
+ return match; // se preserva (h) minúscula
24078
+ return "(".concat(tag.toUpperCase(), ")");
24079
+ });
24080
+ }
24081
+ if (isAmountTag(codigo)) {
24082
+ valorProcesado = '$' + formatearMilesSinDecimales(valor);
24083
+ }
24084
+ // se actualiza el elemento seleccionado
24085
+ var codigoUpper = codigo.toUpperCase();
24086
+ nuevosElementos[codigoUpper] = valorProcesado;
24087
+ // si se cambió un elemento padre, se resetean todos los elementos hijos
24088
+ // que ya no están presentes en el nuevo valor seleccionado
24089
+ if (valorProcesado) {
24090
+ var tagsEnNuevoValor_1 = extractTagsFromText(valorProcesado);
24091
+ var tagsEnValorAnterior = extractTagsFromText(prev.elementos[codigoUpper] || '');
24092
+ // se encuentran los tags que estaban en el valor anterior pero no en el nuevo
24093
+ var tagsAResetear = tagsEnValorAnterior.filter(function (tag) { return !tagsEnNuevoValor_1.includes(tag); });
24094
+ // se resetean los elementos que ya no son válidos
24095
+ tagsAResetear.forEach(function (tag) {
24096
+ nuevosElementos[tag.toUpperCase()] = '';
24097
+ });
24098
+ }
24099
+ else {
24100
+ // si se limpió el valor, se resetean todos los elementos hijos
24101
+ var tagsEnValorAnterior = extractTagsFromText(prev.elementos[codigoUpper] || '');
24102
+ tagsEnValorAnterior.forEach(function (tag) {
24103
+ nuevosElementos[tag.toUpperCase()] = '';
24104
+ });
24105
+ }
24106
+ // se reconstruye la previsualización desde el texto original
24107
+ var newPrevisualizacion = rebuildTextFromOriginal(textoOriginal, nuevosElementos);
24108
+ return __assign(__assign({}, prev), { elementos: nuevosElementos, previsualizacion: newPrevisualizacion });
24109
+ });
24110
+ };
24111
+ // se procesan los tags anidados en un valor
24112
+ var processNestedTags = function (text, elementos) {
24113
+ var result = text;
24114
+ var hasChanges = true;
24115
+ var iterations = 0;
24116
+ var maxIterations = 5; // se previenen bucles infinitos
24117
+ while (hasChanges && iterations < maxIterations) {
24118
+ hasChanges = false;
24119
+ iterations++;
24120
+ var tagRegex = /\(([A-Za-z]\d*)\)/g;
24121
+ var match = void 0;
24122
+ while ((match = tagRegex.exec(result)) !== null) {
24123
+ var fullMatch = match[0], codigo = match[1];
24124
+ // se busca el valor usando mayúscula (como vienen de la API)
24125
+ var codigoUpper = codigo.toUpperCase();
24126
+ var valor = elementos[codigoUpper];
24127
+ if (valor) {
24128
+ var valorFormateado = valor;
24129
+ if (isPeriodTag(codigo)) {
24130
+ valorFormateado = formatPeriodsForReplacement(valor);
24131
+ }
24132
+ else if (isAmountTag(codigo)) {
24133
+ valorFormateado = valor;
24134
+ }
24135
+ else {
24136
+ // se preserva el case, solo se normalizan tags internos excepto (h)
24137
+ valorFormateado = valor.replace(/\(([a-z]\d*)\)/g, function (match, tag) {
24138
+ if (tag === 'h')
24139
+ return match;
24140
+ return "(".concat(tag.toUpperCase(), ")");
24141
+ });
24142
+ }
24143
+ // se escapan caracteres especiales del regex
24144
+ var escapedTag = fullMatch.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
24145
+ var beforeReplace = result;
24146
+ console.log('processNestedTags', { fullMatch: fullMatch, codigo: codigo, valor: valor, valorFormateado: valorFormateado });
24147
+ result = result.replace(new RegExp(escapedTag, 'g'), valorFormateado);
24148
+ if (beforeReplace !== result) {
24149
+ hasChanges = true;
24150
+ }
24151
+ }
24152
+ }
24153
+ }
24154
+ return result;
24155
+ };
24156
+ // se reconstruye el texto desde el original con reemplazos anidados
24157
+ var rebuildTextFromOriginal = function (originalText, elementos) {
24158
+ var result = originalText;
24159
+ var hasChanges = true;
24160
+ var iterations = 0;
24161
+ var maxIterations = 10; // se previenen bucles infinitos
24162
+ // se itera hasta que no haya más reemplazos que hacer
24163
+ while (hasChanges && iterations < maxIterations) {
24164
+ hasChanges = false;
24165
+ iterations++;
24166
+ // Regex corregido: ahora incluye [NUMEROTRABAJADORESCONSTATADOS]
24167
+ var tagRegex = /((?<!\w)\(([A-Za-z]\d*)\)(?!\w)|\[TRABAJADOR\]|\[FECHA\]|\[NUMEROTRABAJADORESCONSTATADOS\])/g;
24168
+ var match = void 0;
24169
+ var replacements = [];
24170
+ // se busca el tag (O) y se elimina en caso de no tener valor
24171
+ var OBSERVATION_TAG = 'O';
24172
+ if (!elementos[OBSERVATION_TAG]) {
24173
+ result = result.replace(/\(O\)/g, '');
24174
+ }
24175
+ while ((match = tagRegex.exec(result)) !== null) {
24176
+ var fullMatch = match[0];
24177
+ // Tags especiales
24178
+ if (fullMatch === '[TRABAJADOR]' ||
24179
+ fullMatch === '[FECHA]' ||
24180
+ fullMatch === '[NUMEROTRABAJADORESCONSTATADOS]') {
24181
+ var replacement = fullMatch === '[TRABAJADOR]'
24182
+ ? nombreTrabajador
24183
+ : fullMatch === '[FECHA]'
24184
+ ? getFechaActual()
24185
+ : String(numeroTrabajadoresConstatados);
24186
+ replacements.push({ tag: fullMatch, replacement: replacement });
24187
+ }
24188
+ else {
24189
+ // Tag normal (H1), (T1), etc.
24190
+ var codigoSinParentesis = fullMatch.slice(1, -1); // (H1) -> H1
24191
+ var codigoUpper = codigoSinParentesis.toUpperCase();
24192
+ var valor = elementos[codigoUpper];
24193
+ if (valor) {
24194
+ var valorFormateado = valor;
24195
+ if (isPeriodTag(codigoSinParentesis)) {
24196
+ valorFormateado = formatPeriodsForReplacement(valor);
24197
+ }
24198
+ else if (isAmountTag(codigoSinParentesis)) {
24199
+ valorFormateado = valor;
24200
+ }
24201
+ else {
24202
+ // se preservan tags internos
24203
+ valorFormateado = valor.replace(/\(([a-z]\d*)\)/g, function (match, tag) {
24204
+ if (tag === 'h')
24205
+ return match;
24206
+ return "(".concat(tag.toUpperCase(), ")");
24207
+ });
24208
+ }
24209
+ // no se procesa recursivamente aquí, se hará en la siguiente iteración
24210
+ replacements.push({ tag: fullMatch, replacement: valorFormateado });
24211
+ }
24212
+ }
24213
+ }
24214
+ // se aplican los reemplazos
24215
+ replacements.forEach(function (_a) {
24216
+ var tag = _a.tag, replacement = _a.replacement;
24217
+ if (result.includes(tag)) {
24218
+ var escapedTag = tag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
24219
+ var beforeReplace = result;
24220
+ result = result.replace(new RegExp(escapedTag, 'g'), replacement);
24221
+ if (beforeReplace !== result) {
24222
+ hasChanges = true;
24223
+ }
24224
+ }
24225
+ });
24226
+ }
24227
+ return result;
24228
+ };
24229
+ // se renderiza el texto con colores
24230
+ var renderTextWithColors = function (text) {
24231
+ if (!text)
24232
+ return null;
24233
+ var processNestedReplacements = function (inputText) {
24234
+ var parts = [];
24235
+ var lastIndex = 0;
24236
+ // se buscan los tags en el texto (incluyendo [TRABAJADOR] y [FECHA])
24237
+ // se usa el mismo regex mejorado que NO detecta (a) dentro de palabras
24238
+ var tagRegex = /((?<!\w)\([A-Za-z]\d*\)(?!\w)|\[TRABAJADOR\]|\[FECHA\]|\[NUMEROTRABAJADORESCONSTATADOS\])/g;
24239
+ var match;
24240
+ while ((match = tagRegex.exec(inputText)) !== null) {
24241
+ var fullMatch = match[0];
24242
+ var startIndex = match.index;
24243
+ // se agrega el texto antes del tag
24244
+ if (startIndex > lastIndex) {
24245
+ parts.push(inputText.slice(lastIndex, startIndex));
24246
+ }
24247
+ // se determina si es un tag especial [TRABAJADOR] o [FECHA]
24248
+ if (fullMatch === '[TRABAJADOR]' ||
24249
+ fullMatch === '[FECHA]' ||
24250
+ fullMatch === '[NUMEROTRABAJADORESCONSTATADOS]') {
24251
+ // tags especiales reemplazados - color verde
24252
+ var replacement = fullMatch === '[TRABAJADOR]'
24253
+ ? nombreTrabajador
24254
+ : fullMatch === '[FECHA]'
24255
+ ? getFechaActual()
24256
+ : String(numeroTrabajadoresConstatados);
24257
+ parts.push(jsxRuntime.jsx("span", { className: "rounded bg-green-100 px-1 text-green-800", children: replacement }, "".concat(fullMatch, "-").concat(startIndex)));
24258
+ }
24259
+ else {
24260
+ // se maneja como tag normal (H1), (T1), etc.
24261
+ var codigo = fullMatch.slice(1, -1); // remover paréntesis preservando case
24262
+ var codigoUpper = codigo.toUpperCase(); // se usa mayúscula para buscar en elementos
24263
+ // se busca el valor usando el código en mayúscula (como vienen de la API)
24264
+ var valor = formData.elementos[codigoUpper];
24265
+ if (valor) {
24266
+ var valorProcesado = void 0;
24267
+ if (isPeriodTag(codigoUpper)) {
24268
+ valorProcesado = formatPeriodsForReplacement(valor);
24269
+ }
24270
+ else if (isAmountTag(codigoUpper)) {
24271
+ valorProcesado = valor;
24272
+ }
24273
+ else {
24274
+ valorProcesado = processNestedTags(valor, formData.elementos);
24275
+ }
24276
+ // texto reemplazado - color verde
24277
+ parts.push(jsxRuntime.jsx("span", { className: "rounded bg-green-100 px-1 text-green-800", children: valorProcesado }, "".concat(codigo, "-").concat(startIndex)));
24278
+ }
24279
+ else {
24280
+ // tag sin reemplazar - color naranja (muestra el case original del texto_base)
24281
+ parts.push(jsxRuntime.jsx("span", { className: "rounded bg-orange-100 px-1 text-orange-800", children: fullMatch }, "".concat(codigo, "-").concat(startIndex)));
24282
+ }
24283
+ }
24284
+ lastIndex = startIndex + fullMatch.length;
24285
+ }
24286
+ // se agrega el texto restante
24287
+ if (lastIndex < inputText.length) {
24288
+ parts.push(inputText.slice(lastIndex));
24289
+ }
24290
+ return parts.length > 0 ? parts : inputText;
24291
+ };
24292
+ return processNestedReplacements(text);
24293
+ };
24294
+ // se renderiza el elemento según su tipo
24295
+ var renderElemento = function (elemento) {
24296
+ var tag = elemento.codigo;
24297
+ var valor = formData.elementos[tag.toUpperCase()] || '';
24298
+ var isDateOv = isDateOverrideForPeriodTag(tag);
24299
+ var isYearOv = isYearOverrideForPeriodTag(tag);
24300
+ // prioridad: fecha (override), año (override), luego período
24301
+ if (isDateTag(tag) || (isPeriodTag(tag) && isDateOv)) {
24302
+ return (jsxRuntime.jsx(DateComponent, { label: "(".concat(tag, ")"), value: valor, onChange: function (value) { return handleElementoChange(tag, value); } }, tag));
24303
+ }
24304
+ if (isPeriodTag(tag) && isYearOv) {
24305
+ return (jsxRuntime.jsx(NumberComponent, { label: "(".concat(tag, ")"), value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, placeholder: 'Ingrese año (4 dígitos)' }, tag));
24306
+ }
24307
+ if (isPeriodTag(tag) && !isDateOv && !isYearOv) {
24308
+ return (jsxRuntime.jsx(PeriodComponent, { label: tag, value: valor, onChange: function (value) { return handleElementoChange(tag, value); } }, tag));
24309
+ }
24310
+ if (isAmountTag(tag)) {
24311
+ return (jsxRuntime.jsx(AmountComponent, { label: "(".concat(tag, ")"), value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, placeholder: elemento.texto_placeholder || 'Ingrese el monto' }, tag));
24312
+ }
24313
+ if (/^N\d*$/i.test(tag)) {
24314
+ return (jsxRuntime.jsx(NumberComponent, { label: "(".concat(tag, ")"), value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, placeholder: elemento.texto_placeholder || 'Ingrese un número mayor a 0' }, tag));
24315
+ }
24316
+ if (elemento.tipo_dato === 'seleccion') {
24317
+ // se obtiene el case original del texto_base para este tag
24318
+ // el tag ya viene en mayúscula de la API, se busca en el mapa (clave siempre en mayúscula)
24319
+ var originalCase = tagCaseMap[tag.toUpperCase()] || tag;
24320
+ // se detecta si es selección múltiple (H mayúscula) o simple (h minúscula) según el case original
24321
+ var isMultiple = originalCase === 'H' ||
24322
+ (originalCase.length > 1 && originalCase[0] === 'H' && /^\d+$/.test(originalCase.slice(1)));
24323
+ return (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsxs("label", { className: "inline-block rounded px-2 py-1 text-sm font-medium ".concat(valor ? 'bg-green-100 text-green-800' : 'text-orange-800'), style: valor ? {} : { backgroundColor: 'rgb(254, 238, 221)' }, children: ["(", originalCase, ")", isMultiple && jsxRuntime.jsx("span", { className: "ml-1 text-xs", children: "(m\u00FAltiple)" })] }), isMultiple ? (jsxRuntime.jsx(MultiSelectorComponent, { value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, options: elemento.opciones, placeholder: "Seleccionar ".concat(originalCase, "...") })) : (jsxRuntime.jsx(SelectorComponent, { value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, options: elemento.opciones, placeholder: "Seleccionar ".concat(originalCase, "...") }))] }, tag));
24324
+ }
24325
+ // por defecto, se renderiza como texto
24326
+ return (jsxRuntime.jsx(TextComponent, { label: tag !== 'O' ? "(".concat(tag, ")") : '(Observaciones)', value: valor, onChange: function (value) { return handleElementoChange(tag, value); }, placeholder: elemento.texto_placeholder || "Ingrese ".concat(tag, "..."), rows: 3 }, tag));
24327
+ };
24328
+ // se verifica si todos los tags están completos
24329
+ var areAllTagsComplete = function () {
24330
+ // se obtienen todos los tags del estado actual (incluidos anidados y renombrados como P2, P3, ...)
24331
+ var allTags = extractAllTagsFromCurrentState();
24332
+ var indexOfObservations = allTags.indexOf('O');
24333
+ if (indexOfObservations !== -1) {
24334
+ allTags.splice(indexOfObservations, 1);
24335
+ }
24336
+ // se verifica que todos los tags tengan valores
24337
+ return allTags.every(function (tag) {
24338
+ // se normaliza el tag a mayúscula para buscar en elementos (como vienen de la API)
24339
+ var tagUpper = tag.toUpperCase();
24340
+ if (isPeriodTag(tag) && !isDateOverrideForPeriodTag(tag)) {
24341
+ // para períodos, se verifica que tengan valor y estén completos
24342
+ var valor = formData.elementos[tagUpper];
24343
+ if (!valor || valor.trim() === '')
24344
+ return false;
24345
+ // se verifica que los períodos estén completos (tengan ambas fechas)
24346
+ return isPeriodComplete(valor);
24347
+ }
24348
+ else if (isPeriodTag(tag) && isDateOverrideForPeriodTag(tag)) {
24349
+ // si es override a fecha, requiere una fecha simple dd/mm/yyyy
24350
+ var valor = (formData.elementos[tagUpper] || '').trim();
24351
+ return /^\d{2}\/\d{2}\/\d{4}$/.test(valor);
24352
+ }
24353
+ else if (isNumberTag(tag)) {
24354
+ var valor = (formData.elementos[tagUpper] || '').trim();
24355
+ if (!valor)
24356
+ return false;
24357
+ // entero positivo > 0
24358
+ return /^[1-9]\d*$/.test(valor);
24359
+ }
24360
+ else if (isAmountTag(tag)) {
24361
+ var valor = (formData.elementos[tagUpper] || '').trim();
24362
+ if (valor == '$0')
24363
+ return false;
24364
+ return true;
24365
+ }
24366
+ else {
24367
+ // para otros elementos, se verifica que tengan valor
24368
+ return formData.elementos[tagUpper] && formData.elementos[tagUpper].trim() !== '';
24369
+ }
24370
+ });
24371
+ };
24372
+ // se verifica si un período está completo (tiene ambas fechas)
24373
+ // se maneja el guardado
24374
+ var handleSave = function () { return __awaiter$1(void 0, void 0, void 0, function () {
24375
+ var textoFinal, meses;
24376
+ return __generator(this, function (_a) {
24377
+ setIsSaving(true);
24378
+ try {
24379
+ console.log('formData to save:', formData);
24380
+ console.log('textoOriginal to save:', textoOriginal);
24381
+ textoFinal = rebuildTextFromOriginal(textoOriginal, formData.elementos);
24382
+ console.log('textoFinal to save:', textoFinal);
24383
+ meses = calcularMesesTotales();
24384
+ onSave({ texto: textoFinal, mesesPeriodos: meses, formData: formData });
24385
+ }
24386
+ finally {
24387
+ setIsSaving(false);
24388
+ }
24389
+ return [2 /*return*/];
24390
+ });
24391
+ }); };
24392
+ if (!isOpen)
24393
+ return null;
24394
+ return (jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-end justify-end bg-black bg-opacity-50", children: jsxRuntime.jsxs("div", { className: "flex h-full w-1/2 flex-col bg-white", children: [jsxRuntime.jsx("div", { className: "border-b border-gray-200 bg-white px-6 py-12", children: jsxRuntime.jsx("h2", { className: "text-4xl font-bold text-blue", children: "Construir hecho infraccional" }) }), jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: jsxRuntime.jsx("form", { className: "flex h-full flex-col", children: jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: jsxRuntime.jsx("div", { className: "flex h-full flex-col", children: jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: jsxRuntime.jsxs("div", { className: "flex h-full flex-col", children: [jsxRuntime.jsx("div", { className: "flex-shrink-0 border-b border-gray-200 p-4", children: jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mb-2 text-sm font-bold text-gray-700", children: "Previsualizaci\u00F3n:" }), jsxRuntime.jsx("div", { className: "min-h-[60px] rounded-lg border border-gray-300 bg-white p-3 text-gray-800", children: renderTextWithColors(textoOriginal) })] }) }), jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", style: { zIndex: 1 }, children: jsxRuntime.jsx("div", { className: "rounded-lg p-3", children: loading ? (jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsxRuntime.jsx("div", { className: "border-blue-600 h-12 w-12 animate-spin rounded-full border-b-2" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-600", children: "Cargando hecho infraccional..." })] }) })) : (jsxRuntime.jsx("div", { className: "space-y-4", children: (function () {
24395
+ var _a;
24396
+ // se extraen todos los tags (base + anidados)
24397
+ var allTags = extractAllTagsFromCurrentState();
24398
+ // se filtran los elementos que están en los tags detectados
24399
+ // se normaliza comparando en mayúscula porque la API devuelve códigos en mayúscula
24400
+ var allTagsUpper = allTags.map(function (t) { return t.toUpperCase(); });
24401
+ var elementosFromAPI = (((_a = hechoInfraccionalData === null || hechoInfraccionalData === void 0 ? void 0 : hechoInfraccionalData.data) === null || _a === void 0 ? void 0 : _a.elementos) || []).filter(function (elemento) {
24402
+ if (!allTagsUpper.includes(elemento.codigo.toUpperCase()))
24403
+ return false;
24404
+ // si algún tag P está overrideado en el texto base, también debemos excluirlo
24405
+ if (isPeriodTag(elemento.codigo) &&
24406
+ (isDateOverrideForPeriodTag(elemento.codigo) ||
24407
+ isYearOverrideForPeriodTag(elemento.codigo))) {
24408
+ return false; // evitar duplicar como periodo si será fecha o año
24409
+ }
24410
+ return true;
24411
+ });
24412
+ // se agregan elementos especiales que no están en la API (como P, M, F y N)
24413
+ var elementosEspeciales = allTags
24414
+ .filter(function (tag) {
24415
+ var _a, _b;
24416
+ return (isPeriodTag(tag) ||
24417
+ isAmountTag(tag) ||
24418
+ isDateTag(tag) ||
24419
+ isNumberTag(tag)) &&
24420
+ !((_b = (_a = hechoInfraccionalData === null || hechoInfraccionalData === void 0 ? void 0 : hechoInfraccionalData.data) === null || _a === void 0 ? void 0 : _a.elementos) === null || _b === void 0 ? void 0 : _b.some(function (e) {
24421
+ return e.codigo.toUpperCase() === tag.toUpperCase();
24422
+ }));
24423
+ })
24424
+ .map(function (tag) { return ({
24425
+ codigo: tag.toUpperCase(), // se normaliza a mayúscula como la API
24426
+ descripcion: "".concat(isPeriodTag(tag) ? 'Período' : isAmountTag(tag) ? 'Monto' : isDateTag(tag) ? 'Fecha' : 'Número', " ").concat(tag),
24427
+ tipo_dato: isPeriodTag(tag) &&
24428
+ !isDateOverrideForPeriodTag(tag) &&
24429
+ !isYearOverrideForPeriodTag(tag)
24430
+ ? 'periodo'
24431
+ : isAmountTag(tag)
24432
+ ? 'monto'
24433
+ : isDateTag(tag) ||
24434
+ (isPeriodTag(tag) && isDateOverrideForPeriodTag(tag))
24435
+ ? 'fecha'
24436
+ : 'numero',
24437
+ opciones: [],
24438
+ }); });
24439
+ var codigosYaRenderizados = new Set(__spreadArray(__spreadArray([], elementosFromAPI, true), elementosEspeciales, true).map(function (e) {
24440
+ return e.codigo.toUpperCase();
24441
+ }));
24442
+ // Tags visibles (p. ej. T1, T2) sin fila en API: campo texto como front002
24443
+ var elementosTextoImplicitos = allTags
24444
+ .map(function (t) { return t.toUpperCase(); })
24445
+ .filter(function (u, i, arr) { return arr.indexOf(u) === i; })
24446
+ .filter(function (u) { return u !== 'O' && !codigosYaRenderizados.has(u); })
24447
+ .map(function (u) { return ({
24448
+ id: 0,
24449
+ codigo: u,
24450
+ texto_placeholder: undefined,
24451
+ tipo_dato: 'texto',
24452
+ es_multiple: false,
24453
+ es_obligatorio: false,
24454
+ opciones: [],
24455
+ }); });
24456
+ var elementosToRender = __spreadArray(__spreadArray(__spreadArray([], elementosFromAPI, true), elementosEspeciales, true), elementosTextoImplicitos, true);
24457
+ var elementosObservacion = elementosToRender.filter(function (elemento) { var _a; return ((_a = elemento.codigo) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === 'O'; });
24458
+ var elementosSinObservacion = elementosToRender.filter(function (elemento) { var _a; return ((_a = elemento.codigo) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== 'O'; });
24459
+ var elementosOrdenados = __spreadArray(__spreadArray([], elementosSinObservacion, true), elementosObservacion, true);
24460
+ return elementosOrdenados.map(function (elemento) {
24461
+ return renderElemento(elemento);
24462
+ });
24463
+ })() })) }) }), jsxRuntime.jsxs("div", { className: "mt-8 flex justify-between border-t border-gray-200 px-6 pb-6 pt-6", children: [jsxRuntime.jsx("button", { type: "button", className: "text-blue-600 hover:text-blue-800 border-blue-600 rounded-md border px-4 py-2 transition-colors", onClick: onClose, children: "Volver" }), jsxRuntime.jsx("button", { type: "button", disabled: loading || isSaving || !areAllTagsComplete(), className: "rounded-md px-4 py-2 transition-colors ".concat(loading || isSaving || !areAllTagsComplete()
24464
+ ? 'cursor-not-allowed bg-gray-400 text-gray-600'
24465
+ : 'hover:bg-blue-700 bg-blue text-white'), onClick: handleSave, children: isSaving ? 'Guardando...' : 'Guardar' })] })] }) }) }) }) }) })] }) }));
24466
+ };
24467
+
23205
24468
  Object.defineProperty(exports, "Flowbite", {
23206
24469
  enumerable: true,
23207
24470
  get: function () { return flowbiteReact.Flowbite; }
@@ -23211,6 +24474,7 @@ exports.Alert = Alert;
23211
24474
  exports.CheckboxInput = CheckboxInput;
23212
24475
  exports.Checklist = Checklist;
23213
24476
  exports.Common = Common;
24477
+ exports.ConstruirHechoInfraccionalModal = ConstruirHechoInfraccionalModal;
23214
24478
  exports.DatePicker = DatePicker;
23215
24479
  exports.DynamicInput = DynamicInput;
23216
24480
  exports.GenericForm = GenericForm;