@jvsoft/utils 0.0.13-alpha.2 → 0.0.13-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/ng-package.json +7 -0
- package/package.json +2 -25
- package/src/classes/data-model.ts +150 -0
- package/src/functions/base64.ts +8 -0
- package/src/functions/browser.ts +20 -0
- package/src/functions/crypto-js.ts +29 -0
- package/src/functions/date.ts +23 -0
- package/src/functions/email.ts +17 -0
- package/src/functions/file.ts +138 -0
- package/src/functions/forms.ts +251 -0
- package/src/functions/http-client.ts +110 -0
- package/src/functions/index.ts +1 -0
- package/src/functions/local-storage.ts +102 -0
- package/src/functions/mat-form-controls/autocomplete.ts +205 -0
- package/src/functions/mat-form-controls/index.ts +6 -0
- package/src/functions/ng-package.json +5 -0
- package/src/functions/number.ts +85 -0
- package/src/functions/object-transformation.ts +37 -0
- package/src/functions/objects-arrays.ts +321 -0
- package/src/functions/public-api.ts +19 -0
- package/src/functions/string.ts +68 -0
- package/src/functions/sweetalert.ts +95 -0
- package/src/functions/utiles.ts +20 -0
- package/{interfaces/datos.d.ts → src/interfaces/datos.ts} +2 -1
- package/src/interfaces/index.ts +1 -0
- package/src/interfaces/ng-package.json +5 -0
- package/src/interfaces/otros.ts +0 -0
- package/src/interfaces/public-api.ts +3 -0
- package/src/interfaces/routes.ts +42 -0
- package/src/pipes/data-en-lista.pipe.ts +40 -0
- package/src/pipes/date-diff-string.pipe.ts +117 -0
- package/src/pipes/filtro.pipe.ts +64 -0
- package/src/pipes/form-control-is-required.pipe.ts +17 -0
- package/src/pipes/index.ts +1 -0
- package/src/pipes/json-parse.pipe.ts +18 -0
- package/src/pipes/ng-package.json +5 -0
- package/src/pipes/no-sanitize.pipe.ts +12 -0
- package/src/pipes/public-api.ts +10 -0
- package/src/pipes/tipo-valor-funcion.pipe.ts +23 -0
- package/src/pipes/zero-fill.pipe.ts +19 -0
- package/src/public-api.ts +12 -0
- package/tsconfig.lib.json +18 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +15 -0
- package/classes/data-model.d.ts +0 -25
- package/fesm2022/jvsoft-utils-src-functions.mjs +0 -1109
- package/fesm2022/jvsoft-utils-src-functions.mjs.map +0 -1
- package/fesm2022/jvsoft-utils-src-interfaces.mjs +0 -6
- package/fesm2022/jvsoft-utils-src-interfaces.mjs.map +0 -1
- package/fesm2022/jvsoft-utils-src-pipes.mjs +0 -290
- package/fesm2022/jvsoft-utils-src-pipes.mjs.map +0 -1
- package/fesm2022/jvsoft-utils.mjs +0 -1526
- package/fesm2022/jvsoft-utils.mjs.map +0 -1
- package/functions/base64.d.ts +0 -2
- package/functions/browser.d.ts +0 -1
- package/functions/crypto-js.d.ts +0 -2
- package/functions/date.d.ts +0 -3
- package/functions/email.d.ts +0 -2
- package/functions/file.d.ts +0 -10
- package/functions/forms.d.ts +0 -10
- package/functions/http-client.d.ts +0 -2
- package/functions/index.d.ts +0 -1
- package/functions/local-storage.d.ts +0 -29
- package/functions/mat-form-controls/autocomplete.d.ts +0 -21
- package/functions/mat-form-controls/index.d.ts +0 -2
- package/functions/number.d.ts +0 -1
- package/functions/object-transformation.d.ts +0 -2
- package/functions/objects-arrays.d.ts +0 -37
- package/functions/public-api.d.ts +0 -16
- package/functions/string.d.ts +0 -1
- package/functions/sweetalert.d.ts +0 -5
- package/functions/utiles.d.ts +0 -1
- package/index.d.ts +0 -5
- package/interfaces/index.d.ts +0 -1
- package/interfaces/public-api.d.ts +0 -1
- package/pipes/data-en-lista.pipe.d.ts +0 -8
- package/pipes/date-diff-string.pipe.d.ts +0 -17
- package/pipes/filtro.pipe.d.ts +0 -18
- package/pipes/form-control-is-required.pipe.d.ts +0 -9
- package/pipes/index.d.ts +0 -1
- package/pipes/json-parse.pipe.d.ts +0 -7
- package/pipes/no-sanitize.pipe.d.ts +0 -10
- package/pipes/public-api.d.ts +0 -8
- package/pipes/tipo-valor-funcion.pipe.d.ts +0 -9
- package/pipes/zero-fill.pipe.d.ts +0 -8
- package/public-api.d.ts +0 -4
- package/src/functions/base64.d.ts +0 -2
- package/src/functions/browser.d.ts +0 -1
- package/src/functions/crypto-js.d.ts +0 -2
- package/src/functions/date.d.ts +0 -3
- package/src/functions/email.d.ts +0 -2
- package/src/functions/file.d.ts +0 -10
- package/src/functions/forms.d.ts +0 -10
- package/src/functions/http-client.d.ts +0 -2
- package/src/functions/index.d.ts +0 -5
- package/src/functions/local-storage.d.ts +0 -29
- package/src/functions/mat-form-controls/autocomplete.d.ts +0 -21
- package/src/functions/mat-form-controls/index.d.ts +0 -2
- package/src/functions/number.d.ts +0 -1
- package/src/functions/object-transformation.d.ts +0 -2
- package/src/functions/objects-arrays.d.ts +0 -37
- package/src/functions/public-api.d.ts +0 -16
- package/src/functions/string.d.ts +0 -1
- package/src/functions/sweetalert.d.ts +0 -5
- package/src/functions/utiles.d.ts +0 -1
- package/src/interfaces/datos.d.ts +0 -4
- package/src/interfaces/index.d.ts +0 -5
- package/src/interfaces/public-api.d.ts +0 -1
- package/src/pipes/data-en-lista.pipe.d.ts +0 -8
- package/src/pipes/date-diff-string.pipe.d.ts +0 -17
- package/src/pipes/filtro.pipe.d.ts +0 -18
- package/src/pipes/form-control-is-required.pipe.d.ts +0 -9
- package/src/pipes/index.d.ts +0 -5
- package/src/pipes/json-parse.pipe.d.ts +0 -7
- package/src/pipes/no-sanitize.pipe.d.ts +0 -10
- package/src/pipes/public-api.d.ts +0 -8
- package/src/pipes/tipo-valor-funcion.pipe.d.ts +0 -9
- package/src/pipes/zero-fill.pipe.d.ts +0 -8
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {AbstractControl, FormArray, FormControl, FormGroup, ValidationErrors, Validators} from '@angular/forms';
|
|
2
|
+
import {ReactiveFormConfig} from '@rxweb/reactive-form-validators';
|
|
3
|
+
import moment from "moment";
|
|
4
|
+
import {BehaviorSubject} from 'rxjs';
|
|
5
|
+
|
|
6
|
+
export function establecerQuitarRequired(formulario: FormGroup, establecer: any[] = [], quitar: any[] = [], camposDisabled: string[] | 'todos' = []) {
|
|
7
|
+
establecer.forEach((control: string) => {
|
|
8
|
+
if (!formulario.get(control)?.hasValidator(Validators.required)) {
|
|
9
|
+
formulario.get(control)?.addValidators([Validators.required]);
|
|
10
|
+
formulario.get(control)?.enable();
|
|
11
|
+
formulario.get(control)?.updateValueAndValidity();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
const deshabilitar = (strControl: string) => {
|
|
15
|
+
if (camposDisabled == 'todos') {
|
|
16
|
+
formulario.get(strControl)?.disable();
|
|
17
|
+
console.log(strControl);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
if (camposDisabled.includes(strControl)) {
|
|
21
|
+
formulario.get(strControl)?.disable();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
quitar.forEach(control => {
|
|
26
|
+
if (formulario.get(control)?.hasValidator(Validators.required)) {
|
|
27
|
+
formulario.get(control)?.removeValidators([Validators.required]);
|
|
28
|
+
formulario.get(control)?.updateValueAndValidity();
|
|
29
|
+
}
|
|
30
|
+
deshabilitar(control);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getFormValidationErrors(form: FormGroup) {
|
|
35
|
+
const result: { control: string; error: string; value: any; }[] = [];
|
|
36
|
+
Object.keys(form.controls).forEach(key => {
|
|
37
|
+
const formProperty = form.get(key);
|
|
38
|
+
if (formProperty instanceof FormGroup) {
|
|
39
|
+
result.push(...getFormValidationErrors(formProperty));
|
|
40
|
+
}
|
|
41
|
+
const controlErrors: ValidationErrors | null | undefined = formProperty?.errors;
|
|
42
|
+
if (controlErrors) {
|
|
43
|
+
Object.keys(controlErrors).forEach(keyError => {
|
|
44
|
+
result.push({
|
|
45
|
+
control: key,
|
|
46
|
+
error: keyError,
|
|
47
|
+
value: controlErrors[keyError]
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function mensajesErrorFormControl(control: AbstractControl | null): string {
|
|
57
|
+
if (!control || !control.errors || !control.touched) return '';
|
|
58
|
+
|
|
59
|
+
ReactiveFormConfig.set({
|
|
60
|
+
// RxwebValidators
|
|
61
|
+
validationMessage: {
|
|
62
|
+
required: 'Es requerido',
|
|
63
|
+
numeric: 'Debe ser numérico valido',
|
|
64
|
+
// minLength: 'minimum length is {{1}}',
|
|
65
|
+
// maxLength: 'allowed max length is {{1}}',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const errorMessages: Record<string, string> = {
|
|
70
|
+
required: 'Es requerido',
|
|
71
|
+
numeric: 'Debe ser numérico válido',
|
|
72
|
+
min: `Valor mínimo permitido: ${control.errors['min']?.min}`,
|
|
73
|
+
minValue: 'Debe ser positivo',
|
|
74
|
+
minlength: `Mínimo ${control.errors['minlength']?.requiredLength} caracteres.`,
|
|
75
|
+
maxlength: `Caracteres ${control.errors['maxlength']?.actualLength}/${control.errors['maxlength']?.requiredLength}`,
|
|
76
|
+
email: 'No se cumple con el formato de Correo Electrónico',
|
|
77
|
+
isNumeric: 'Debe seleccionar una opción',
|
|
78
|
+
hasNumber: 'Se requiere al menos un número',
|
|
79
|
+
hasCapitalCase: 'Se requiere al menos una mayúscula',
|
|
80
|
+
hasSmallCase: 'Se requiere al menos una minúscula',
|
|
81
|
+
hasSpecialCharacters: 'Se requiere al menos un carácter especial',
|
|
82
|
+
NoPassswordMatch: 'La contraseña no coincide',
|
|
83
|
+
itemSelected: 'Debe seleccionar una opción de la lista',
|
|
84
|
+
inputMask: 'El formato ingresado no es válido',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Devuelve el primer mensaje de error encontrado
|
|
88
|
+
for (const errorKey of Object.keys(control.errors)) {
|
|
89
|
+
if (errorMessages[errorKey]) {
|
|
90
|
+
return errorMessages[errorKey];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Si el error tiene un mensaje personalizado, usarlo
|
|
95
|
+
return control.errors[Object.keys(control.errors)[0]]?.message || '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function toFormData<T extends Record<string, any>>(formValue: T): FormData {
|
|
99
|
+
const formData = new FormData();
|
|
100
|
+
|
|
101
|
+
Object.keys(formValue).forEach((key) => {
|
|
102
|
+
const value = formValue[key];
|
|
103
|
+
|
|
104
|
+
if (value === null || value === undefined) {
|
|
105
|
+
return; // Ignorar valores nulos o indefinidos
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (Array.isArray(value)) {
|
|
109
|
+
value.forEach((item, index) => {
|
|
110
|
+
if (typeof item === 'object' && item !== null) {
|
|
111
|
+
if ('file' in item) {
|
|
112
|
+
formData.append(`${key}[${index}]`, item.file);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
formData.append(`${key}[${index}]`, JSON.stringify(item));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
formData.append(`${key}[${index}]`, item.toString());
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else if (typeof value === 'object') {
|
|
124
|
+
// Si es un objeto (pero no un array), convertirlo a JSON
|
|
125
|
+
formData.append(key, JSON.stringify(value));
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Para valores primitivos (string, number, boolean)
|
|
129
|
+
formData.append(key, value.toString());
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return formData;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function markAsTouchedWithoutEmitEvent(control: AbstractControl): void {
|
|
137
|
+
if (control instanceof FormControl) {
|
|
138
|
+
control.markAsTouched({onlySelf: true});
|
|
139
|
+
control.updateValueAndValidity({emitEvent: false});
|
|
140
|
+
}
|
|
141
|
+
else if (control instanceof FormGroup || control instanceof FormArray) {
|
|
142
|
+
Object.values(control.controls).forEach(childControl => {
|
|
143
|
+
markAsTouchedWithoutEmitEvent(childControl);
|
|
144
|
+
});
|
|
145
|
+
control.updateValueAndValidity({emitEvent: false});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
export interface SetControlDesdeListaConfig<T, V = any> {
|
|
151
|
+
lista$: BehaviorSubject<T[]>;
|
|
152
|
+
formControl?: FormControl<V>;
|
|
153
|
+
formGroup?: FormGroup;
|
|
154
|
+
controlName?: string;
|
|
155
|
+
idProp?: keyof T;
|
|
156
|
+
idValor?: any;
|
|
157
|
+
selector?: (item: T) => V;
|
|
158
|
+
usarPrimeraOpcion?: boolean; // ✅ nuevo
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function setControlDesdeLista<T, V = any>(
|
|
162
|
+
config: SetControlDesdeListaConfig<T, V>
|
|
163
|
+
): void {
|
|
164
|
+
const lista = config.lista$?.getValue() ?? [];
|
|
165
|
+
|
|
166
|
+
if (!lista.length) return;
|
|
167
|
+
|
|
168
|
+
let seleccionado: T | undefined;
|
|
169
|
+
|
|
170
|
+
if (config.idProp && config.idValor !== undefined) {
|
|
171
|
+
seleccionado = lista.find((item: any) => item[config.idProp] === config.idValor);
|
|
172
|
+
} else if (config.usarPrimeraOpcion) {
|
|
173
|
+
seleccionado = lista[0];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log(seleccionado);
|
|
177
|
+
if (!seleccionado) return;
|
|
178
|
+
|
|
179
|
+
let valor: V;
|
|
180
|
+
|
|
181
|
+
if (config.selector) {
|
|
182
|
+
valor = config.selector(seleccionado);
|
|
183
|
+
} else if (config.idProp) {
|
|
184
|
+
valor = seleccionado[config.idProp] as V;
|
|
185
|
+
} else {
|
|
186
|
+
valor = seleccionado as unknown as V;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (config.formControl) {
|
|
190
|
+
config.formControl.setValue(valor);
|
|
191
|
+
} else if (config.formGroup && config.controlName) {
|
|
192
|
+
const control = config.formGroup.get(config.controlName);
|
|
193
|
+
if (control instanceof FormControl) {
|
|
194
|
+
(control as FormControl<V>).setValue(valor);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
export function transformarFechasPorNombreDeCampo<T extends Record<string, any>>(formValue: T): T {
|
|
201
|
+
const retData: any = {};
|
|
202
|
+
|
|
203
|
+
Object.entries(formValue).forEach(([key, value]) => {
|
|
204
|
+
|
|
205
|
+
// ✅ No procesar Blob o File
|
|
206
|
+
if (value instanceof Blob || value instanceof File) {
|
|
207
|
+
retData[key] = value;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (value instanceof Date) {
|
|
212
|
+
if (/^d[A-Za-z]+/.test(key)) {
|
|
213
|
+
retData[key] = moment(value).format('YYYY-MM-DD');
|
|
214
|
+
} else {
|
|
215
|
+
retData[key] = new Date(Date.UTC(
|
|
216
|
+
value.getFullYear(),
|
|
217
|
+
value.getMonth(),
|
|
218
|
+
value.getDate(),
|
|
219
|
+
value.getHours(),
|
|
220
|
+
value.getMinutes(),
|
|
221
|
+
value.getSeconds()
|
|
222
|
+
));
|
|
223
|
+
}
|
|
224
|
+
} else if (/^dt[A-Za-z]+/.test(key) && typeof value === 'string') {
|
|
225
|
+
if (/\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d{3}/.test(value)) {
|
|
226
|
+
retData[key] = new Date(value + 'Z');
|
|
227
|
+
} 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)) {
|
|
228
|
+
retData[key] = new Date(value + ':00.000Z');
|
|
229
|
+
} else {
|
|
230
|
+
console.warn('FECHA INVALIDA AL ENVIAR (FormInter):', key, value);
|
|
231
|
+
retData[key] = value;
|
|
232
|
+
}
|
|
233
|
+
} else if (Array.isArray(value)) {
|
|
234
|
+
if (value.every(v => v instanceof File || v instanceof Blob)) {
|
|
235
|
+
retData[key] = value;
|
|
236
|
+
} else {
|
|
237
|
+
retData[key] = value.map(item =>
|
|
238
|
+
typeof item === 'object' && item !== null
|
|
239
|
+
? transformarFechasPorNombreDeCampo(item)
|
|
240
|
+
: item
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
244
|
+
retData[key] = transformarFechasPorNombreDeCampo(value);
|
|
245
|
+
} else {
|
|
246
|
+
retData[key] = value;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return retData;
|
|
251
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {HttpErrorResponse} from '@angular/common/http';
|
|
2
|
+
import {mensajeAlerta, mensajeToast} from './sweetalert';
|
|
3
|
+
|
|
4
|
+
export function mensajesDeError(error: HttpErrorResponse, toast = false) {
|
|
5
|
+
let msg;
|
|
6
|
+
|
|
7
|
+
if (error.error && error.error instanceof ArrayBuffer) {
|
|
8
|
+
const msgArrayBuffer = (arrayBuffer: ArrayBuffer): string => {
|
|
9
|
+
try {
|
|
10
|
+
const mensajeError = JSON.parse(new TextDecoder("utf-8").decode(arrayBuffer));
|
|
11
|
+
return mensajeError.message || 'Error desconocido';
|
|
12
|
+
} catch (parseError) {
|
|
13
|
+
console.error('Error al analizar la respuesta JSON:', parseError);
|
|
14
|
+
return 'Error al analizar la respuesta JSON';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
msg = msgArrayBuffer(error.error);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
|
|
21
|
+
switch (error.status) {
|
|
22
|
+
case 0:
|
|
23
|
+
// msg = error.message;
|
|
24
|
+
msg = 'El servidor no responde, verifica tu conexion a la red';
|
|
25
|
+
console.log(error);
|
|
26
|
+
break;
|
|
27
|
+
case 401:
|
|
28
|
+
if (error.error && typeof error.error == 'object') {
|
|
29
|
+
if (error.error.message) {
|
|
30
|
+
msg = error.error.message;
|
|
31
|
+
}
|
|
32
|
+
else if (error.error.error) {
|
|
33
|
+
msg = error.error.error;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
msg = JSON.stringify(error.error);
|
|
37
|
+
console.log(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (error.error && typeof error.error == 'string') {
|
|
41
|
+
msg = error.error;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
msg = 'Acceso no autorizado';
|
|
45
|
+
console.log(error);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case 422:
|
|
49
|
+
let strEr = '';
|
|
50
|
+
|
|
51
|
+
console.log(typeof error.error.errors);
|
|
52
|
+
console.log(error.error.errors);
|
|
53
|
+
if (error.error.errors) {
|
|
54
|
+
Object.keys(error.error.errors).forEach(o => {
|
|
55
|
+
strEr += '<li>' + error.error.errors[o][0] + '</li>';
|
|
56
|
+
});
|
|
57
|
+
msg = (error.error.message ?? '') + '<ul>' + strEr + '</ul>';
|
|
58
|
+
}
|
|
59
|
+
else if (error.error.error) {
|
|
60
|
+
msg = error.error.msg;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case 429:
|
|
64
|
+
case 400:
|
|
65
|
+
case 500:
|
|
66
|
+
case 503:
|
|
67
|
+
msg = error.error.message;
|
|
68
|
+
break;
|
|
69
|
+
case 504:
|
|
70
|
+
msg = 'No se puede conectar al servidor. Comprueba tu conexion a la red - ' + error.statusText;
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
msg = error?.error?.message ?? 'Error de Sistema';
|
|
74
|
+
console.log(error);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!msg) {
|
|
79
|
+
msg = error.statusText ?? 'Error inesperado o datos inexistentes.';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let tituloFinal = 'Error!';
|
|
83
|
+
let mensajeFinal;
|
|
84
|
+
|
|
85
|
+
if (msg.includes('Hmac::doVerify')) {
|
|
86
|
+
console.log(error, msg);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
else if (msg == 'Server Error') {
|
|
90
|
+
console.log(error, msg);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
else if (msg.includes('[IMSSP]')) {
|
|
94
|
+
mensajeFinal = 'Error en consulta de registros.';
|
|
95
|
+
}
|
|
96
|
+
else if (msg.includes('Tiempo de espera de la')) {
|
|
97
|
+
mensajeFinal = 'Hubo un error en la solicitud de datos, por favor actualice (SHIFT + F5)';
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
mensajeFinal = msg;
|
|
101
|
+
}
|
|
102
|
+
if (toast) {
|
|
103
|
+
mensajeToast('error', tituloFinal, mensajeFinal);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
mensajeAlerta('error', tituloFinal, mensajeFinal);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
throw new Error(mensajeFinal);
|
|
110
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './public-api'
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
import {jwtDecode} from 'jwt-decode';
|
|
3
|
+
|
|
4
|
+
export interface JwtTokenResponse {
|
|
5
|
+
access_token: string;
|
|
6
|
+
expires_in: number;
|
|
7
|
+
token_type: string;
|
|
8
|
+
user: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DataSessionStorage {
|
|
12
|
+
tokenStringKey?: string;
|
|
13
|
+
changePasswordKey?: string;
|
|
14
|
+
logoUrl?: string;
|
|
15
|
+
logoLogin?: string;
|
|
16
|
+
backgroundLogin?: string;
|
|
17
|
+
favicon?: string;
|
|
18
|
+
darkMode?: string;
|
|
19
|
+
serverTimestamp?: string;
|
|
20
|
+
apiDataKey?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let dataSessionStorageKey: DataSessionStorage = {
|
|
24
|
+
tokenStringKey: 'JVSoftTkn',
|
|
25
|
+
changePasswordKey: 'chPwd',
|
|
26
|
+
logoUrl: 'logo_url',
|
|
27
|
+
logoLogin: 'login-logo',
|
|
28
|
+
backgroundLogin: 'login-background',
|
|
29
|
+
favicon: 'favicon',
|
|
30
|
+
darkMode: 'darkMode',
|
|
31
|
+
serverTimestamp: 'srvtmstp',
|
|
32
|
+
apiDataKey: 'reqDt',
|
|
33
|
+
};
|
|
34
|
+
export let localStorageKeys = dataSessionStorageKey;
|
|
35
|
+
|
|
36
|
+
export function inicializarVariablesSessionStorage(datSesion: DataSessionStorage) {
|
|
37
|
+
dataSessionStorageKey = datSesion;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setJwtTokenData(data: string) {
|
|
41
|
+
localStorage.setItem(<string>dataSessionStorageKey.tokenStringKey, data)
|
|
42
|
+
}
|
|
43
|
+
export function jwtTokenData(key: string = <string>dataSessionStorageKey.tokenStringKey): JwtTokenResponse | null {
|
|
44
|
+
const tokenObj = localStorage.getItem(key);
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(<string>tokenObj) as JwtTokenResponse;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function jwtToken(key: string = <string>dataSessionStorageKey.tokenStringKey) {
|
|
53
|
+
const varJwtTokenData = jwtTokenData(key);
|
|
54
|
+
if (varJwtTokenData) {
|
|
55
|
+
return varJwtTokenData.access_token;
|
|
56
|
+
}
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function jwtTokenExpiracion(key: string = <string>dataSessionStorageKey.tokenStringKey) {
|
|
61
|
+
const jwtStr = jwtToken(key);
|
|
62
|
+
if (!jwtStr) return null;
|
|
63
|
+
try {
|
|
64
|
+
const decodedToken: any = jwtDecode(jwtStr);
|
|
65
|
+
return decodedToken.exp ? decodedToken.exp * 1000:null; // Convertir a milisegundos
|
|
66
|
+
} catch (e) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function jwtTokenExpiracionFaltante() {
|
|
72
|
+
return Math.abs(moment().diff(jwtTokenExpiracion(), 'seconds'));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function setCambiarPwd(accion: boolean = true) {
|
|
76
|
+
localStorage.setItem(<string>dataSessionStorageKey.changePasswordKey, (accion ? 1:0).toString())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function getCambiarPwd() {
|
|
80
|
+
const frmCambioPwd = localStorage.getItem(<string>dataSessionStorageKey.changePasswordKey);
|
|
81
|
+
if (!frmCambioPwd) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return frmCambioPwd == '1';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function delLocalStorage(keyElim: string[] = [
|
|
88
|
+
<string>dataSessionStorageKey.tokenStringKey,
|
|
89
|
+
<string>dataSessionStorageKey.changePasswordKey,
|
|
90
|
+
<string>dataSessionStorageKey.apiDataKey,
|
|
91
|
+
]) {
|
|
92
|
+
keyElim.forEach(key => {
|
|
93
|
+
localStorage.removeItem(key);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getLocalStorage(key: string | undefined) {
|
|
98
|
+
return localStorage.getItem(<string>key);
|
|
99
|
+
}
|
|
100
|
+
export function setLocalStorage(key: string, value = '') {
|
|
101
|
+
localStorage.setItem(key, value.toString())
|
|
102
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {esNumero} from '../objects-arrays';
|
|
2
|
+
import {AbstractControl} from '@angular/forms';
|
|
3
|
+
import {untilDestroyed} from '@ngneat/until-destroy';
|
|
4
|
+
import {debounceTime, finalize, isObservable, of, startWith, switchMap, tap} from 'rxjs';
|
|
5
|
+
import {map} from 'rxjs/operators';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Devuelve un valor de visualización para un elemento buscado.
|
|
9
|
+
* Compatible con listas simples, objetos y campos múltiples.
|
|
10
|
+
*/
|
|
11
|
+
export function mostrarValorEnBusqueda(campos: any, idxSel: any) {
|
|
12
|
+
const buscarEnLista = (lista: any[]) => {
|
|
13
|
+
if (!lista) return null;
|
|
14
|
+
if (campos.campoId === '*object*' || campos.campoId === '*objeto*') {
|
|
15
|
+
return lista.find((x: any) => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
|
|
16
|
+
}
|
|
17
|
+
return lista.find((x: any) => x[campos.campoId] === idxSel);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const impDataMostrar = () => {
|
|
21
|
+
let vD = buscarEnLista(campos.lista) || (campos.opcExtra && buscarEnLista(campos.opcExtra));
|
|
22
|
+
if (!vD) return '';
|
|
23
|
+
|
|
24
|
+
if (Array.isArray(campos.campoValue)) {
|
|
25
|
+
return campos.campoValue.map((vCampo: any) => vD[vCampo] ?? '').join(' - ').trim();
|
|
26
|
+
}
|
|
27
|
+
return (vD[campos.campoValue] ?? '').trim();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (esNumero(idxSel)) {
|
|
31
|
+
if ((idxSel > 0 && campos.lista?.length) || (idxSel && typeof idxSel === 'object')) {
|
|
32
|
+
return impDataMostrar();
|
|
33
|
+
}
|
|
34
|
+
} else if (campos.lista?.length) {
|
|
35
|
+
return impDataMostrar();
|
|
36
|
+
}
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Filtra datos locales de un array basado en un valor de búsqueda.
|
|
42
|
+
*/
|
|
43
|
+
function filtrarDatosLocal(data: any[], value: any, campoBuscar: string | string[]) {
|
|
44
|
+
if (!value) return data;
|
|
45
|
+
|
|
46
|
+
const normalizar = (val: any) => val?.toString()?.toLowerCase() ?? '';
|
|
47
|
+
const esNum = !isNaN(Number(value));
|
|
48
|
+
|
|
49
|
+
return data.filter(item => {
|
|
50
|
+
const campos = Array.isArray(campoBuscar) ? campoBuscar : [campoBuscar];
|
|
51
|
+
return campos.some(campo => {
|
|
52
|
+
const campoVal = item[campo];
|
|
53
|
+
if (campoVal == null) return false;
|
|
54
|
+
return esNum
|
|
55
|
+
? campoVal.toString().includes(value.toString())
|
|
56
|
+
: normalizar(campoVal).includes(normalizar(value));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Vincula un FormControl a datos locales para autocompletado.
|
|
63
|
+
*/
|
|
64
|
+
export function changeSelectData(objThis: any, { formControl, data, campoBuscar, variableResultado }: {
|
|
65
|
+
formControl: AbstractControl;
|
|
66
|
+
data: any[];
|
|
67
|
+
campoBuscar: string | string[];
|
|
68
|
+
variableResultado: string;
|
|
69
|
+
}) {
|
|
70
|
+
objThis.filtrados[variableResultado] = formControl.valueChanges.pipe(untilDestroyed(objThis)).pipe(
|
|
71
|
+
startWith(''),
|
|
72
|
+
map(value => data ? filtrarDatosLocal(data, value, campoBuscar) : [])
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Vincula un FormControl a datos locales obtenidos de dataServidor o dataServidorSuscripcion.
|
|
78
|
+
*/
|
|
79
|
+
export function changeSelect(control: any, formControl: AbstractControl, tipo: string, campoBuscar: string | string[], campoFiltro: string | null = null) {
|
|
80
|
+
const filtro = campoFiltro ?? tipo;
|
|
81
|
+
control.filtrados[filtro] = formControl.valueChanges.pipe(untilDestroyed(control)).pipe(
|
|
82
|
+
startWith(''),
|
|
83
|
+
map(value => {
|
|
84
|
+
const partes = tipo.split('.');
|
|
85
|
+
const varN =
|
|
86
|
+
control.dataServidor?.[partes[0]]?.[partes[1]] ??
|
|
87
|
+
control.dataServidor?.[tipo] ??
|
|
88
|
+
control.dataServidorSuscripcion?.[tipo]?.getValue();
|
|
89
|
+
|
|
90
|
+
return varN ? filtrarDatosLocal(varN, value, campoBuscar) : [];
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Configuración para changeSelectReformateado.
|
|
97
|
+
*/
|
|
98
|
+
interface ChangeSelectConfig {
|
|
99
|
+
objThis: any;
|
|
100
|
+
tipoReq: string;
|
|
101
|
+
formControl: AbstractControl;
|
|
102
|
+
queryService: any;
|
|
103
|
+
campoId?: string;
|
|
104
|
+
minLength?: number;
|
|
105
|
+
dataExtra?: any;
|
|
106
|
+
dataExtraVariable?: { campo: string; ctrlValue: AbstractControl }[];
|
|
107
|
+
anonimo?: boolean;
|
|
108
|
+
variableResultado?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Función genérica para vincular un FormControl con datos desde API o Promise.
|
|
113
|
+
* Preparada para migrar a signals en el futuro.
|
|
114
|
+
*/
|
|
115
|
+
export function changeSelectReformateado(config: ChangeSelectConfig) {
|
|
116
|
+
const {
|
|
117
|
+
objThis,
|
|
118
|
+
tipoReq,
|
|
119
|
+
formControl,
|
|
120
|
+
queryService,
|
|
121
|
+
campoId,
|
|
122
|
+
minLength = 3,
|
|
123
|
+
dataExtra = {},
|
|
124
|
+
dataExtraVariable = [],
|
|
125
|
+
anonimo = false,
|
|
126
|
+
variableResultado = tipoReq,
|
|
127
|
+
} = config;
|
|
128
|
+
|
|
129
|
+
formControl.valueChanges.pipe(
|
|
130
|
+
debounceTime(500),
|
|
131
|
+
tap(() => {
|
|
132
|
+
objThis.filtrados[variableResultado + 'tmp'] = isObservable(objThis.filtrados[variableResultado])
|
|
133
|
+
? []
|
|
134
|
+
: objThis.filtrados[variableResultado] || [];
|
|
135
|
+
if (objThis.filtrados[variableResultado] !== objThis.filtrados[variableResultado + 'tmp']) {
|
|
136
|
+
objThis.filtrados[variableResultado] = [];
|
|
137
|
+
}
|
|
138
|
+
objThis.isLoading = true;
|
|
139
|
+
}),
|
|
140
|
+
switchMap(value => {
|
|
141
|
+
if (campoId) {
|
|
142
|
+
const existe = objThis.filtrados[variableResultado + 'tmp']
|
|
143
|
+
.findIndex((item: any) => item[campoId] === value);
|
|
144
|
+
if (existe >= 0) {
|
|
145
|
+
return of({ [tipoReq]: objThis.filtrados[variableResultado + 'tmp'] });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!value || value.length < minLength) {
|
|
149
|
+
objThis.isLoading = false;
|
|
150
|
+
return of({ [tipoReq]: [] });
|
|
151
|
+
}
|
|
152
|
+
const extraVars = Object.fromEntries(dataExtraVariable.map(v => [v.campo, v.ctrlValue.value]));
|
|
153
|
+
const query = queryService.getDataMethod('GET', tipoReq, { ...dataExtra, ...extraVars, txtBuscar: value }, anonimo);
|
|
154
|
+
|
|
155
|
+
if (esPromise(query)) {
|
|
156
|
+
return query.then((data: any) => ({ [tipoReq]: data[tipoReq] ?? [] }))
|
|
157
|
+
.finally(() => { objThis.isLoading = false; });
|
|
158
|
+
}
|
|
159
|
+
return query.pipe(finalize(() => { objThis.isLoading = false; }));
|
|
160
|
+
})
|
|
161
|
+
).subscribe((data: any) => {
|
|
162
|
+
objThis.filtrados[variableResultado] = data[tipoReq] ?? [];
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Alias para compatibilidad.
|
|
168
|
+
*/
|
|
169
|
+
export function changeSelectDataApi(objThis: any, dataFiltro: any) {
|
|
170
|
+
return changeSelectReformateado({
|
|
171
|
+
objThis,
|
|
172
|
+
tipoReq: dataFiltro.tipoReq,
|
|
173
|
+
formControl: dataFiltro.formControl,
|
|
174
|
+
queryService: dataFiltro.queryService,
|
|
175
|
+
campoId: dataFiltro.campoId,
|
|
176
|
+
minLength: dataFiltro.minLength,
|
|
177
|
+
dataExtra: dataFiltro.dataExtra,
|
|
178
|
+
dataExtraVariable: dataFiltro.dataExtraVariable,
|
|
179
|
+
anonimo: dataFiltro.anonimo,
|
|
180
|
+
variableResultado: dataFiltro.variableResultado,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Alias para compatibilidad.
|
|
186
|
+
*/
|
|
187
|
+
export function changeSelectApi(control: any, queryService: any, formControl: AbstractControl, tipo: any, dataExtra = {}, dataExtraVariable: any[] | null = null, minLength = 1, anonimo = false) {
|
|
188
|
+
return changeSelectReformateado({
|
|
189
|
+
objThis: control,
|
|
190
|
+
tipoReq: tipo,
|
|
191
|
+
formControl,
|
|
192
|
+
queryService,
|
|
193
|
+
minLength,
|
|
194
|
+
dataExtra,
|
|
195
|
+
dataExtraVariable: dataExtraVariable ?? [],
|
|
196
|
+
anonimo,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Comprueba si un valor es una Promesa.
|
|
202
|
+
*/
|
|
203
|
+
function esPromise(valor: any): valor is Promise<any> {
|
|
204
|
+
return !!valor && typeof valor.then === 'function';
|
|
205
|
+
}
|