@jvsoft/utils 1.0.0-alpha.7 → 1.0.0-alpha.9

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 (48) hide show
  1. package/directives/auto-select-first.directive.d.ts +13 -0
  2. package/directives/public-api.d.ts +1 -0
  3. package/fesm2022/jvsoft-utils-directives.mjs +72 -3
  4. package/fesm2022/jvsoft-utils-directives.mjs.map +1 -1
  5. package/fesm2022/jvsoft-utils-functions.mjs +1744 -0
  6. package/fesm2022/jvsoft-utils-functions.mjs.map +1 -0
  7. package/fesm2022/jvsoft-utils-interfaces.mjs +6 -0
  8. package/fesm2022/jvsoft-utils-interfaces.mjs.map +1 -0
  9. package/fesm2022/jvsoft-utils-pipes.mjs +345 -0
  10. package/fesm2022/jvsoft-utils-pipes.mjs.map +1 -0
  11. package/fesm2022/jvsoft-utils.mjs +72 -3
  12. package/fesm2022/jvsoft-utils.mjs.map +1 -1
  13. package/functions/index.d.ts +5 -0
  14. package/interfaces/index.d.ts +5 -0
  15. package/package.json +13 -1
  16. package/pipes/index.d.ts +5 -0
  17. package/public-api.d.ts +3 -3
  18. /package/{src/functions → functions}/base64.d.ts +0 -0
  19. /package/{src/functions → functions}/browser.d.ts +0 -0
  20. /package/{src/functions → functions}/crypto-js.d.ts +0 -0
  21. /package/{src/functions → functions}/date.d.ts +0 -0
  22. /package/{src/functions → functions}/dev-log.d.ts +0 -0
  23. /package/{src/functions → functions}/email.d.ts +0 -0
  24. /package/{src/functions → functions}/file.d.ts +0 -0
  25. /package/{src/functions → functions}/forms.d.ts +0 -0
  26. /package/{src/functions → functions}/http-client.d.ts +0 -0
  27. /package/{src/functions → functions}/local-storage.d.ts +0 -0
  28. /package/{src/functions → functions}/mat-form-controls/autocomplete.d.ts +0 -0
  29. /package/{src/functions → functions}/mat-form-controls/index.d.ts +0 -0
  30. /package/{src/functions → functions}/number.d.ts +0 -0
  31. /package/{src/functions → functions}/object-transformation.d.ts +0 -0
  32. /package/{src/functions → functions}/objects-arrays.d.ts +0 -0
  33. /package/{src/functions → functions}/public-api.d.ts +0 -0
  34. /package/{src/functions → functions}/string.d.ts +0 -0
  35. /package/{src/functions → functions}/sweetalert.d.ts +0 -0
  36. /package/{src/functions → functions}/utiles.d.ts +0 -0
  37. /package/{src/interfaces → interfaces}/datos.d.ts +0 -0
  38. /package/{src/interfaces → interfaces}/public-api.d.ts +0 -0
  39. /package/{src/pipes → pipes}/data-en-lista.pipe.d.ts +0 -0
  40. /package/{src/pipes → pipes}/date-diff-string.pipe.d.ts +0 -0
  41. /package/{src/pipes → pipes}/display-with.pipe.d.ts +0 -0
  42. /package/{src/pipes → pipes}/filtro.pipe.d.ts +0 -0
  43. /package/{src/pipes → pipes}/form-control-is-required.pipe.d.ts +0 -0
  44. /package/{src/pipes → pipes}/json-parse.pipe.d.ts +0 -0
  45. /package/{src/pipes → pipes}/no-sanitize.pipe.d.ts +0 -0
  46. /package/{src/pipes → pipes}/public-api.d.ts +0 -0
  47. /package/{src/pipes → pipes}/tipo-valor-funcion.pipe.d.ts +0 -0
  48. /package/{src/pipes → pipes}/zero-fill.pipe.d.ts +0 -0
@@ -0,0 +1,1744 @@
1
+ import { inject, DestroyRef } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { tap, startWith, debounceTime, isObservable, switchMap, of, finalize } from 'rxjs';
4
+ import { map } from 'rxjs/operators';
5
+ import { Buffer } from 'buffer';
6
+ import CryptoJS from 'crypto-js';
7
+ import { formatDate } from '@angular/common';
8
+ import { saveAs } from 'file-saver';
9
+ import { Validators, FormGroup, FormControl, FormArray } from '@angular/forms';
10
+ import { ReactiveFormConfig } from '@rxweb/reactive-form-validators';
11
+ import moment from 'moment';
12
+ import swal from 'sweetalert2';
13
+ import { jwtDecode } from 'jwt-decode';
14
+
15
+ function deepMerge(source, target) {
16
+ // Crea un clon profundo sin usar JSON.parse(JSON.stringify)
17
+ let cloneSource = deepClone(source);
18
+ if (typeof target !== 'object' || target === null) {
19
+ return target;
20
+ }
21
+ if (typeof cloneSource !== 'object' || cloneSource === null) {
22
+ cloneSource = Array.isArray(target) ? [] : {};
23
+ }
24
+ for (const key of Object.keys(target)) {
25
+ const targetValue = target[key];
26
+ const sourceValue = cloneSource[key];
27
+ if (typeof targetValue === 'object' && targetValue !== null && !Array.isArray(targetValue)) {
28
+ cloneSource[key] = deepMerge(sourceValue, targetValue);
29
+ }
30
+ else {
31
+ cloneSource[key] = targetValue;
32
+ }
33
+ }
34
+ return cloneSource; // Retorna el clon y no modifica el original
35
+ }
36
+ // Función de clonación profunda que maneja funciones, fechas y otros tipos especiales
37
+ function deepClone(obj) {
38
+ if (obj === null || typeof obj !== 'object') {
39
+ return obj; // Devuelve el valor si no es un objeto
40
+ }
41
+ // Manejar instancias de Date
42
+ if (obj instanceof Date) {
43
+ return new Date(obj.getTime());
44
+ }
45
+ // Manejar funciones devolviendo una copia directa
46
+ if (typeof obj === 'function') {
47
+ return obj.bind({}); // Devuelve una copia de la función enlazada a un contexto vacío
48
+ }
49
+ // Crear un nuevo objeto o array
50
+ const clonedObj = Array.isArray(obj) ? [] : {};
51
+ // Clonar recursivamente las propiedades del objeto
52
+ for (const key in obj) {
53
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
54
+ clonedObj[key] = deepClone(obj[key]);
55
+ }
56
+ }
57
+ return clonedObj;
58
+ }
59
+ /**
60
+ * Busca un elemento en un array o jerarquía de objetos según un campo y valor especificado.
61
+ *
62
+ * @returns El elemento encontrado o undefined si no existe.
63
+ */
64
+ function buscarPorCampo(datosFn) {
65
+ for (const item of datosFn.items) {
66
+ // Verifica si el campo coincide con el valor
67
+ if (item[datosFn.campo] === datosFn.valor) {
68
+ return item;
69
+ }
70
+ // Verifica si hay un campo hijo y si es un array
71
+ if (datosFn.campoHijo && item[datosFn.campoHijo] && Array.isArray(item[datosFn.campoHijo])) {
72
+ // Realiza la búsqueda recursiva en el campo hijo
73
+ const encontrado = buscarPorCampo({
74
+ items: item[datosFn.campoHijo], // Asegura el tipo correcto
75
+ campo: datosFn.campo,
76
+ valor: datosFn.valor,
77
+ campoHijo: datosFn.campoHijo,
78
+ });
79
+ // Si se encuentra el valor en el campo hijo, retorna el resultado
80
+ if (encontrado) {
81
+ return encontrado;
82
+ }
83
+ }
84
+ }
85
+ // Si no se encuentra nada, retorna undefined
86
+ return undefined;
87
+ }
88
+ function sumarPropiedades(item, campos) {
89
+ const datosSumar = campos.map(campo => (item[campo] * 1));
90
+ return datosSumar.reduce((a, b) => a + b, 0);
91
+ }
92
+ function esNumero(value) {
93
+ return !isNaN(Number(value));
94
+ }
95
+ function sumarObjetos(arrayObjetos, campos) {
96
+ return arrayObjetos.reduce((accumulator, item) => {
97
+ campos.forEach(campo => {
98
+ const valor = Number(item[campo]);
99
+ if (!isNaN(valor)) {
100
+ accumulator[campo] = (accumulator[campo] ?? 0) + valor;
101
+ }
102
+ });
103
+ return accumulator;
104
+ }, {});
105
+ }
106
+ function getUniqueValues(array) {
107
+ return array.filter((currentValue, index, arr) => (arr.indexOf(currentValue) === index));
108
+ }
109
+ function getUniqueValuesByProperty(objetos, campo) {
110
+ const objetosUnicos = {};
111
+ objetos.forEach(objeto => {
112
+ // Verificar si el objeto tiene el campo especificado
113
+ // @ts-ignore
114
+ if (objeto.hasOwnProperty(campo)) {
115
+ // @ts-ignore
116
+ const valorCampo = objeto[campo];
117
+ // Utilizar el valor del campo como clave en un objeto para asegurar que no haya duplicados
118
+ objetosUnicos[valorCampo] = objeto;
119
+ }
120
+ });
121
+ // Convertir el objeto de claves únicas de vuelta a una lista de objetos
122
+ return Object.values(objetosUnicos);
123
+ }
124
+ function ordenarArray(array, numeros = false, sentido = 'ASC') {
125
+ if (numeros) {
126
+ if (sentido != 'ASC') {
127
+ return array.sort((a, b) => b - a);
128
+ }
129
+ return array.sort((a, b) => a - b);
130
+ }
131
+ return array.sort((a, b) => (a > b) ? 1 : ((b > a) ? -1 : 0));
132
+ }
133
+ function ordenarPorPropiedad(objData, propiedad, /**@deprecated*/ numeros = false) {
134
+ return ordenarPorPropiedades(objData, { propiedades: [propiedad], direcciones: ['asc'] });
135
+ }
136
+ function ordenarPorPropiedades(arr, options) {
137
+ const { propiedades, direcciones = [] } = options;
138
+ const orden = direcciones.map(d => d === 'desc' ? -1 : 1);
139
+ return [...arr].sort((a, b) => {
140
+ return propiedades.reduce((acc, propiedad, index) => {
141
+ if (acc !== 0)
142
+ return acc; // Si ya hay diferencia, no seguir comparando
143
+ const aValue = a[propiedad];
144
+ const bValue = b[propiedad];
145
+ if (typeof aValue === 'string' && typeof bValue === 'string') {
146
+ return aValue.localeCompare(bValue) * orden[index]; // 🔹 Comparación alfabética
147
+ }
148
+ if (typeof aValue === 'number' && typeof bValue === 'number') {
149
+ return (aValue - bValue) * orden[index]; // 🔹 Comparación numérica
150
+ }
151
+ return 0; // En caso de valores no comparables
152
+ }, 0);
153
+ });
154
+ }
155
+ function groupBy(array, key) {
156
+ const keyFn = key instanceof Function ? key : (obj) => obj[key];
157
+ return array.reduce((objectsByKeyValue, obj) => {
158
+ const value = keyFn(obj);
159
+ objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
160
+ return objectsByKeyValue;
161
+ }, {});
162
+ }
163
+ function nestGroupsBy(arr, properties) {
164
+ const fnGroupBy = (conversions, property2) => {
165
+ return conversions.reduce((acc, obj) => {
166
+ const key = obj[property2];
167
+ if (!acc[key]) {
168
+ acc[key] = [];
169
+ }
170
+ acc[key].push(obj);
171
+ return acc;
172
+ }, {});
173
+ };
174
+ properties = Array.from(properties);
175
+ if (properties.length === 1) {
176
+ return fnGroupBy(arr, properties[0]);
177
+ }
178
+ const property = properties.shift();
179
+ const grouped = fnGroupBy(arr, property);
180
+ Object.keys(grouped).forEach(key => {
181
+ grouped[key] = nestGroupsBy(grouped[key], Array.from(properties));
182
+ });
183
+ return grouped;
184
+ }
185
+ /**
186
+ * Obtiene un valor de un objeto usando una ruta de propiedad anidada.
187
+ *
188
+ * @param obj - Objeto de entrada.
189
+ * @param path - Ruta en formato punto (ej: "cliente.orden").
190
+ * @returns El valor encontrado o undefined si no existe.
191
+ */
192
+ function getValueByPath(obj, path) {
193
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
194
+ }
195
+ /**
196
+ * Retorna el valor máximo del campo especificado (incluso anidado) en un arreglo de objetos.
197
+ *
198
+ * @param data - Lista de objetos a procesar.
199
+ * @param campo - Nombre del campo a evaluar, puede ser anidado (ej. "campo.orden").
200
+ * @param incrementar - Si es true, retorna el valor máximo + 1. Por defecto es true.
201
+ * @returns El valor máximo encontrado, posiblemente incrementado.
202
+ */
203
+ function obtenerUltimoOrden(data, campo, incrementar = true) {
204
+ const max = data.reduce((mayor, item) => {
205
+ const valor = Number(getValueByPath(item, campo)) || 0;
206
+ return valor > mayor ? valor : mayor;
207
+ }, 0);
208
+ return incrementar ? max + 1 : max;
209
+ }
210
+ /**
211
+ * Elimina una o varias columnas específicas (por índice) de una tabla representada como array de arrays.
212
+ *
213
+ * @param data - Array de filas (cada fila debe ser un array).
214
+ * @param columnIndex - Índice o lista de índices de las columnas a eliminar.
215
+ * @returns Nuevo array con las columnas eliminadas.
216
+ */
217
+ function eliminarColumnaPorIndex(data, columnIndex) {
218
+ if (!Array.isArray(data))
219
+ return [];
220
+ // Normalizar a array único y ordenado (descendente para evitar reindexación al splicing)
221
+ const indices = Array.isArray(columnIndex)
222
+ ? [...new Set(columnIndex)].filter((i) => (typeof i === 'number' && i >= 0)).sort((a, b) => b - a)
223
+ : [columnIndex];
224
+ return data.map((row) => {
225
+ if (!Array.isArray(row))
226
+ return row;
227
+ const newRow = [...row];
228
+ for (const index of indices) {
229
+ if (index >= 0 && index < newRow.length) {
230
+ newRow.splice(index, 1);
231
+ }
232
+ }
233
+ return newRow;
234
+ });
235
+ }
236
+ function eliminarDuplicados(array, claves) {
237
+ const unicos = new Map();
238
+ for (const item of array) {
239
+ const claveUnica = claves && claves.length > 0
240
+ ? claves.map(k => item[k]).join('|')
241
+ : JSON.stringify(item);
242
+ if (!unicos.has(claveUnica)) {
243
+ unicos.set(claveUnica, item);
244
+ }
245
+ }
246
+ return Array.from(unicos.values());
247
+ }
248
+ function eliminarElementos(origen, elementosAEliminar, claves) {
249
+ const clavesSet = new Set();
250
+ for (const item of elementosAEliminar) {
251
+ const key = claves && claves.length > 0
252
+ ? claves.map(k => item[k]).join('|')
253
+ : JSON.stringify(item);
254
+ clavesSet.add(key);
255
+ }
256
+ return origen.filter(item => {
257
+ const key = claves && claves.length > 0
258
+ ? claves.map(k => item[k]).join('|')
259
+ : JSON.stringify(item);
260
+ return !clavesSet.has(key);
261
+ });
262
+ }
263
+ /**
264
+ * Filtra datos localmente según un valor de búsqueda
265
+ * @param data - Array de datos a filtrar
266
+ * @param value - Valor de búsqueda
267
+ * @param campoBuscar - Campo(s) por el cual buscar
268
+ * @returns Array filtrado
269
+ */
270
+ function filtrarDatosLocal(data, value, campoBuscar) {
271
+ if (!value)
272
+ return data;
273
+ const normalizar = (val) => val?.toString()?.toLowerCase() ?? '';
274
+ const esNum = !isNaN(Number(value));
275
+ return data.filter(item => {
276
+ const campos = Array.isArray(campoBuscar) ? campoBuscar : [campoBuscar];
277
+ return campos.some(campo => {
278
+ const campoVal = item[campo];
279
+ if (campoVal == null)
280
+ return false;
281
+ return esNum
282
+ ? campoVal.toString().includes(value.toString())
283
+ : normalizar(campoVal).includes(normalizar(value));
284
+ });
285
+ });
286
+ }
287
+
288
+ /**
289
+ * Intenta obtener el DestroyRef desde el llamador (objThis/control)
290
+ * o inyectándolo si estamos en un contexto de inyección.
291
+ */
292
+ function obtenerDestroyRef(caller, manualDRef, fnName = 'N/A') {
293
+ let dRef = manualDRef || caller?.['destroyRef'] || caller?.['_destroyRef'];
294
+ if (!dRef) {
295
+ try {
296
+ dRef = inject(DestroyRef, { optional: true });
297
+ }
298
+ catch (e) {
299
+ console.warn(`${fnName}: Falló inject(DestroyRef) (fuera del contexto de inyección). Pasa el destroyRef explícitamente o decláralo en el componente para habilitar la limpieza.`);
300
+ }
301
+ }
302
+ return dRef ?? undefined;
303
+ }
304
+ function mostrarValorEnBusqueda(campos, idxSel) {
305
+ const impDataMostrar = () => {
306
+ let vD;
307
+ if (campos.campoId == '*object*' || campos.campoId == '*objeto*') {
308
+ console.log(campos);
309
+ vD = campos.lista.find((x) => JSON.stringify(x).trim() == JSON.stringify(idxSel).trim());
310
+ console.log(vD);
311
+ }
312
+ else {
313
+ vD = campos.lista.find((x) => x[campos.campoId] == idxSel);
314
+ }
315
+ if (!vD && campos.opcExtra) {
316
+ console.log('eval ', campos.opcExtra);
317
+ if (campos.campoId == '*object*' || campos.campoId == '*objeto*') {
318
+ console.log(campos);
319
+ vD = campos.opcExtra.find((x) => JSON.stringify(x).trim() == JSON.stringify(idxSel).trim());
320
+ console.log(vD);
321
+ }
322
+ else {
323
+ vD = campos.opcExtra.find((x) => x[campos.campoId] == idxSel);
324
+ }
325
+ }
326
+ if (vD) {
327
+ let txtFinal = '';
328
+ if (Array.isArray(campos.campoValue)) {
329
+ campos.campoValue.forEach((vCampo, idx) => {
330
+ txtFinal += (vD[vCampo] ?? '');
331
+ if (idx < campos.campoValue.length - 1) {
332
+ txtFinal += ' - ';
333
+ }
334
+ });
335
+ }
336
+ else {
337
+ txtFinal = vD[campos.campoValue] ?? '';
338
+ }
339
+ return txtFinal.trim();
340
+ }
341
+ else {
342
+ console.log('ASSSSS ----- SSSS ');
343
+ }
344
+ return '';
345
+ };
346
+ if (esNumero(idxSel)) {
347
+ if (idxSel > 0 && campos.lista?.length > 0) {
348
+ return impDataMostrar();
349
+ }
350
+ else if (idxSel && typeof idxSel == 'object') {
351
+ return impDataMostrar();
352
+ }
353
+ }
354
+ else {
355
+ if (campos.lista?.length > 0) {
356
+ return impDataMostrar();
357
+ }
358
+ }
359
+ return '';
360
+ }
361
+ /**
362
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
363
+ */
364
+ function changeSelectData(objThis, dataFiltro) {
365
+ const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectData');
366
+ objThis['filtrados'][dataFiltro.variableResultado] = dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
367
+ const varN = dataFiltro.data;
368
+ if (varN) {
369
+ if (value) {
370
+ return varN.map(x => x).filter(dat => {
371
+ if (Array.isArray(dataFiltro.campoBuscar)) {
372
+ let encontrado = false;
373
+ for (const vCampo of dataFiltro.campoBuscar) {
374
+ // console.log(vCampo, value, dat[vCampo]);
375
+ if (isNaN(Number(value))) {
376
+ // NO ES NUMERO
377
+ if (value && dat[vCampo] && dat[vCampo].toLowerCase().includes(value?.toString().toLowerCase())) {
378
+ encontrado = true;
379
+ break;
380
+ }
381
+ }
382
+ else {
383
+ if (value && dat[vCampo] && dat[vCampo].toString().includes(value?.toString())) {
384
+ encontrado = true;
385
+ break;
386
+ }
387
+ }
388
+ }
389
+ return encontrado;
390
+ }
391
+ else {
392
+ if (isNaN(Number(value))) {
393
+ return dat[dataFiltro.campoBuscar].toLowerCase().includes(value?.toString().toLowerCase());
394
+ }
395
+ else {
396
+ return dat[dataFiltro.campoBuscar].toString().includes(value?.toString());
397
+ }
398
+ }
399
+ });
400
+ }
401
+ return varN;
402
+ }
403
+ return false;
404
+ }));
405
+ }
406
+ /**
407
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
408
+ */
409
+ function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = null, destroyRef) {
410
+ // console.log(formControl);
411
+ // const formGroup = formControl.parent.controls;
412
+ // console.warn( Object.keys(formGroup).find(name => formControl === formGroup[name]) || null );
413
+ if (!campoFiltro) {
414
+ campoFiltro = tipo;
415
+ }
416
+ const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelect');
417
+ control['filtrados'][campoFiltro ?? '__'] = formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
418
+ // console.warn(value);
419
+ const partes = tipo.split('.');
420
+ let varN;
421
+ if (control['dataServidor']) {
422
+ varN = (partes.length > 1) ? control['dataServidor'][partes[0]][partes[1]] : control['dataServidor'][tipo];
423
+ }
424
+ else if (control['dataServidorSuscripcion']) {
425
+ varN = control['dataServidorSuscripcion'][tipo].getValue();
426
+ }
427
+ if (varN) {
428
+ if (value) {
429
+ return varN.map((x) => x).filter((dat) => {
430
+ if (Array.isArray(campoBuscar)) {
431
+ let encontrado = false;
432
+ for (const vCampo of campoBuscar) {
433
+ // console.log(vCampo, value, dat[vCampo]);
434
+ if (isNaN(Number(value))) {
435
+ // NO ES NUMERO
436
+ if (value && dat[vCampo] && dat[vCampo].toLowerCase().includes(value?.toString().toLowerCase())) {
437
+ encontrado = true;
438
+ break;
439
+ }
440
+ }
441
+ else {
442
+ if (value && dat[vCampo] && dat[vCampo].toString().includes(value?.toString())) {
443
+ encontrado = true;
444
+ break;
445
+ }
446
+ }
447
+ }
448
+ return encontrado;
449
+ }
450
+ else {
451
+ if (isNaN(Number(value))) {
452
+ return dat[campoBuscar].toLowerCase().includes(value?.toString().toLowerCase());
453
+ }
454
+ else {
455
+ return dat[campoBuscar].toString().includes(value?.toString());
456
+ }
457
+ }
458
+ });
459
+ }
460
+ return varN;
461
+ }
462
+ return false;
463
+ }));
464
+ }
465
+ /**
466
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
467
+ */
468
+ function changeSelectDataApi(objThis, dataFiltro) {
469
+ if (!dataFiltro.variableResultado) {
470
+ dataFiltro.variableResultado = dataFiltro.tipoReq;
471
+ }
472
+ const idFiltrado = dataFiltro.variableResultado;
473
+ const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectDataApi');
474
+ dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
475
+ objThis.filtrados[dataFiltro.variableResultado + 'tmp'] = isObservable(objThis.filtrados[idFiltrado]) ? [] : objThis.filtrados[idFiltrado] || [];
476
+ if (objThis.filtrados[idFiltrado] !== objThis.filtrados[idFiltrado + 'tmp']) {
477
+ objThis.filtrados[idFiltrado] = [];
478
+ }
479
+ objThis.isLoading = true;
480
+ }), switchMap(value => {
481
+ if (dataFiltro.campoId) {
482
+ const busquedaActual2 = objThis.filtrados[idFiltrado + 'tmp'].findIndex((item) => item[dataFiltro.campoId ?? '--'] === value);
483
+ if (busquedaActual2 >= 0) {
484
+ return of({ [dataFiltro.tipoReq]: objThis.filtrados[idFiltrado + 'tmp'] });
485
+ }
486
+ }
487
+ return !value || value.length < (dataFiltro.minLength ?? 3) ? [] : (dataFiltro.queryService.getDataMethod('GET', dataFiltro.tipoReq, {
488
+ ...(dataFiltro.dataExtra ?? {}),
489
+ ...(dataFiltro.dataExtraVariable ? Object.fromEntries(dataFiltro.dataExtraVariable.map((objData) => [objData.campo, objData.ctrlValue.value])) : {}),
490
+ txtBuscar: value,
491
+ }, dataFiltro.anonimo).pipe(finalize(() => objThis.isLoading = false)));
492
+ })).subscribe((data) => {
493
+ objThis.filtrados[idFiltrado] = data[dataFiltro.tipoReq] ?? [];
494
+ });
495
+ }
496
+ /**
497
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
498
+ */
499
+ function changeSelectApi(control, queryService, formControl, tipo, dataExtra = {}, dataExtraVariable = null, minLength = 1, anonimo = false, destroyRef) {
500
+ const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelectApi');
501
+ formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap((value) => {
502
+ control['filtrados'][tipo + 'tmp'] = isObservable(control['filtrados'][tipo]) ? [] : control['filtrados'][tipo];
503
+ if (control['filtrados'][tipo] != control['filtrados'][tipo + 'tmp']) {
504
+ control['filtrados'][tipo] = [];
505
+ }
506
+ control['isLoading'] = true;
507
+ }), switchMap(value => {
508
+ const formGroup = formControl.parent?.controls;
509
+ const nombreControl = Object.keys(formGroup).find(name => formControl === formGroup[name]) || null;
510
+ if (nombreControl && control['filtrados'][tipo + 'tmp'] && control['filtrados'][tipo + 'tmp'].length > 0) {
511
+ const busquedaActual = control['filtrados'][tipo + 'tmp'].findIndex((item) => item[nombreControl] == value);
512
+ if (busquedaActual >= 0) {
513
+ const vRet = {};
514
+ vRet[tipo] = control['filtrados'][tipo + 'tmp'];
515
+ control['isLoading'] = false;
516
+ return of(vRet);
517
+ }
518
+ }
519
+ if (!value || value.length < minLength) {
520
+ return [];
521
+ }
522
+ const dataExtraVariableData = {};
523
+ if (dataExtraVariable) {
524
+ // @ts-ignore
525
+ for (const objData of dataExtraVariable) {
526
+ dataExtraVariableData[objData.campo] = objData.ctrlValue.value;
527
+ }
528
+ }
529
+ return queryService.getDataMethod('GET', tipo, { ...dataExtra, ...dataExtraVariableData, ...{ txtBuscar: value } }, anonimo).pipe(finalize(() => {
530
+ control['isLoading'] = false;
531
+ }));
532
+ })).subscribe((data) => {
533
+ if (data[tipo] == undefined) {
534
+ control['filtrados'][tipo] = [];
535
+ }
536
+ else {
537
+ control['filtrados'][tipo] = data[tipo];
538
+ }
539
+ });
540
+ }
541
+ /**
542
+ * Comprueba si un valor es una Promesa
543
+ * @param valor - Valor a verificar
544
+ * @returns true si es una Promise
545
+ */
546
+ function esPromise(valor) {
547
+ return !!valor && typeof valor.then === 'function';
548
+ }
549
+ /**
550
+ * Selecciona todo el texto de un input
551
+ * @param event - Evento del input
552
+ */
553
+ function seleccionarTextoInput$1(event) {
554
+ event.target.select();
555
+ }
556
+ /**
557
+ * Función genérica para vincular un FormControl con datos desde API o Promise.
558
+ * Preparada para migrar a signals en el futuro.
559
+ */
560
+ /**
561
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
562
+ */
563
+ function changeSelectReformateado(config) {
564
+ const { objThis, tipoReq, formControl, queryService, campoId, minLength = 3, dataExtra = {}, dataExtraVariable = [], anonimo = false, variableResultado = tipoReq, destroyRef } = config;
565
+ const dRef = obtenerDestroyRef(objThis, destroyRef, 'changeSelectReformateado');
566
+ formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
567
+ objThis.filtrados[variableResultado + 'tmp'] = isObservable(objThis.filtrados[variableResultado])
568
+ ? []
569
+ : objThis.filtrados[variableResultado] || [];
570
+ if (objThis.filtrados[variableResultado] !== objThis.filtrados[variableResultado + 'tmp']) {
571
+ objThis.filtrados[variableResultado] = [];
572
+ }
573
+ objThis.isLoading = true;
574
+ }), switchMap(value => {
575
+ if (campoId) {
576
+ const existe = objThis.filtrados[variableResultado + 'tmp']
577
+ .findIndex((item) => item[campoId] === value);
578
+ if (existe >= 0) {
579
+ return of({ [tipoReq]: objThis.filtrados[variableResultado + 'tmp'] });
580
+ }
581
+ }
582
+ if (!value || value.length < minLength) {
583
+ objThis.isLoading = false;
584
+ return of({ [tipoReq]: [] });
585
+ }
586
+ const extraVars = Object.fromEntries(dataExtraVariable.map((v) => [v.campo, v.ctrlValue.value]));
587
+ const query = queryService.getDataMethod('GET', tipoReq, { ...dataExtra, ...extraVars, txtBuscar: value }, anonimo);
588
+ if (esPromise(query)) {
589
+ return query
590
+ .then((data) => ({ [tipoReq]: data[tipoReq] ?? [] }))
591
+ .finally(() => { objThis.isLoading = false; });
592
+ }
593
+ return query.pipe(finalize(() => { objThis.isLoading = false; }));
594
+ })).subscribe((data) => {
595
+ objThis.filtrados[variableResultado] = data[tipoReq] ?? [];
596
+ });
597
+ }
598
+
599
+ function seleccionarTextoInput(event) {
600
+ event.target.select();
601
+ }
602
+
603
+ /**
604
+ * Codifica un string a base64 (método legacy)
605
+ * @param val - String a codificar
606
+ * @returns String codificado en base64
607
+ * @deprecated Use encodeBase64String() en su lugar
608
+ */
609
+ function b64Encode(val) {
610
+ return Buffer.from(val, 'binary').toString('base64');
611
+ }
612
+ /**
613
+ * Decodifica un string desde base64 (método legacy)
614
+ * @param val - String en base64 a decodificar
615
+ * @returns String decodificado
616
+ * @deprecated Use decodeBase64String() en su lugar
617
+ */
618
+ function b64Decode(val) {
619
+ return Buffer.from(val, 'base64').toString('binary');
620
+ }
621
+ /**
622
+ * Codificar string a Base64 (UTF-8 seguro)
623
+ * @param str - String a codificar
624
+ * @returns String codificado en base64
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * const encoded = encodeBase64String('Hola Mundo ñ');
629
+ * // encoded: "SG9sYSBNdW5kbyDDsQ=="
630
+ * ```
631
+ */
632
+ function encodeBase64String(str) {
633
+ const encoder = new TextEncoder();
634
+ const bytes = encoder.encode(str);
635
+ let binary = '';
636
+ bytes.forEach(b => binary += String.fromCharCode(b));
637
+ return btoa(binary);
638
+ }
639
+ /**
640
+ * Decodificar Base64 a string (UTF-8 seguro)
641
+ * @param b64 - String en base64 a decodificar
642
+ * @returns String decodificado
643
+ *
644
+ * @example
645
+ * ```typescript
646
+ * const decoded = decodeBase64String('SG9sYSBNdW5kbyDDsQ==');
647
+ * // decoded: "Hola Mundo ñ"
648
+ * ```
649
+ */
650
+ function decodeBase64String(b64) {
651
+ const binary = atob(b64);
652
+ const bytes = new Uint8Array(binary.length);
653
+ for (let i = 0; i < binary.length; i++) {
654
+ bytes[i] = binary.charCodeAt(i);
655
+ }
656
+ const decoder = new TextDecoder();
657
+ return decoder.decode(bytes);
658
+ }
659
+ /**
660
+ * Codificar un objeto a base64 (UTF-8 seguro)
661
+ * @param obj - Objeto a codificar
662
+ * @returns String codificado en base64
663
+ *
664
+ * @example
665
+ * ```typescript
666
+ * const obj = { nombre: 'Juan', edad: 25 };
667
+ * const encoded = encodeBase64Object(obj);
668
+ * ```
669
+ */
670
+ function encodeBase64Object(obj) {
671
+ return encodeBase64String(JSON.stringify(obj));
672
+ }
673
+ /**
674
+ * Decodificar un base64 y obtener el objeto original
675
+ * @param b64 - String en base64 a decodificar
676
+ * @returns Objeto decodificado
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * const obj = decodeBase64Object<{ nombre: string, edad: number }>(encoded);
681
+ * // obj: { nombre: 'Juan', edad: 25 }
682
+ * ```
683
+ */
684
+ function decodeBase64Object(b64) {
685
+ return JSON.parse(decodeBase64String(b64));
686
+ }
687
+ /**
688
+ * Codificar archivo a Base64 (retorna solo el contenido, sin "data:...")
689
+ * @param file - Archivo o Blob a codificar
690
+ * @returns Promise con el string en base64
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * const file = event.target.files[0];
695
+ * const base64 = await encodeBase64File(file);
696
+ * // base64: "iVBORw0KGgoAAAANSUhEUgAA..."
697
+ * ```
698
+ */
699
+ function encodeBase64File(file) {
700
+ return new Promise((resolve, reject) => {
701
+ const reader = new FileReader();
702
+ reader.onload = () => {
703
+ const result = reader.result;
704
+ resolve(result.split(',')[1]); // quita el prefijo "data:...;base64,"
705
+ };
706
+ reader.onerror = reject;
707
+ reader.readAsDataURL(file);
708
+ });
709
+ }
710
+ /**
711
+ * Decodificar Base64 a Blob (para reconstruir archivos en Angular)
712
+ * @param b64 - String en base64
713
+ * @param mimeType - Tipo MIME del archivo (opcional)
714
+ * @returns Blob con el contenido decodificado
715
+ *
716
+ * @example
717
+ * ```typescript
718
+ * const blob = decodeBase64ToBlob(base64String, 'image/png');
719
+ * const url = URL.createObjectURL(blob);
720
+ * // Usar url para mostrar imagen o descargar
721
+ * ```
722
+ */
723
+ function decodeBase64ToBlob(b64, mimeType = 'application/octet-stream') {
724
+ const byteChars = atob(b64);
725
+ const byteNumbers = new Array(byteChars.length);
726
+ for (let i = 0; i < byteChars.length; i++) {
727
+ byteNumbers[i] = byteChars.charCodeAt(i);
728
+ }
729
+ return new Blob([new Uint8Array(byteNumbers)], { type: mimeType });
730
+ }
731
+
732
+ function getBrowserName() {
733
+ const agent = window.navigator.userAgent.toLowerCase();
734
+ switch (true) {
735
+ case agent.indexOf('edge') > -1:
736
+ return 'edge';
737
+ case agent.indexOf('opr') > -1 && !!window.opr:
738
+ return 'opera';
739
+ case agent.indexOf('chrome') > -1 && !!window.chrome:
740
+ return 'chrome';
741
+ case agent.indexOf('trident') > -1:
742
+ return 'ie';
743
+ case agent.indexOf('firefox') > -1:
744
+ return 'firefox';
745
+ case agent.indexOf('safari') > -1:
746
+ return 'safari';
747
+ default:
748
+ return 'other';
749
+ }
750
+ }
751
+
752
+ // import * as CryptoJS from 'crypto-js';
753
+ // var CryptoJS = require("crypto-js");
754
+ // Clave secreta (debe ser de 16, 24 o 32 caracteres)
755
+ const secretKey = CryptoJS.enc.Utf8.parse('JVSoftSecret@20615178350');
756
+ const iv = CryptoJS.enc.Utf8.parse('AnSalHuaJVSoft07'); // Debe ser de 16 bytes
757
+ // Función para encriptar texto
758
+ function encriptar(text) {
759
+ const encrypted = CryptoJS.AES.encrypt(text, secretKey, {
760
+ iv: iv,
761
+ mode: CryptoJS.mode.CBC,
762
+ padding: CryptoJS.pad.Pkcs7,
763
+ });
764
+ return encrypted.toString(); // Texto cifrado en Base64
765
+ }
766
+ // Función para desencriptar texto
767
+ function desencriptar(ciphertext) {
768
+ const decrypted = CryptoJS.AES.decrypt(ciphertext, secretKey, {
769
+ iv: iv,
770
+ mode: CryptoJS.mode.CBC,
771
+ padding: CryptoJS.pad.Pkcs7,
772
+ });
773
+ return decrypted.toString(CryptoJS.enc.Utf8);
774
+ }
775
+
776
+ function formatearFechaFormato(val, format = 'dd/MM/yyyy') {
777
+ return val ? formatDate(val, format, 'es-PE') : '';
778
+ }
779
+ function formatearFecha(val, hora = '00:00:00') {
780
+ if (val) {
781
+ if (val.length <= 10) {
782
+ val = val + ' ' + hora;
783
+ }
784
+ return new Date(val);
785
+ }
786
+ return val;
787
+ }
788
+ function formatearFechaCadena(fecha) {
789
+ const year = parseInt(fecha.substring(0, 4), 10);
790
+ const month = parseInt(fecha.substring(4, 6), 10) - 1;
791
+ const day = parseInt(fecha.substring(6, 8), 10);
792
+ return new Date(year, month, day);
793
+ }
794
+
795
+ /**
796
+ * Configuración global para las utilidades de logging
797
+ */
798
+ let isProductionMode = false;
799
+ /**
800
+ * Configura el modo de producción para las utilidades de logging
801
+ * @param production - true si está en modo producción, false para desarrollo
802
+ *
803
+ * @example
804
+ * ```typescript
805
+ * import { setProductionMode } from '@jvsoft/utils';
806
+ * import { environment } from './environments/environment';
807
+ *
808
+ * setProductionMode(environment.production);
809
+ * ```
810
+ */
811
+ function setProductionMode(production) {
812
+ isProductionMode = production;
813
+ }
814
+ /**
815
+ * Obtiene el estado actual del modo de producción
816
+ * @returns true si está en modo producción, false en desarrollo
817
+ */
818
+ function isProduction() {
819
+ return isProductionMode;
820
+ }
821
+ /**
822
+ * Muestra mensajes de log solo en modo desarrollo
823
+ * @param args - Argumentos a mostrar en consola
824
+ *
825
+ * @example
826
+ * ```typescript
827
+ * devLog('Usuario cargado:', usuario);
828
+ * devLog('Estado:', { activo: true, rol: 'admin' });
829
+ * ```
830
+ */
831
+ function devLog(...args) {
832
+ if (!isProductionMode) {
833
+ console.log(...args);
834
+ }
835
+ }
836
+ /**
837
+ * Muestra advertencias solo en modo desarrollo
838
+ * @param args - Argumentos a mostrar como advertencia
839
+ *
840
+ * @example
841
+ * ```typescript
842
+ * devWarn('Función deprecada, usar nuevaFuncion() en su lugar');
843
+ * ```
844
+ */
845
+ function devWarn(...args) {
846
+ if (!isProductionMode) {
847
+ console.warn(...args);
848
+ }
849
+ }
850
+ /**
851
+ * Muestra errores en consola (siempre, incluso en producción)
852
+ * @param args - Argumentos a mostrar como error
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * devError('Error al cargar datos:', error);
857
+ * ```
858
+ */
859
+ function devError(...args) {
860
+ console.error(...args);
861
+ }
862
+ /**
863
+ * Crea un grupo de logs solo en modo desarrollo
864
+ * @param label - Etiqueta del grupo
865
+ * @param collapsed - Si el grupo debe estar colapsado por defecto
866
+ *
867
+ * @example
868
+ * ```typescript
869
+ * devGroup('Datos del usuario');
870
+ * devLog('Nombre:', usuario.nombre);
871
+ * devLog('Email:', usuario.email);
872
+ * devGroupEnd();
873
+ * ```
874
+ */
875
+ function devGroup(label, collapsed = false) {
876
+ if (!isProductionMode) {
877
+ if (collapsed) {
878
+ console.groupCollapsed(label);
879
+ }
880
+ else {
881
+ console.group(label);
882
+ }
883
+ }
884
+ }
885
+ /**
886
+ * Cierra el grupo de logs actual
887
+ */
888
+ function devGroupEnd() {
889
+ if (!isProductionMode) {
890
+ console.groupEnd();
891
+ }
892
+ }
893
+ /**
894
+ * Muestra una tabla en consola solo en modo desarrollo
895
+ * @param data - Datos a mostrar en formato tabla
896
+ *
897
+ * @example
898
+ * ```typescript
899
+ * devTable([
900
+ * { nombre: 'Juan', edad: 25 },
901
+ * { nombre: 'María', edad: 30 }
902
+ * ]);
903
+ * ```
904
+ */
905
+ function devTable(data) {
906
+ if (!isProductionMode) {
907
+ console.table(data);
908
+ }
909
+ }
910
+ /**
911
+ * Inicia un temporizador solo en modo desarrollo
912
+ * @param label - Etiqueta del temporizador
913
+ *
914
+ * @example
915
+ * ```typescript
916
+ * devTime('carga-datos');
917
+ * // ... código a medir
918
+ * devTimeEnd('carga-datos'); // Muestra: carga-datos: 123.45ms
919
+ * ```
920
+ */
921
+ function devTime(label) {
922
+ if (!isProductionMode) {
923
+ console.time(label);
924
+ }
925
+ }
926
+ /**
927
+ * Finaliza un temporizador y muestra el tiempo transcurrido
928
+ * @param label - Etiqueta del temporizador
929
+ */
930
+ function devTimeEnd(label) {
931
+ if (!isProductionMode) {
932
+ console.timeEnd(label);
933
+ }
934
+ }
935
+
936
+ function maskEmail(email) {
937
+ const [user, domain] = email.split("@");
938
+ if (user.length <= 2) {
939
+ return `${user[0]}***@${domain}`; // 🔹 Si el usuario es muy corto, no se oculta nada
940
+ }
941
+ if (user.length <= 4) {
942
+ return `${user[0]}***${user.slice(-1)}@${domain}`; // 🔹 Muestra 1 al inicio y 1 al final
943
+ }
944
+ return `${user.slice(0, 2)}***${user.slice(-2)}@${domain}`; // 🔹 Muestra 2 al inicio y 2 al final
945
+ }
946
+ function isEmail(email) {
947
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
948
+ }
949
+
950
+ const mimeTypes = {
951
+ // Imágenes
952
+ 'jpg': 'image/jpeg',
953
+ 'jpeg': 'image/jpeg',
954
+ 'png': 'image/png',
955
+ 'gif': 'image/gif',
956
+ 'webp': 'image/webp',
957
+ 'svg': 'image/svg+xml',
958
+ 'ico': 'image/x-icon',
959
+ 'bmp': 'image/bmp',
960
+ // Documentos
961
+ 'pdf': 'application/pdf',
962
+ 'doc': 'application/msword',
963
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
964
+ 'xls': 'application/vnd.ms-excel',
965
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
966
+ 'ppt': 'application/vnd.ms-powerpoint',
967
+ 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
968
+ 'txt': 'text/plain',
969
+ 'csv': 'text/csv',
970
+ 'json': 'application/json',
971
+ 'xml': 'application/xml',
972
+ 'html': 'text/html',
973
+ // Audio
974
+ 'mp3': 'audio/mpeg',
975
+ 'wav': 'audio/wav',
976
+ 'ogg': 'audio/ogg',
977
+ 'm4a': 'audio/mp4',
978
+ // Video
979
+ 'mp4': 'video/mp4',
980
+ 'avi': 'video/x-msvideo',
981
+ 'mov': 'video/quicktime',
982
+ 'wmv': 'video/x-ms-wmv',
983
+ 'flv': 'video/x-flv',
984
+ 'webm': 'video/webm',
985
+ 'mkv': 'video/x-matroska',
986
+ // Archivos comprimidos
987
+ 'zip': 'application/zip',
988
+ 'rar': 'application/vnd.rar',
989
+ '7z': 'application/x-7z-compressed',
990
+ 'tar': 'application/x-tar',
991
+ 'gz': 'application/gzip',
992
+ 'bz2': 'application/x-bzip2',
993
+ // Otros formatos
994
+ 'js': 'application/javascript',
995
+ 'css': 'text/css',
996
+ 'ts': 'application/typescript',
997
+ 'md': 'text/markdown',
998
+ 'exe': 'application/octet-stream',
999
+ 'eot': 'application/vnd.ms-fontobject',
1000
+ 'woff': 'font/woff',
1001
+ 'woff2': 'font/woff2',
1002
+ 'ttf': 'font/ttf',
1003
+ 'otf': 'font/otf',
1004
+ };
1005
+ function obtenerMimeType(nombreArchivo) {
1006
+ const extension = nombreArchivo.split('.').pop()?.toLowerCase();
1007
+ return extension ? mimeTypes[extension] || 'application/octet-stream' : null;
1008
+ }
1009
+ function sanitizarNombreArchivo(nombre, reemplazo = '_') {
1010
+ // 1. Quitar caracteres no válidos para nombres de archivo
1011
+ const nombreSanitizado = nombre.replace(/[\/\\:*?"<>|]/g, reemplazo);
1012
+ // 2. Reemplazar espacios múltiples o al inicio/final
1013
+ const nombreLimpio = nombreSanitizado.trim().replace(/\s+/g, reemplazo);
1014
+ // 3. Asegurar longitud máxima (opcional, aquí 255 caracteres)
1015
+ return nombreLimpio.substring(0, 255);
1016
+ }
1017
+ function getDataArchivoFromPath(value, conTimeStamp = false) {
1018
+ const partesPath = value.split('/');
1019
+ const nombreCompleto = partesPath[partesPath.length - 1];
1020
+ let timeStamp = 1;
1021
+ let nombreSinTimeStamp = nombreCompleto;
1022
+ const partesNombre = nombreCompleto.split('-');
1023
+ if (partesNombre.length > 1) {
1024
+ timeStamp = partesNombre[0] * 1;
1025
+ partesNombre.shift();
1026
+ nombreSinTimeStamp = partesNombre.join('-');
1027
+ }
1028
+ if (conTimeStamp) {
1029
+ return {
1030
+ nombre: nombreCompleto,
1031
+ extension: nombreCompleto.split('.').pop(),
1032
+ d: timeStamp,
1033
+ fechaSubida: timeStamp ? new Date(timeStamp * 1000) : '',
1034
+ };
1035
+ }
1036
+ return {
1037
+ nombre: nombreSinTimeStamp,
1038
+ extension: nombreSinTimeStamp.split('.').pop(),
1039
+ d: timeStamp,
1040
+ fechaSubida: timeStamp ? new Date(timeStamp * 1000) : '',
1041
+ };
1042
+ }
1043
+ function convertirBytes(valor, unidadSalida = null, incluirUnidad = true) {
1044
+ const unidades = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
1045
+ const indiceEntrada = unidadSalida ? unidades.indexOf(unidadSalida) : 0;
1046
+ if (indiceEntrada === -1) {
1047
+ // Unidad de entrada no válida
1048
+ return null;
1049
+ }
1050
+ let indiceActual = indiceEntrada;
1051
+ let resultado = valor;
1052
+ let cont = 0;
1053
+ while (cont < 6 && (indiceActual < unidades.length - 1) && (resultado >= 1024)) {
1054
+ resultado /= 1024;
1055
+ indiceActual++;
1056
+ }
1057
+ if (incluirUnidad) {
1058
+ return `${resultado.toFixed(2)} ${unidades[indiceActual]}`;
1059
+ }
1060
+ return resultado;
1061
+ }
1062
+ function downLoadFileStream(data, type, nombreArchivo) {
1063
+ const blob = new Blob([data], { type });
1064
+ saveAs(blob, nombreArchivo);
1065
+ }
1066
+
1067
+ function establecerQuitarRequired(formulario, establecer = [], quitar = [], camposDisabled = []) {
1068
+ establecer.forEach((control) => {
1069
+ if (!formulario.get(control)?.hasValidator(Validators.required)) {
1070
+ formulario.get(control)?.addValidators([Validators.required]);
1071
+ formulario.get(control)?.enable();
1072
+ formulario.get(control)?.updateValueAndValidity();
1073
+ }
1074
+ });
1075
+ const deshabilitar = (strControl) => {
1076
+ if (camposDisabled == 'todos') {
1077
+ formulario.get(strControl)?.disable();
1078
+ console.log(strControl);
1079
+ }
1080
+ else {
1081
+ if (camposDisabled.includes(strControl)) {
1082
+ formulario.get(strControl)?.disable();
1083
+ }
1084
+ }
1085
+ };
1086
+ quitar.forEach(control => {
1087
+ if (formulario.get(control)?.hasValidator(Validators.required)) {
1088
+ formulario.get(control)?.removeValidators([Validators.required]);
1089
+ formulario.get(control)?.updateValueAndValidity();
1090
+ }
1091
+ deshabilitar(control);
1092
+ });
1093
+ }
1094
+ function getFormValidationErrors(form) {
1095
+ const result = [];
1096
+ Object.keys(form.controls).forEach(key => {
1097
+ const formProperty = form.get(key);
1098
+ if (formProperty instanceof FormGroup) {
1099
+ result.push(...getFormValidationErrors(formProperty));
1100
+ }
1101
+ const controlErrors = formProperty?.errors;
1102
+ if (controlErrors) {
1103
+ Object.keys(controlErrors).forEach(keyError => {
1104
+ result.push({
1105
+ control: key,
1106
+ error: keyError,
1107
+ value: controlErrors[keyError]
1108
+ });
1109
+ });
1110
+ }
1111
+ });
1112
+ return result;
1113
+ }
1114
+ function mensajesErrorFormControl(control) {
1115
+ if (!control || !control.errors || !control.touched)
1116
+ return '';
1117
+ ReactiveFormConfig.set({
1118
+ // RxwebValidators
1119
+ validationMessage: {
1120
+ required: 'Es requerido',
1121
+ numeric: 'Debe ser numérico valido',
1122
+ // minLength: 'minimum length is {{1}}',
1123
+ // maxLength: 'allowed max length is {{1}}',
1124
+ },
1125
+ });
1126
+ const errorMessages = {
1127
+ required: 'Es requerido',
1128
+ numeric: 'Debe ser numérico válido',
1129
+ min: `Valor mínimo permitido: ${control.errors['min']?.min}`,
1130
+ minValue: 'Debe ser positivo',
1131
+ minlength: `Mínimo ${control.errors['minlength']?.requiredLength} caracteres.`,
1132
+ maxlength: `Caracteres ${control.errors['maxlength']?.actualLength}/${control.errors['maxlength']?.requiredLength}`,
1133
+ email: 'No se cumple con el formato de Correo Electrónico',
1134
+ isNumeric: 'Debe seleccionar una opción',
1135
+ hasNumber: 'Se requiere al menos un número',
1136
+ hasCapitalCase: 'Se requiere al menos una mayúscula',
1137
+ hasSmallCase: 'Se requiere al menos una minúscula',
1138
+ hasSpecialCharacters: 'Se requiere al menos un carácter especial',
1139
+ NoPassswordMatch: 'La contraseña no coincide',
1140
+ itemSelected: 'Debe seleccionar una opción de la lista',
1141
+ inputMask: 'El formato ingresado no es válido',
1142
+ };
1143
+ // Devuelve el primer mensaje de error encontrado
1144
+ for (const errorKey of Object.keys(control.errors)) {
1145
+ if (errorMessages[errorKey]) {
1146
+ return errorMessages[errorKey];
1147
+ }
1148
+ }
1149
+ // Si el error tiene un mensaje personalizado, usarlo
1150
+ return control.errors[Object.keys(control.errors)[0]]?.message || '';
1151
+ }
1152
+ function toFormData(formValue) {
1153
+ const formData = new FormData();
1154
+ Object.keys(formValue).forEach((key) => {
1155
+ const value = formValue[key];
1156
+ if (value === null || value === undefined) {
1157
+ return; // Ignorar valores nulos o indefinidos
1158
+ }
1159
+ if (Array.isArray(value)) {
1160
+ value.forEach((item, index) => {
1161
+ if (typeof item === 'object' && item !== null) {
1162
+ if ('file' in item) {
1163
+ formData.append(`${key}[${index}]`, item.file);
1164
+ }
1165
+ else {
1166
+ formData.append(`${key}[${index}]`, JSON.stringify(item));
1167
+ }
1168
+ }
1169
+ else {
1170
+ formData.append(`${key}[${index}]`, item.toString());
1171
+ }
1172
+ });
1173
+ }
1174
+ else if (typeof value === 'object') {
1175
+ // Si es un objeto (pero no un array), convertirlo a JSON
1176
+ formData.append(key, JSON.stringify(value));
1177
+ }
1178
+ else {
1179
+ // Para valores primitivos (string, number, boolean)
1180
+ formData.append(key, value.toString());
1181
+ }
1182
+ });
1183
+ return formData;
1184
+ }
1185
+ function markAsTouchedWithoutEmitEvent(control) {
1186
+ if (control instanceof FormControl) {
1187
+ control.markAsTouched({ onlySelf: true });
1188
+ control.updateValueAndValidity({ emitEvent: false });
1189
+ }
1190
+ else if (control instanceof FormGroup || control instanceof FormArray) {
1191
+ Object.values(control.controls).forEach(childControl => {
1192
+ markAsTouchedWithoutEmitEvent(childControl);
1193
+ });
1194
+ control.updateValueAndValidity({ emitEvent: false });
1195
+ }
1196
+ }
1197
+ function setControlDesdeLista(config) {
1198
+ const lista = config.lista$?.getValue() ?? [];
1199
+ if (!lista.length)
1200
+ return;
1201
+ let seleccionado;
1202
+ if (config.idProp && config.idValor !== undefined) {
1203
+ seleccionado = lista.find((item) => item[config.idProp] === config.idValor);
1204
+ }
1205
+ else if (config.usarPrimeraOpcion) {
1206
+ seleccionado = lista[0];
1207
+ }
1208
+ console.log(seleccionado);
1209
+ if (!seleccionado)
1210
+ return;
1211
+ let valor;
1212
+ if (config.selector) {
1213
+ valor = config.selector(seleccionado);
1214
+ }
1215
+ else if (config.idProp) {
1216
+ valor = seleccionado[config.idProp];
1217
+ }
1218
+ else {
1219
+ valor = seleccionado;
1220
+ }
1221
+ if (config.formControl) {
1222
+ config.formControl.setValue(valor);
1223
+ }
1224
+ else if (config.formGroup && config.controlName) {
1225
+ const control = config.formGroup.get(config.controlName);
1226
+ if (control instanceof FormControl) {
1227
+ control.setValue(valor);
1228
+ }
1229
+ }
1230
+ }
1231
+ function transformarFechasPorNombreDeCampo(formValue) {
1232
+ const retData = {};
1233
+ Object.entries(formValue).forEach(([key, value]) => {
1234
+ // ✅ No procesar Blob o File
1235
+ if (value instanceof Blob || value instanceof File) {
1236
+ retData[key] = value;
1237
+ return;
1238
+ }
1239
+ if (value instanceof Date) {
1240
+ if (/^d[A-Za-z]+/.test(key)) {
1241
+ retData[key] = moment(value).format('YYYY-MM-DD');
1242
+ }
1243
+ else {
1244
+ retData[key] = new Date(Date.UTC(value.getFullYear(), value.getMonth(), value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds()));
1245
+ }
1246
+ }
1247
+ else if (/^dt[A-Za-z]+/.test(key) && typeof value === 'string') {
1248
+ if (/\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}/.test(value)) {
1249
+ retData[key] = new Date(value + 'Z');
1250
+ }
1251
+ else if (/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(value) || /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}/.test(value)) {
1252
+ retData[key] = new Date(value + ':00.000Z');
1253
+ }
1254
+ else {
1255
+ console.warn('FECHA INVALIDA AL ENVIAR (FormInter):', key, value);
1256
+ retData[key] = value;
1257
+ }
1258
+ }
1259
+ else if (Array.isArray(value)) {
1260
+ if (value.every(v => v instanceof File || v instanceof Blob)) {
1261
+ retData[key] = value;
1262
+ }
1263
+ else {
1264
+ retData[key] = value.map(item => typeof item === 'object' && item !== null
1265
+ ? transformarFechasPorNombreDeCampo(item)
1266
+ : item);
1267
+ }
1268
+ }
1269
+ else if (typeof value === 'object' && value !== null) {
1270
+ retData[key] = transformarFechasPorNombreDeCampo(value);
1271
+ }
1272
+ else {
1273
+ retData[key] = value;
1274
+ }
1275
+ });
1276
+ return retData;
1277
+ }
1278
+
1279
+ function mensajeAlerta(tipo, titulo, mensaje, opciones) {
1280
+ opciones = {
1281
+ ...{
1282
+ heightAuto: false,
1283
+ title: titulo,
1284
+ html: mensaje,
1285
+ icon: tipo,
1286
+ confirmButtonText: 'Aceptar',
1287
+ // customClass: {
1288
+ // confirmButton: 'btn btn-lg btn-outline-success mx-2',
1289
+ // cancelButton: 'btn btn-lg btn-outline-dark mx-2'
1290
+ // },
1291
+ // buttonsStyling: false
1292
+ },
1293
+ ...opciones
1294
+ };
1295
+ return swal.fire(opciones);
1296
+ }
1297
+ function mensajeTimer(tipo, titulo, mensaje, milisegundos = 3000, showLoading = true, opciones) {
1298
+ let timerInterval;
1299
+ opciones = {
1300
+ ...{
1301
+ heightAuto: false,
1302
+ title: titulo,
1303
+ html: mensaje + '<br> Se cerrará en <strong> X </strong> segundos.',
1304
+ icon: tipo,
1305
+ timer: milisegundos,
1306
+ showCancelButton: false,
1307
+ showConfirmButton: false,
1308
+ willOpen: () => {
1309
+ if (showLoading) {
1310
+ swal.showLoading();
1311
+ }
1312
+ timerInterval = setInterval(() => {
1313
+ const impr = Math.ceil(((swal.getTimerLeft() ?? 1) / 1000));
1314
+ if (swal.getHtmlContainer()) {
1315
+ // @ts-ignore
1316
+ swal.getHtmlContainer().querySelector('strong').textContent = String(impr);
1317
+ }
1318
+ }, 100);
1319
+ },
1320
+ willClose: () => {
1321
+ clearInterval(timerInterval);
1322
+ }
1323
+ },
1324
+ ...opciones
1325
+ };
1326
+ return swal.fire(opciones);
1327
+ }
1328
+ // @ts-ignore
1329
+ function mensajeConfirmacion(tipo, titulo, mensaje, opciones) {
1330
+ opciones = {
1331
+ ...{
1332
+ heightAuto: false,
1333
+ title: titulo,
1334
+ html: mensaje,
1335
+ icon: tipo,
1336
+ showCancelButton: true,
1337
+ // confirmButtonColor: '#3f51b5',
1338
+ // cancelButtonColor: '#ffffff',
1339
+ confirmButtonText: 'Confirmar',
1340
+ cancelButtonText: 'Cancelar',
1341
+ reverseButtons: true,
1342
+ // customClass: {
1343
+ // confirmButton: 'btn btn-lg btn-outline-success mx-2',
1344
+ // cancelButton: 'btn btn-lg btn-outline-dark mx-2'
1345
+ // },
1346
+ // buttonsStyling: false
1347
+ },
1348
+ ...opciones
1349
+ };
1350
+ return swal.fire(opciones);
1351
+ }
1352
+ function mensajeToast(tipo, titulo, mensaje, opciones) {
1353
+ opciones = {
1354
+ ...{
1355
+ heightAuto: false,
1356
+ title: titulo,
1357
+ html: mensaje,
1358
+ icon: tipo,
1359
+ confirmButtonText: 'Aceptar',
1360
+ toast: true,
1361
+ position: 'top-end',
1362
+ showConfirmButton: false,
1363
+ timer: 3000,
1364
+ timerProgressBar: true,
1365
+ },
1366
+ ...opciones
1367
+ };
1368
+ return swal.fire(opciones);
1369
+ }
1370
+
1371
+ function mensajesDeError(error, toast = false) {
1372
+ let msg;
1373
+ if (error.error && error.error instanceof ArrayBuffer) {
1374
+ const msgArrayBuffer = (arrayBuffer) => {
1375
+ try {
1376
+ const mensajeError = JSON.parse(new TextDecoder("utf-8").decode(arrayBuffer));
1377
+ return mensajeError.message || 'Error desconocido';
1378
+ }
1379
+ catch (parseError) {
1380
+ console.error('Error al analizar la respuesta JSON:', parseError);
1381
+ return 'Error al analizar la respuesta JSON';
1382
+ }
1383
+ };
1384
+ msg = msgArrayBuffer(error.error);
1385
+ }
1386
+ else {
1387
+ switch (error.status) {
1388
+ case 0:
1389
+ // msg = error.message;
1390
+ msg = 'El servidor no responde, verifica tu conexion a la red';
1391
+ console.log(error);
1392
+ break;
1393
+ case 401:
1394
+ if (error.error && typeof error.error == 'object') {
1395
+ if (error.error.message) {
1396
+ msg = error.error.message;
1397
+ }
1398
+ else if (error.error.error) {
1399
+ msg = error.error.error;
1400
+ }
1401
+ else {
1402
+ msg = JSON.stringify(error.error);
1403
+ console.log(error);
1404
+ }
1405
+ }
1406
+ else if (error.error && typeof error.error == 'string') {
1407
+ msg = error.error;
1408
+ }
1409
+ else {
1410
+ msg = 'Acceso no autorizado';
1411
+ console.log(error);
1412
+ }
1413
+ break;
1414
+ case 422:
1415
+ let strEr = '';
1416
+ console.log(typeof error.error.errors);
1417
+ console.log(error.error.errors);
1418
+ if (error.error.errors) {
1419
+ Object.keys(error.error.errors).forEach(o => {
1420
+ strEr += '<li>' + error.error.errors[o][0] + '</li>';
1421
+ });
1422
+ msg = (error.error.message ?? '') + '<ul>' + strEr + '</ul>';
1423
+ }
1424
+ else if (error.error.error) {
1425
+ msg = error.error.msg;
1426
+ }
1427
+ break;
1428
+ case 429:
1429
+ case 400:
1430
+ case 500:
1431
+ case 503:
1432
+ msg = error.error.message;
1433
+ break;
1434
+ case 504:
1435
+ msg = 'No se puede conectar al servidor. Comprueba tu conexion a la red - ' + error.statusText;
1436
+ break;
1437
+ default:
1438
+ msg = error?.error?.message ?? 'Error de Sistema';
1439
+ console.log(error);
1440
+ break;
1441
+ }
1442
+ }
1443
+ if (!msg) {
1444
+ msg = error.statusText ?? 'Error inesperado o datos inexistentes.';
1445
+ }
1446
+ let tituloFinal = 'Error!';
1447
+ let mensajeFinal;
1448
+ if (msg.includes('Hmac::doVerify')) {
1449
+ console.log(error, msg);
1450
+ return;
1451
+ }
1452
+ else if (msg == 'Server Error') {
1453
+ console.log(error, msg);
1454
+ return;
1455
+ }
1456
+ else if (msg.includes('[IMSSP]')) {
1457
+ mensajeFinal = 'Error en consulta de registros.';
1458
+ }
1459
+ else if (msg.includes('Tiempo de espera de la')) {
1460
+ mensajeFinal = 'Hubo un error en la solicitud de datos, por favor actualice (SHIFT + F5)';
1461
+ }
1462
+ else {
1463
+ mensajeFinal = msg;
1464
+ }
1465
+ if (toast) {
1466
+ mensajeToast('error', tituloFinal, mensajeFinal);
1467
+ }
1468
+ else {
1469
+ mensajeAlerta('error', tituloFinal, mensajeFinal);
1470
+ }
1471
+ throw new Error(mensajeFinal);
1472
+ }
1473
+
1474
+ let dataSessionStorageKey = {
1475
+ tokenStringKey: 'JVSoftTkn',
1476
+ changePasswordKey: 'chPwd',
1477
+ logoUrl: 'logo_url',
1478
+ logoLogin: 'login-logo',
1479
+ backgroundLogin: 'login-background',
1480
+ favicon: 'favicon',
1481
+ darkMode: 'darkMode',
1482
+ serverTimestamp: 'srvtmstp',
1483
+ apiDataKey: 'reqDt',
1484
+ };
1485
+ let localStorageKeys = dataSessionStorageKey;
1486
+ function inicializarVariablesSessionStorage(datSesion) {
1487
+ dataSessionStorageKey = datSesion;
1488
+ }
1489
+ function setJwtTokenData(data) {
1490
+ localStorage.setItem(dataSessionStorageKey.tokenStringKey, data);
1491
+ }
1492
+ function jwtTokenData(key = dataSessionStorageKey.tokenStringKey) {
1493
+ const tokenObj = localStorage.getItem(key);
1494
+ try {
1495
+ return JSON.parse(tokenObj);
1496
+ }
1497
+ catch (error) {
1498
+ return null;
1499
+ }
1500
+ }
1501
+ function jwtToken(key = dataSessionStorageKey.tokenStringKey) {
1502
+ const varJwtTokenData = jwtTokenData(key);
1503
+ if (varJwtTokenData) {
1504
+ return varJwtTokenData.access_token;
1505
+ }
1506
+ return '';
1507
+ }
1508
+ function jwtTokenExpiracion(key = dataSessionStorageKey.tokenStringKey) {
1509
+ const jwtStr = jwtToken(key);
1510
+ if (!jwtStr)
1511
+ return null;
1512
+ try {
1513
+ const decodedToken = jwtDecode(jwtStr);
1514
+ return decodedToken.exp ? decodedToken.exp * 1000 : null; // Convertir a milisegundos
1515
+ }
1516
+ catch (e) {
1517
+ return null;
1518
+ }
1519
+ }
1520
+ function jwtTokenExpiracionFaltante() {
1521
+ return Math.abs(moment().diff(jwtTokenExpiracion(), 'seconds'));
1522
+ }
1523
+ function setCambiarPwd(accion = true) {
1524
+ localStorage.setItem(dataSessionStorageKey.changePasswordKey, (accion ? 1 : 0).toString());
1525
+ }
1526
+ function getCambiarPwd() {
1527
+ const frmCambioPwd = localStorage.getItem(dataSessionStorageKey.changePasswordKey);
1528
+ if (!frmCambioPwd) {
1529
+ return null;
1530
+ }
1531
+ return frmCambioPwd == '1';
1532
+ }
1533
+ function delLocalStorage(keyElim = [
1534
+ dataSessionStorageKey.tokenStringKey,
1535
+ dataSessionStorageKey.changePasswordKey,
1536
+ dataSessionStorageKey.apiDataKey,
1537
+ ]) {
1538
+ keyElim.forEach(key => {
1539
+ localStorage.removeItem(key);
1540
+ });
1541
+ }
1542
+ function getLocalStorage(key) {
1543
+ return localStorage.getItem(key);
1544
+ }
1545
+ function setLocalStorage(key, value = '') {
1546
+ localStorage.setItem(key, value.toString());
1547
+ }
1548
+
1549
+ function roundToDecimal(number, decimal) {
1550
+ return parseFloat(number.toFixed(decimal));
1551
+ }
1552
+ function numberToWords(num) {
1553
+ if (num === 0)
1554
+ return 'cero';
1555
+ if (num < 0)
1556
+ return 'menos ' + numberToWords(Math.abs(num));
1557
+ if (num > 999999999999)
1558
+ return 'número demasiado grande';
1559
+ const ones = ['', 'un', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve'];
1560
+ const onesFinal = ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve'];
1561
+ const tens = ['', 'diez', 'veinte', 'treinta', 'cuarenta', 'cincuenta', 'sesenta', 'setenta', 'ochenta', 'noventa'];
1562
+ const teens = ['diez', 'once', 'doce', 'trece', 'catorce', 'quince', 'dieciséis', 'diecisiete', 'dieciocho', 'diecinueve'];
1563
+ const hundreds = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos', 'quinientos', 'seiscientos', 'setecientos', 'ochocientos', 'novecientos'];
1564
+ // Función auxiliar para "un"/"uno"
1565
+ const getOneForm = (n, isFinal) => n === 1 ? (isFinal ? 'uno' : 'un') : onesFinal[n];
1566
+ let words = '';
1567
+ // Miles de millones (ahora sí se ejecuta)
1568
+ if (num >= 1000000000) {
1569
+ const billions = Math.floor(num / 1000000000);
1570
+ words += (billions === 1 ? 'mil' : numberToWords(billions) + ' mil') + ' millones ';
1571
+ num %= 1000000000;
1572
+ }
1573
+ // Millones
1574
+ if (num >= 1000000) {
1575
+ const millions = Math.floor(num / 1000000);
1576
+ words += millions === 1 ? 'un millón ' : numberToWords(millions) + ' millones ';
1577
+ num %= 1000000;
1578
+ }
1579
+ // Miles
1580
+ if (num >= 1000) {
1581
+ const thousands = Math.floor(num / 1000);
1582
+ words += thousands === 1 ? 'mil ' : numberToWords(thousands) + ' mil ';
1583
+ num %= 1000;
1584
+ }
1585
+ // Centenas (con tratamiento especial para "ciento uno")
1586
+ if (num >= 100) {
1587
+ if (num === 100) {
1588
+ words += 'cien';
1589
+ num = 0;
1590
+ }
1591
+ else {
1592
+ words += hundreds[Math.floor(num / 100)];
1593
+ num %= 100;
1594
+ if (num > 0) {
1595
+ words += ' ' + getOneForm(num, true); // Siempre "uno" después de ciento
1596
+ num = 0;
1597
+ }
1598
+ }
1599
+ }
1600
+ // Decenas y unidades
1601
+ if (num > 0) {
1602
+ const isFinalWord = words === '';
1603
+ if (num < 10) {
1604
+ words += getOneForm(num, isFinalWord);
1605
+ }
1606
+ else if (num < 20) {
1607
+ words += teens[num - 10];
1608
+ }
1609
+ else if (num < 30) {
1610
+ if (num === 21)
1611
+ words += 'veintiuno';
1612
+ else if (num === 22)
1613
+ words += 'veintidós';
1614
+ else if (num === 23)
1615
+ words += 'veintitrés';
1616
+ else if (num === 26)
1617
+ words += 'veintiséis';
1618
+ else
1619
+ words += `veinti${onesFinal[num % 10]}`;
1620
+ }
1621
+ else {
1622
+ words += tens[Math.floor(num / 10)];
1623
+ if (num % 10 > 0) {
1624
+ words += ' y ' + getOneForm(num % 10, isFinalWord);
1625
+ }
1626
+ }
1627
+ }
1628
+ return words.trim().replace(/\s+/g, ' ');
1629
+ }
1630
+
1631
+ function objectPropertiesToType(formFields) {
1632
+ Object.keys(formFields).filter(control => !!formFields[control]).forEach(control => {
1633
+ if (/^dt[a-zA-Z]+/.test(control)) {
1634
+ formFields[control] = formatDate(formFields[control], 'yyyy-MM-dd HH:mm', 'es-PE');
1635
+ }
1636
+ else if (control.startsWith('d')) {
1637
+ formFields[control] = formatearFecha(formFields[control]);
1638
+ }
1639
+ else if (control.startsWith('n')) {
1640
+ formFields[control] = Number(formFields[control]);
1641
+ }
1642
+ });
1643
+ return formFields;
1644
+ }
1645
+ function objectPropertiesBoolean(formFields, retorno = 'boolean') {
1646
+ Object.keys(formFields).forEach(control => {
1647
+ const valRetorno = (ctrl) => {
1648
+ switch (retorno) {
1649
+ case 'boolean':
1650
+ formFields[ctrl] = formFields[ctrl] == 1;
1651
+ break;
1652
+ case 'bit':
1653
+ formFields[ctrl] = formFields[ctrl] ? 1 : 0;
1654
+ break;
1655
+ }
1656
+ };
1657
+ if (control.charAt(0) == 'b' || (control.charAt(0) == 'i' && control.indexOf('Estado') !== -1)) {
1658
+ valRetorno(control);
1659
+ }
1660
+ });
1661
+ return formFields;
1662
+ }
1663
+
1664
+ function generateRandomString(length) {
1665
+ let result = '';
1666
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
1667
+ const charactersLength = characters.length;
1668
+ for (let i = 0; i < length; i++) {
1669
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
1670
+ }
1671
+ return result;
1672
+ }
1673
+ /**
1674
+ * Obtiene el host (hostname) de una URL o cadena host[:port].
1675
+ * Opcionalmente puede devolver también el puerto si está presente.
1676
+ *
1677
+ * - Acepta inputs como:
1678
+ * 'https://example.com/path', 'example.com:3000', 'localhost', 'http://[::1]:4200'
1679
+ * - Usa la API URL cuando es posible (más robusta) y cae a un regex de respaldo.
1680
+ *
1681
+ * @param url Cadena que representa una URL o host
1682
+ * @param options
1683
+ * @param options.includePort Si es true, incluye":puerto" cuando exista (por defecto false)
1684
+ * @param options.includeProtocol Incluye "http://" o "https://" según corresponda (por defecto false)
1685
+ */
1686
+ function obtenerHostDesdeUrl(url, options) {
1687
+ if (!url)
1688
+ return null;
1689
+ const includePort = !!options?.includePort;
1690
+ const includeProtocol = !!options?.includeProtocol;
1691
+ // Intentar con API URL
1692
+ try {
1693
+ const candidate = url.includes('://') ? url : `http://${url}`;
1694
+ const parsed = new URL(candidate);
1695
+ const protocol = includeProtocol ? `${parsed.protocol}//` : '';
1696
+ const hostname = parsed.hostname;
1697
+ const port = parsed.port;
1698
+ if (!hostname)
1699
+ return null;
1700
+ return `${protocol}${hostname}${includePort && port ? `:${port}` : ''}`;
1701
+ }
1702
+ catch {
1703
+ // Regex fallback
1704
+ const regex = /^(?:(?<protocol>[a-z]+):\/\/)?(?:www\.)?(?<host>\[[^\]]+\]|[A-Za-z0-9.-]+)(?::(?<port>\d{1,5}))?/;
1705
+ const match = String(url).match(regex);
1706
+ if (!match?.groups)
1707
+ return null;
1708
+ let host = match.groups['host'];
1709
+ if (host.startsWith('[') && host.endsWith(']')) {
1710
+ host = host.slice(1, -1);
1711
+ }
1712
+ const port = match.groups['port'];
1713
+ const protocol = includeProtocol ? `${match.groups['protocol'] ?? 'http'}://` : '';
1714
+ return `${protocol}${host}${includePort && port ? `:${port}` : ''}`;
1715
+ }
1716
+ }
1717
+ /** @deprecated Alias compatible (deprecated) — preferir usar `obtenerHostDesdeUrl`. */
1718
+ const extraerDominio = (url, options) => obtenerHostDesdeUrl(url, options);
1719
+
1720
+ function verificarRUC(ruc) {
1721
+ const f = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
1722
+ const rucArray = ruc.split('');
1723
+ const nArray = f.map((item, idx) => {
1724
+ return item * parseFloat(rucArray[idx]);
1725
+ });
1726
+ const suma = nArray.reduce((a, b) => a + b, 0);
1727
+ const residuo = suma % 11;
1728
+ const residuo2 = 11 - residuo;
1729
+ // @residuo=CONVERT(Integer,Right(CONVERT(VarChar,@residuo),1))
1730
+ const residuo3 = residuo2.toString().charAt(residuo2.toString().length - 1);
1731
+ const ultimoCaracter = ruc.toString().charAt(ruc.toString().length - 1);
1732
+ if (residuo3 == ultimoCaracter) {
1733
+ return true;
1734
+ }
1735
+ mensajeAlerta('error', 'Datos No válidos', ' El número de RUC no es válido');
1736
+ return false;
1737
+ }
1738
+
1739
+ /**
1740
+ * Generated bundle index. Do not edit.
1741
+ */
1742
+
1743
+ export { b64Decode, b64Encode, buscarPorCampo, changeSelect, changeSelectApi, changeSelectData, changeSelectDataApi, changeSelectReformateado, convertirBytes, decodeBase64Object, decodeBase64String, decodeBase64ToBlob, deepClone, deepMerge, delLocalStorage, desencriptar, devError, devGroup, devGroupEnd, devLog, devTable, devTime, devTimeEnd, devWarn, downLoadFileStream, eliminarColumnaPorIndex, eliminarDuplicados, eliminarElementos, encodeBase64File, encodeBase64Object, encodeBase64String, encriptar, esNumero, esPromise, establecerQuitarRequired, extraerDominio, filtrarDatosLocal, formatearFecha, formatearFechaCadena, formatearFechaFormato, generateRandomString, getBrowserName, getCambiarPwd, getDataArchivoFromPath, getFormValidationErrors, getLocalStorage, getUniqueValues, getUniqueValuesByProperty, getValueByPath, groupBy, inicializarVariablesSessionStorage, isEmail, isProduction, jwtToken, jwtTokenData, jwtTokenExpiracion, jwtTokenExpiracionFaltante, localStorageKeys, markAsTouchedWithoutEmitEvent, maskEmail, mensajeAlerta, mensajeConfirmacion, mensajeTimer, mensajeToast, mensajesDeError, mensajesErrorFormControl, mostrarValorEnBusqueda, nestGroupsBy, numberToWords, objectPropertiesBoolean, objectPropertiesToType, obtenerHostDesdeUrl, obtenerMimeType, obtenerUltimoOrden, ordenarArray, ordenarPorPropiedad, ordenarPorPropiedades, roundToDecimal, sanitizarNombreArchivo, seleccionarTextoInput, setCambiarPwd, setControlDesdeLista, setJwtTokenData, setLocalStorage, setProductionMode, sumarObjetos, sumarPropiedades, toFormData, transformarFechasPorNombreDeCampo, verificarRUC };
1744
+ //# sourceMappingURL=jvsoft-utils-functions.mjs.map