sf-documents 0.1.9 → 0.1.11

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.
@@ -1,22 +1,25 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Pipe, InjectionToken, EventEmitter, ViewChild, Output, Input, Component, inject, ElementRef } from '@angular/core';
3
3
  import { BehaviorSubject, Subject, of } from 'rxjs';
4
- import * as i2$1 from 'primeng/api';
5
- import { ConfirmationService } from 'primeng/api';
4
+ import * as i2 from 'primeng/api';
5
+ import { ConfirmationService, MessageService } from 'primeng/api';
6
+ import * as i4$2 from 'primeng/toast';
6
7
  import { ToastModule } from 'primeng/toast';
8
+ import * as i15 from 'primeng/message';
9
+ import { MessageModule } from 'primeng/message';
7
10
  import * as _ from 'lodash';
8
- import * as i1$1 from 'primeng/button';
11
+ import * as i3 from 'primeng/button';
9
12
  import { ButtonModule } from 'primeng/button';
10
- import * as i5$1 from 'primeng/confirmdialog';
13
+ import * as i6$1 from 'primeng/confirmdialog';
11
14
  import { ConfirmDialogModule } from 'primeng/confirmdialog';
12
15
  import { PanelModule } from 'primeng/panel';
13
- import * as i4 from 'primeng/checkbox';
16
+ import * as i4$1 from 'primeng/checkbox';
14
17
  import { CheckboxModule } from 'primeng/checkbox';
15
- import * as i7$1 from 'primeng/dialog';
18
+ import * as i4 from 'primeng/dialog';
16
19
  import { DialogModule } from 'primeng/dialog';
17
- import * as i8 from '@angular/common';
20
+ import * as i9 from '@angular/common';
18
21
  import { CommonModule, registerLocaleData, DatePipe } from '@angular/common';
19
- import * as i2 from '@angular/forms';
22
+ import * as i2$1 from '@angular/forms';
20
23
  import { FormsModule } from '@angular/forms';
21
24
  import * as i1 from '@angular/platform-browser';
22
25
  import * as i5 from 'primeng/inputtext';
@@ -29,11 +32,11 @@ import { debounceTime, distinctUntilChanged, takeUntil, tap, switchMap, finalize
29
32
  import * as i7 from 'primeng/select';
30
33
  import { SelectModule } from 'primeng/select';
31
34
  import localeEs from '@angular/common/locales/es';
32
- import * as i11 from 'primeng/dropdown';
35
+ import * as i12 from 'primeng/dropdown';
33
36
  import { DropdownModule } from 'primeng/dropdown';
34
- import * as i12 from 'primeng/datepicker';
37
+ import * as i13 from 'primeng/datepicker';
35
38
  import { DatePickerModule } from 'primeng/datepicker';
36
- import * as i13 from 'primeng/skeleton';
39
+ import * as i14 from 'primeng/skeleton';
37
40
  import { SkeletonModule } from 'primeng/skeleton';
38
41
 
39
42
  class SfDocumentsService {
@@ -88,10 +91,12 @@ const DOCUMENT_SERVICE = new InjectionToken('DOCUMENT_SERVICE');
88
91
  * decisión de negocio (qué tipos de documento se aceptan).
89
92
  */
90
93
  const DEFAULT_ALLOWED_UPLOAD_EXTENSIONS = ['.pdf', '.xls', '.xlsx'];
94
+ const MAX_POR_ARCHIVO = 25 * 1024 * 1024; // 25 MB
95
+ const MAX_POR_LOTE = 100 * 1024 * 1024; // 100 MB
91
96
  const MIME_TYPES_BY_EXTENSION = {
92
97
  '.pdf': 'application/pdf',
93
98
  '.xls': 'application/vnd.ms-excel',
94
- '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
99
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
95
100
  };
96
101
  /**
97
102
  * Extensiones que el navegador puede renderizar inline dentro de un <embed>/<iframe>.
@@ -99,7 +104,16 @@ const MIME_TYPES_BY_EXTENSION = {
99
104
  * decisión de negocio, así que la librería la conoce de antemano (evita que el host
100
105
  * marque como "previsualizable" un tipo que en realidad nunca se va a renderizar).
101
106
  */
102
- const PREVIEWABLE_EXTENSIONS = ['.pdf', '.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg'];
107
+ const PREVIEWABLE_EXTENSIONS = [
108
+ '.pdf',
109
+ '.jpg',
110
+ '.jpeg',
111
+ '.png',
112
+ '.gif',
113
+ '.webp',
114
+ '.bmp',
115
+ '.svg',
116
+ ];
103
117
  const ICON_BY_EXTENSION = {
104
118
  '.pdf': 'pi-file-pdf',
105
119
  '.xls': 'pi-file-excel',
@@ -112,31 +126,55 @@ const ICON_BY_EXTENSION = {
112
126
  '.gif': 'pi-image',
113
127
  '.webp': 'pi-image',
114
128
  '.bmp': 'pi-image',
115
- '.svg': 'pi-image'
129
+ '.svg': 'pi-image',
116
130
  };
117
131
  /** Normaliza una lista de extensiones dada por el host (con o sin punto, mayúsc/minúsc). */
118
132
  function normalizeExtensions(extensions, fallback) {
119
133
  const list = extensions && extensions.length ? extensions : fallback;
120
134
  return list
121
- .map(ext => ext.trim().toLowerCase())
122
- .filter(ext => !!ext)
123
- .map(ext => (ext.startsWith('.') ? ext : `.${ext}`));
135
+ .map((ext) => ext.trim().toLowerCase())
136
+ .filter((ext) => !!ext)
137
+ .map((ext) => (ext.startsWith('.') ? ext : `.${ext}`));
124
138
  }
125
139
  /** Arma el atributo `accept` del input file a partir de las extensiones permitidas. */
126
140
  function buildAcceptAttr(extensions) {
127
- const mimeTypes = extensions.map(ext => MIME_TYPES_BY_EXTENSION[ext]).filter((m) => !!m);
141
+ const mimeTypes = extensions
142
+ .map((ext) => MIME_TYPES_BY_EXTENSION[ext])
143
+ .filter((m) => !!m);
128
144
  return [...new Set([...mimeTypes, ...extensions])].join(',');
129
145
  }
130
146
  function hasExtension(fileName, extensions) {
131
147
  if (!fileName)
132
148
  return false;
133
149
  const lower = fileName.toLowerCase();
134
- return extensions.some(ext => lower.endsWith(ext));
150
+ return extensions.some((ext) => lower.endsWith(ext));
135
151
  }
136
152
  function isAllowedUploadFile(file, extensions) {
137
- const mimeTypes = extensions.map(ext => MIME_TYPES_BY_EXTENSION[ext]).filter((m) => !!m);
153
+ const mimeTypes = extensions
154
+ .map((ext) => MIME_TYPES_BY_EXTENSION[ext])
155
+ .filter((m) => !!m);
138
156
  return mimeTypes.includes(file.type) || hasExtension(file.name, extensions);
139
157
  }
158
+ /** Formatea un tamaño en bytes a MB con un decimal (ej. "12.3 MB"). */
159
+ function formatFileSizeMB(bytes) {
160
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
161
+ }
162
+ /** Tamaño total en bytes de un conjunto de archivos. */
163
+ function getBatchSize(files) {
164
+ return files.reduce((total, file) => total + file.size, 0);
165
+ }
166
+ /** Separa los archivos según superen o no el tamaño máximo permitido por archivo. */
167
+ function splitFilesByMaxSize(files, maxFileSize) {
168
+ const allowed = [];
169
+ const rejected = [];
170
+ files.forEach((file) => {
171
+ if (file.size > maxFileSize)
172
+ rejected.push({ name: file.name, size: file.size });
173
+ else
174
+ allowed.push(file);
175
+ });
176
+ return { allowed, rejected };
177
+ }
140
178
  /** true si el navegador puede mostrar este archivo inline en un <embed>/<iframe>. */
141
179
  function canPreviewFile(name) {
142
180
  return hasExtension(name, PREVIEWABLE_EXTENSIONS);
@@ -146,24 +184,42 @@ function getFileTypeIcon(name) {
146
184
  if (!name)
147
185
  return 'pi-file';
148
186
  const lower = name.toLowerCase();
149
- const match = Object.keys(ICON_BY_EXTENSION).find(ext => lower.endsWith(ext));
187
+ const match = Object.keys(ICON_BY_EXTENSION).find((ext) => lower.endsWith(ext));
150
188
  return match ? ICON_BY_EXTENSION[match] : 'pi-file';
151
189
  }
152
190
 
191
+ /**
192
+ * `key` de los avisos de la librería. Solo los pinta el `<p-toast>` de `SfDocumentsComponent`:
193
+ * un `<p-toast>` del host sin `key` (o con otra) no los muestra, así que no salen duplicados.
194
+ */
195
+ const SF_DOCUMENTS_TOAST_KEY = 'sf-documents';
196
+
153
197
  class UploadDialogComponent {
198
+ messageService;
154
199
  selectedDocument;
155
200
  /** Extensiones permitidas para subir (ej. ['.pdf', '.xlsx']). Si no se define, usa el default de la librería. */
156
201
  allowedExtensions;
157
202
  onUploaded = new EventEmitter();
158
203
  loadFile = new EventEmitter();
159
204
  fileInput;
160
- constructor() { }
205
+ maxFileSize = MAX_POR_ARCHIVO;
206
+ maxBatchSize = MAX_POR_LOTE;
207
+ displayOversizedDialog = false;
208
+ allowedFiles = [];
209
+ rejectedFiles = [];
210
+ pendingTagValue;
211
+ constructor(messageService) {
212
+ this.messageService = messageService;
213
+ }
161
214
  get normalizedExtensions() {
162
215
  return normalizeExtensions(this.allowedExtensions, DEFAULT_ALLOWED_UPLOAD_EXTENSIONS);
163
216
  }
164
217
  get acceptedFileTypes() {
165
218
  return buildAcceptAttr(this.normalizedExtensions);
166
219
  }
220
+ formatSize(bytes) {
221
+ return formatFileSizeMB(bytes);
222
+ }
167
223
  loadFileClick() {
168
224
  this.loadFile.emit();
169
225
  this.fileInput.nativeElement.value = '';
@@ -175,17 +231,50 @@ class UploadDialogComponent {
175
231
  return;
176
232
  const files = Array.from(input.files);
177
233
  const validFiles = files.filter(f => isAllowedUploadFile(f, this.normalizedExtensions));
178
- const imagePathInput = input.value;
179
- if (validFiles?.length)
180
- this.onUploaded.emit({ fileList: validFiles, tagValue: imagePathInput });
234
+ const tagValue = input.value;
235
+ if (!validFiles.length)
236
+ return;
237
+ if (getBatchSize(validFiles) > this.maxBatchSize) {
238
+ this.addMessage('error', 'Lote demasiado grande', `El lote seleccionado supera el tamaño máximo permitido de ${this.formatSize(this.maxBatchSize)}.`);
239
+ return;
240
+ }
241
+ const { allowed, rejected } = splitFilesByMaxSize(validFiles, this.maxFileSize);
242
+ if (!rejected.length) {
243
+ this.onUploaded.emit({ fileList: allowed, tagValue });
244
+ return;
245
+ }
246
+ this.allowedFiles = allowed;
247
+ this.rejectedFiles = rejected;
248
+ this.pendingTagValue = tagValue;
249
+ this.displayOversizedDialog = true;
250
+ }
251
+ continuarConPermitidos() {
252
+ this.displayOversizedDialog = false;
253
+ if (this.allowedFiles.length) {
254
+ this.onUploaded.emit({ fileList: this.allowedFiles, tagValue: this.pendingTagValue });
255
+ }
256
+ this.limpiarSeleccionRechazada();
257
+ }
258
+ cancelarEnvio() {
259
+ this.displayOversizedDialog = false;
260
+ this.limpiarSeleccionRechazada();
261
+ }
262
+ limpiarSeleccionRechazada() {
263
+ this.allowedFiles = [];
264
+ this.rejectedFiles = [];
265
+ this.pendingTagValue = null;
181
266
  }
182
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UploadDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
183
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: UploadDialogComponent, isStandalone: true, selector: "lib-upload-dialog", inputs: { selectedDocument: "selectedDocument", allowedExtensions: "allowedExtensions" }, outputs: { onUploaded: "onUploaded", loadFile: "loadFile" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, static: true }], ngImport: i0, template: "<input\r\n #fileInput\r\n type=\"file\"\r\n (change)=\"fileChange($event)\"\r\n class=\"hidden\"\r\n placeholder=\"Upload file\"\r\n [attr.accept]=\"acceptedFileTypes\"\r\n multiple\r\n/>\r\n<button\r\n pButton\r\n type=\"button\"\r\n label=\"Subir archivo\"\r\n icon=\"pi pi-upload\"\r\n class=\"p-button-outlined ff-btn-upload\"\r\n (click)=\"loadFileClick()\"\r\n></button>\r\n\r\n<!-- <p-dialog [header] = \"'Adicionar ' + selectedDocument.label\" [(visible)]=\"visible\" [modal]=\"true\" [style]=\"{ width: '30rem' }\" [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\r\nposition = \"top\" [closable]=\"true\" (onHide)=\"visible=false\">\r\n <div class=\"mt-3\">\r\n <div class=\"text-center\">\r\n <input #fileInput type=\"file\" (change)=\"fileChange($event)\" class=\"hidden\"\r\n placeholder=\"Upload file\" [attr.accept]=\"acceptedFileTypes\" multiple>\r\n </div>\r\n <div class=\"text-center\">\r\n <p-button\r\n icon=\"pi pi-upload\"\r\n (click)=\"loadFileClick()\"\r\n [text] = \"true\"\r\n [rounded]=\"true\"\r\n ></p-button>\r\n\r\n <label *ngIf=\"isMobile\" (click)=\"openModal2(scanContent)\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">camera_alt</mat-icon>\r\n </label> \r\n </div>\r\n </div>\r\n</p-dialog> -->\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: DialogModule }] });
267
+ addMessage(severity, summary, detail) {
268
+ // Usa el MessageService y el <p-toast> de SfDocumentsComponent (ver SF_DOCUMENTS_TOAST_KEY).
269
+ this.messageService.add({ key: SF_DOCUMENTS_TOAST_KEY, severity, summary, detail, life: 4000 });
270
+ }
271
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UploadDialogComponent, deps: [{ token: i2.MessageService }], target: i0.ɵɵFactoryTarget.Component });
272
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: UploadDialogComponent, isStandalone: true, selector: "lib-upload-dialog", inputs: { selectedDocument: "selectedDocument", allowedExtensions: "allowedExtensions" }, outputs: { onUploaded: "onUploaded", loadFile: "loadFile" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, static: true }], ngImport: i0, template: "<input\n #fileInput\n type=\"file\"\n (change)=\"fileChange($event)\"\n class=\"hidden\"\n placeholder=\"Upload file\"\n [attr.accept]=\"acceptedFileTypes\"\n multiple\n/>\n<button\n pButton\n type=\"button\"\n label=\"Subir archivo\"\n icon=\"pi pi-upload\"\n class=\"p-button-outlined ff-btn-upload\"\n (click)=\"loadFileClick()\"\n></button>\n\n<p-dialog\n header=\"Archivos que superan el tama\u00F1o permitido\"\n [(visible)]=\"displayOversizedDialog\"\n [modal]=\"true\"\n [closable]=\"false\"\n [style]=\"{ width: '32rem' }\"\n [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\n>\n <p>\n Tama\u00F1o m\u00E1ximo por archivo:\n <strong>{{ formatSize(maxFileSize) }}</strong>\n </p>\n\n <div class=\"oversized-section\">\n <p class=\"oversized-title\">Archivos rechazados:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of rejectedFiles\">\n {{ file.name }} \u2014 {{ formatSize(file.size) }}\n </li>\n </ul>\n </div>\n\n <div class=\"oversized-section\" *ngIf=\"allowedFiles.length\">\n <p class=\"oversized-title\">Archivos que s\u00ED se enviar\u00E1n:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of allowedFiles\">{{ file.name }}</li>\n </ul>\n </div>\n <p *ngIf=\"!allowedFiles.length\">No hay archivos v\u00E1lidos para enviar.</p>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"cancelarEnvio()\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n label=\"Continuar\"\n icon=\"pi pi-upload\"\n [disabled]=\"!allowedFiles.length\"\n (click)=\"continuarConPermitidos()\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [".oversized-section{margin-bottom:1rem}.oversized-section .oversized-title{font-weight:600;margin-bottom:.25rem}.oversized-section .oversized-list{margin:0;padding-left:1.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }] });
184
273
  }
185
274
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UploadDialogComponent, decorators: [{
186
275
  type: Component,
187
- args: [{ selector: 'lib-upload-dialog', imports: [CommonModule, ButtonModule, DialogModule], template: "<input\r\n #fileInput\r\n type=\"file\"\r\n (change)=\"fileChange($event)\"\r\n class=\"hidden\"\r\n placeholder=\"Upload file\"\r\n [attr.accept]=\"acceptedFileTypes\"\r\n multiple\r\n/>\r\n<button\r\n pButton\r\n type=\"button\"\r\n label=\"Subir archivo\"\r\n icon=\"pi pi-upload\"\r\n class=\"p-button-outlined ff-btn-upload\"\r\n (click)=\"loadFileClick()\"\r\n></button>\r\n\r\n<!-- <p-dialog [header] = \"'Adicionar ' + selectedDocument.label\" [(visible)]=\"visible\" [modal]=\"true\" [style]=\"{ width: '30rem' }\" [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\r\nposition = \"top\" [closable]=\"true\" (onHide)=\"visible=false\">\r\n <div class=\"mt-3\">\r\n <div class=\"text-center\">\r\n <input #fileInput type=\"file\" (change)=\"fileChange($event)\" class=\"hidden\"\r\n placeholder=\"Upload file\" [attr.accept]=\"acceptedFileTypes\" multiple>\r\n </div>\r\n <div class=\"text-center\">\r\n <p-button\r\n icon=\"pi pi-upload\"\r\n (click)=\"loadFileClick()\"\r\n [text] = \"true\"\r\n [rounded]=\"true\"\r\n ></p-button>\r\n\r\n <label *ngIf=\"isMobile\" (click)=\"openModal2(scanContent)\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">camera_alt</mat-icon>\r\n </label> \r\n </div>\r\n </div>\r\n</p-dialog> -->\r\n" }]
188
- }], ctorParameters: () => [], propDecorators: { selectedDocument: [{
276
+ args: [{ selector: 'lib-upload-dialog', imports: [CommonModule, ButtonModule, DialogModule], template: "<input\n #fileInput\n type=\"file\"\n (change)=\"fileChange($event)\"\n class=\"hidden\"\n placeholder=\"Upload file\"\n [attr.accept]=\"acceptedFileTypes\"\n multiple\n/>\n<button\n pButton\n type=\"button\"\n label=\"Subir archivo\"\n icon=\"pi pi-upload\"\n class=\"p-button-outlined ff-btn-upload\"\n (click)=\"loadFileClick()\"\n></button>\n\n<p-dialog\n header=\"Archivos que superan el tama\u00F1o permitido\"\n [(visible)]=\"displayOversizedDialog\"\n [modal]=\"true\"\n [closable]=\"false\"\n [style]=\"{ width: '32rem' }\"\n [breakpoints]=\"{ '1199px': '75vw', '575px': '90vw' }\"\n>\n <p>\n Tama\u00F1o m\u00E1ximo por archivo:\n <strong>{{ formatSize(maxFileSize) }}</strong>\n </p>\n\n <div class=\"oversized-section\">\n <p class=\"oversized-title\">Archivos rechazados:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of rejectedFiles\">\n {{ file.name }} \u2014 {{ formatSize(file.size) }}\n </li>\n </ul>\n </div>\n\n <div class=\"oversized-section\" *ngIf=\"allowedFiles.length\">\n <p class=\"oversized-title\">Archivos que s\u00ED se enviar\u00E1n:</p>\n <ul class=\"oversized-list\">\n <li *ngFor=\"let file of allowedFiles\">{{ file.name }}</li>\n </ul>\n </div>\n <p *ngIf=\"!allowedFiles.length\">No hay archivos v\u00E1lidos para enviar.</p>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"cancelarEnvio()\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n label=\"Continuar\"\n icon=\"pi pi-upload\"\n [disabled]=\"!allowedFiles.length\"\n (click)=\"continuarConPermitidos()\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [".oversized-section{margin-bottom:1rem}.oversized-section .oversized-title{font-weight:600;margin-bottom:.25rem}.oversized-section .oversized-list{margin:0;padding-left:1.25rem}\n"] }]
277
+ }], ctorParameters: () => [{ type: i2.MessageService }], propDecorators: { selectedDocument: [{
189
278
  type: Input
190
279
  }], allowedExtensions: [{
191
280
  type: Input
@@ -457,7 +546,7 @@ class FolderFilesComponent {
457
546
  this.loadFiles();
458
547
  }
459
548
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FolderFilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
460
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: FolderFilesComponent, isStandalone: true, selector: "lib-folder-files", inputs: { carpeta: "carpeta", isMobile: "isMobile", idKatios: "idKatios", server: "server", subestado: "subestado", requestData: "requestData", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes" }, outputs: { onFileChange: "onFileChange", onCargarArchivo: "onCargarArchivo", onEliminarMasivo: "onEliminarMasivo", onBack: "onBack", viewDocument: "viewDocument" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"ff-layout\">\r\n <!-- Header fijo -->\r\n <div class=\"ff-header\">\r\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-arrow-left\"\r\n label=\"Volver\"\r\n (click)=\"goBack()\"\r\n ></button>\r\n </div>\r\n\r\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\r\n <div class=\"ff-toolbar\">\r\n <p-iconfield class=\"ff-toolbar__search\">\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n [placeholder]=\"\r\n 'Buscar en ' +\r\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\r\n \"\r\n [(ngModel)]=\"searchQuery\"\r\n (input)=\"onSearchInput()\"\r\n class=\"w-full\"\r\n />\r\n </p-iconfield>\r\n\r\n <div class=\"ff-toolbar__actions\">\r\n <lib-upload-dialog\r\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\r\n [selectedDocument]=\"carpeta\"\r\n [allowedExtensions]=\"allowedUploadTypes\"\r\n (onUploaded)=\"fileChange($event)\"\r\n (loadFile)=\"cargarArchivo()\"\r\n >\r\n </lib-upload-dialog>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-trash\"\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n (click)=\"emitEliminarMasivo()\"\r\n [disabled]=\"docsEliminables.length === 0\"\r\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\r\n >\r\n <span class=\"ff-btn-label\"\r\n >Eliminar ({{ docsEliminables.length }})</span\r\n >\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Fila seleccionar todo / total archivos -->\r\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\r\n <div class=\"ff-select-row__left\">\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"allSelected\"\r\n (onChange)=\"toggleSelectAll()\"\r\n >\r\n </p-checkbox>\r\n <span\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n class=\"ff-select-row__label\"\r\n >Seleccionar todo</span\r\n >\r\n </div>\r\n <span class=\"ff-select-row__count\"\r\n >{{ totalRecords || items.length }}\r\n {{\r\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <!-- Contenido scrollable -->\r\n <div class=\"ff-file-list-wrapper\">\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"ff-loading\">\r\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\r\n </div>\r\n\r\n <!-- Lista de archivos -->\r\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\r\n <div\r\n class=\"ff-file-item\"\r\n *ngFor=\"let item of items\"\r\n (click)=\"openVisorDoc(item)\"\r\n >\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"item.delete\"\r\n (onChange)=\"onClickedCheckDelete($event, item)\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n </p-checkbox>\r\n\r\n <div class=\"ff-file-item__preview\">\r\n <i\r\n *ngIf=\"!canPreview(item.label, item.Path)\"\r\n class=\"pi ff-file-item__frame ff-file-item__icon\"\r\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\r\n ></i>\r\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\r\n <embed\r\n *ngIf=\"carpeta.TipoArchivo == '2'\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n />\r\n <img\r\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\r\n class=\"ff-file-item__frame\"\r\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\r\n />\r\n <iframe\r\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n frameborder=\"0\"\r\n ></iframe>\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"ff-file-item__info\">\r\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\r\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\r\n >Fecha Subida:\r\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <span\r\n class=\"ff-file-item__date\"\r\n *ngIf=\"item.FechaSubida && isMobile\"\r\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <i\r\n class=\"pi pi-external-link ff-file-item__open\"\r\n (click)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n aria-label=\"Abrir en nueva ventana\"\r\n (keydown.enter)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n ></i>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Sin resultados -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\r\n Sin documentos cargados\r\n </div>\r\n </div>\r\n\r\n <!-- Footer fijo: paginaci\u00F3n compacta -->\r\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\r\n <div class=\"ff-pagination\">\r\n <p-select\r\n [options]=\"pageSizeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(ngModel)]=\"pageSize\"\r\n (ngModelChange)=\"onPageSizeChange()\"\r\n >\r\n </p-select>\r\n <p-paginator\r\n [first]=\"first\"\r\n [rows]=\"pageSize\"\r\n [totalRecords]=\"totalRecords\"\r\n (onPageChange)=\"onPageChange($event)\"\r\n [showCurrentPageReport]=\"true\"\r\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\r\n [showPageLinks]=\"false\"\r\n [showFirstLastIcon]=\"false\"\r\n >\r\n </p-paginator>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i6.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "component", type: UploadDialogComponent, selector: "lib-upload-dialog", inputs: ["selectedDocument", "allowedExtensions"], outputs: ["onUploaded", "loadFile"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "pipe", type: FlexibleDatePipe, name: "flexibleDate" }, { kind: "ngmodule", type: DialogModule }] });
549
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: FolderFilesComponent, isStandalone: true, selector: "lib-folder-files", inputs: { carpeta: "carpeta", isMobile: "isMobile", idKatios: "idKatios", server: "server", subestado: "subestado", requestData: "requestData", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes" }, outputs: { onFileChange: "onFileChange", onCargarArchivo: "onCargarArchivo", onEliminarMasivo: "onEliminarMasivo", onBack: "onBack", viewDocument: "viewDocument" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "ngmodule", type: PaginatorModule }, { kind: "component", type: i6.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "component", type: UploadDialogComponent, selector: "lib-upload-dialog", inputs: ["selectedDocument", "allowedExtensions"], outputs: ["onUploaded", "loadFile"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i7.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "pipe", type: FlexibleDatePipe, name: "flexibleDate" }, { kind: "ngmodule", type: DialogModule }] });
461
550
  }
462
551
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: FolderFilesComponent, decorators: [{
463
552
  type: Component,
@@ -475,7 +564,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
475
564
  SelectModule,
476
565
  FlexibleDatePipe,
477
566
  DialogModule,
478
- ], standalone: true, template: "<div class=\"ff-layout\">\r\n <!-- Header fijo -->\r\n <div class=\"ff-header\">\r\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-arrow-left\"\r\n label=\"Volver\"\r\n (click)=\"goBack()\"\r\n ></button>\r\n </div>\r\n\r\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\r\n <div class=\"ff-toolbar\">\r\n <p-iconfield class=\"ff-toolbar__search\">\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n [placeholder]=\"\r\n 'Buscar en ' +\r\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\r\n \"\r\n [(ngModel)]=\"searchQuery\"\r\n (input)=\"onSearchInput()\"\r\n class=\"w-full\"\r\n />\r\n </p-iconfield>\r\n\r\n <div class=\"ff-toolbar__actions\">\r\n <lib-upload-dialog\r\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\r\n [selectedDocument]=\"carpeta\"\r\n [allowedExtensions]=\"allowedUploadTypes\"\r\n (onUploaded)=\"fileChange($event)\"\r\n (loadFile)=\"cargarArchivo()\"\r\n >\r\n </lib-upload-dialog>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-trash\"\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n (click)=\"emitEliminarMasivo()\"\r\n [disabled]=\"docsEliminables.length === 0\"\r\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\r\n >\r\n <span class=\"ff-btn-label\"\r\n >Eliminar ({{ docsEliminables.length }})</span\r\n >\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Fila seleccionar todo / total archivos -->\r\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\r\n <div class=\"ff-select-row__left\">\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"allSelected\"\r\n (onChange)=\"toggleSelectAll()\"\r\n >\r\n </p-checkbox>\r\n <span\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n class=\"ff-select-row__label\"\r\n >Seleccionar todo</span\r\n >\r\n </div>\r\n <span class=\"ff-select-row__count\"\r\n >{{ totalRecords || items.length }}\r\n {{\r\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <!-- Contenido scrollable -->\r\n <div class=\"ff-file-list-wrapper\">\r\n <!-- Loading -->\r\n <div *ngIf=\"loading\" class=\"ff-loading\">\r\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\r\n </div>\r\n\r\n <!-- Lista de archivos -->\r\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\r\n <div\r\n class=\"ff-file-item\"\r\n *ngFor=\"let item of items\"\r\n (click)=\"openVisorDoc(item)\"\r\n >\r\n <p-checkbox\r\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\r\n [binary]=\"true\"\r\n [(ngModel)]=\"item.delete\"\r\n (onChange)=\"onClickedCheckDelete($event, item)\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n </p-checkbox>\r\n\r\n <div class=\"ff-file-item__preview\">\r\n <i\r\n *ngIf=\"!canPreview(item.label, item.Path)\"\r\n class=\"pi ff-file-item__frame ff-file-item__icon\"\r\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\r\n ></i>\r\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\r\n <embed\r\n *ngIf=\"carpeta.TipoArchivo == '2'\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n />\r\n <img\r\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\r\n class=\"ff-file-item__frame\"\r\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\r\n />\r\n <iframe\r\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\r\n class=\"ff-file-item__frame\"\r\n [src]=\"item.Path | safe\"\r\n frameborder=\"0\"\r\n ></iframe>\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"ff-file-item__info\">\r\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\r\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\r\n >Fecha Subida:\r\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <span\r\n class=\"ff-file-item__date\"\r\n *ngIf=\"item.FechaSubida && isMobile\"\r\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\r\n >\r\n <i\r\n class=\"pi pi-external-link ff-file-item__open\"\r\n (click)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n aria-label=\"Abrir en nueva ventana\"\r\n (keydown.enter)=\"\r\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\r\n \"\r\n ></i>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Sin resultados -->\r\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\r\n Sin documentos cargados\r\n </div>\r\n </div>\r\n\r\n <!-- Footer fijo: paginaci\u00F3n compacta -->\r\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\r\n <div class=\"ff-pagination\">\r\n <p-select\r\n [options]=\"pageSizeOptions\"\r\n optionLabel=\"label\"\r\n optionValue=\"value\"\r\n [(ngModel)]=\"pageSize\"\r\n (ngModelChange)=\"onPageSizeChange()\"\r\n >\r\n </p-select>\r\n <p-paginator\r\n [first]=\"first\"\r\n [rows]=\"pageSize\"\r\n [totalRecords]=\"totalRecords\"\r\n (onPageChange)=\"onPageChange($event)\"\r\n [showCurrentPageReport]=\"true\"\r\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\r\n [showPageLinks]=\"false\"\r\n [showFirstLastIcon]=\"false\"\r\n >\r\n </p-paginator>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"] }]
567
+ ], standalone: true, template: "<div class=\"ff-layout\">\n <!-- Header fijo -->\n <div class=\"ff-header\">\n <div class=\"ff-back-row\" *ngIf=\"!useBreadcrumb\">\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-arrow-left\"\n label=\"Volver\"\n (click)=\"goBack()\"\n ></button>\n </div>\n\n <!-- Toolbar: b\u00FAsqueda + botones de acci\u00F3n -->\n <div class=\"ff-toolbar\">\n <p-iconfield class=\"ff-toolbar__search\">\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n [placeholder]=\"\n 'Buscar en ' +\n carpeta.label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\n \"\n [(ngModel)]=\"searchQuery\"\n (input)=\"onSearchInput()\"\n class=\"w-full\"\n />\n </p-iconfield>\n\n <div class=\"ff-toolbar__actions\">\n <lib-upload-dialog\n *ngIf=\"carpeta?.reglas?.permisos?.cargarFront\"\n [selectedDocument]=\"carpeta\"\n [allowedExtensions]=\"allowedUploadTypes\"\n (onUploaded)=\"fileChange($event)\"\n (loadFile)=\"cargarArchivo()\"\n >\n </lib-upload-dialog>\n\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-trash\"\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n (click)=\"emitEliminarMasivo()\"\n [disabled]=\"docsEliminables.length === 0\"\n class=\"p-button-outlined p-button-danger p-button-sm ff-btn-delete\"\n >\n <span class=\"ff-btn-label\"\n >Eliminar ({{ docsEliminables.length }})</span\n >\n </button>\n </div>\n </div>\n\n <!-- Fila seleccionar todo / total archivos -->\n <div class=\"ff-select-row\" *ngIf=\"!loading && items.length > 0\">\n <div class=\"ff-select-row__left\">\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"allSelected\"\n (onChange)=\"toggleSelectAll()\"\n >\n </p-checkbox>\n <span\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n class=\"ff-select-row__label\"\n >Seleccionar todo</span\n >\n </div>\n <span class=\"ff-select-row__count\"\n >{{ totalRecords || items.length }}\n {{\n (totalRecords || items.length) === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n </div>\n </div>\n\n <!-- Contenido scrollable -->\n <div class=\"ff-file-list-wrapper\">\n <!-- Loading -->\n <div *ngIf=\"loading\" class=\"ff-loading\">\n <i class=\"pi pi-spin pi-spinner\" style=\"font-size: 2rem\"></i>\n </div>\n\n <!-- Lista de archivos -->\n <div class=\"ff-file-list\" *ngIf=\"!loading\">\n <div\n class=\"ff-file-item\"\n *ngFor=\"let item of items\"\n (click)=\"openVisorDoc(item)\"\n >\n <p-checkbox\n *ngIf=\"carpeta?.reglas?.permisos?.borrarFront\"\n [binary]=\"true\"\n [(ngModel)]=\"item.delete\"\n (onChange)=\"onClickedCheckDelete($event, item)\"\n (click)=\"$event.stopPropagation()\"\n >\n </p-checkbox>\n\n <div class=\"ff-file-item__preview\">\n <i\n *ngIf=\"!canPreview(item.label, item.Path)\"\n class=\"pi ff-file-item__frame ff-file-item__icon\"\n [ngClass]=\"previewFallbackIcon(item.label, item.Path)\"\n ></i>\n <ng-container *ngIf=\"canPreview(item.label, item.Path)\">\n <embed\n *ngIf=\"carpeta.TipoArchivo == '2'\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n />\n <img\n *ngIf=\"carpeta.TipoArchivo == '1' && isMobile\"\n class=\"ff-file-item__frame\"\n src=\"https://macuna.tecfinanzas.com/Imagenes/pdf_icon.png\"\n />\n <iframe\n *ngIf=\"carpeta.TipoArchivo == '1' && !isMobile\"\n class=\"ff-file-item__frame\"\n [src]=\"item.Path | safe\"\n frameborder=\"0\"\n ></iframe>\n </ng-container>\n </div>\n\n <div class=\"ff-file-item__info\">\n <span class=\"ff-file-item__name\">{{ item.label }}</span>\n <span class=\"ff-file-item__date\" *ngIf=\"item.FechaSubida && !isMobile\"\n >Fecha Subida:\n {{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <span\n class=\"ff-file-item__date\"\n *ngIf=\"item.FechaSubida && isMobile\"\n >{{ item.FechaSubida | flexibleDate: \"dd/MM/yyyy HH:mm\" }}</span\n >\n <i\n class=\"pi pi-external-link ff-file-item__open\"\n (click)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Abrir en nueva ventana\"\n (keydown.enter)=\"\n openCurrentInNewWindow(item.Path); $event.stopPropagation()\n \"\n ></i>\n </div>\n </div>\n </div>\n\n <!-- Sin resultados -->\n <div *ngIf=\"!loading && items.length === 0\" class=\"ff-empty\">\n Sin documentos cargados\n </div>\n </div>\n\n <!-- Footer fijo: paginaci\u00F3n compacta -->\n <div class=\"ff-footer\" *ngIf=\"usesApi && totalRecords > 0\">\n <div class=\"ff-pagination\">\n <p-select\n [options]=\"pageSizeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange()\"\n >\n </p-select>\n <p-paginator\n [first]=\"first\"\n [rows]=\"pageSize\"\n [totalRecords]=\"totalRecords\"\n (onPageChange)=\"onPageChange($event)\"\n [showCurrentPageReport]=\"true\"\n currentPageReportTemplate=\"{first} - {last} de {totalRecords}\"\n [showPageLinks]=\"false\"\n [showFirstLastIcon]=\"false\"\n >\n </p-paginator>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.ff-header{flex-shrink:0}.ff-back-row{display:flex;margin-block:15px}.ff-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:4px;padding:.5rem}.ff-toolbar__search{flex:1;min-width:0}:host ::ng-deep .ff-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.ff-toolbar__actions{display:flex;align-items:center;gap:6px;flex-shrink:0}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px;padding:.4rem .75rem}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .ff-btn-delete{white-space:nowrap;font-size:13px;padding:.4rem .75rem}.ff-select-row{display:flex;align-items:center;justify-content:space-between;padding:8px 4px;border-bottom:1px solid #e5e7eb;padding:.5rem}.ff-select-row__left{display:flex;align-items:center;gap:8px}.ff-select-row__label{font-size:13px;color:#374151}.ff-select-row__count{font-size:13px;color:#6b7280}.ff-file-list-wrapper{flex:1;min-height:0;overflow-y:auto}.ff-loading{text-align:center;padding:20px}.ff-file-list{display:flex;flex-direction:column}.ff-file-item{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.ff-file-item:hover{background-color:#f9fafb}.ff-file-item__preview{flex-shrink:0;width:85px;height:100px;overflow:hidden;display:flex;align-items:center;justify-content:center}.ff-file-item__frame{width:85px;height:100px;border:none;pointer-events:none;object-fit:cover}.ff-file-item__icon{display:flex;align-items:center;justify-content:center;font-size:40px;color:#6b7280;background-color:#f3f4f6;border-radius:4px}.ff-file-item__icon.pi-file-excel{color:#1d6f42;background-color:#f0faf5}.ff-file-item__icon.pi-file-pdf{color:#b91c1c;background-color:#fef2f2}.ff-file-item__icon.pi-file-word{color:#1d4ed8;background-color:#eff6ff}.ff-file-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px;text-align:right}.ff-file-item__name{font-size:13px;font-weight:500;color:#111827;min-width:0;word-break:break-word}.ff-file-item__date{font-size:12px;color:#9ca3af;overflow:hidden}.ff-file-item__open{font-size:18px;color:#3b82f6;flex-shrink:0;padding:4px;border-radius:4px;transition:color .15s ease,background-color .15s ease;cursor:pointer;align-self:flex-end}.ff-file-item__open:hover{color:#2563eb;background-color:#eff6ff}.ff-empty{text-align:center;padding:20px;color:#999}.ff-footer{flex-shrink:0;border-top:1px solid #e5e7eb}.ff-pagination{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px;font-size:13px}:host ::ng-deep .ff-pagination .p-select{width:auto;min-width:90px}:host ::ng-deep .ff-pagination .p-select .p-select-label{font-size:12px;padding:4px 8px}:host ::ng-deep .ff-pagination .p-paginator{padding:0;background:transparent;border:none;gap:0}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-current{font-size:12px;color:#6b7280;padding:0 6px;min-width:auto;height:auto}:host ::ng-deep .ff-pagination .p-paginator .p-paginator-prev,:host ::ng-deep .ff-pagination .p-paginator .p-paginator-next{min-width:28px;height:28px;font-size:12px}@media only screen and (max-width: 656px){.ff-toolbar{gap:6px}.ff-btn-label{display:none}:host ::ng-deep .ff-toolbar__actions lib-upload-dialog .p-button .p-button-label{display:none}:host ::ng-deep .ff-toolbar__actions .p-button{padding:.5rem}.ff-file-item__preview,.ff-file-item__frame{width:65px;height:80px}.ff-file-item__icon{font-size:28px}.ff-file-item__name{font-size:12px}.ff-file-item__date{font-size:11px}}\n"] }]
479
568
  }], ctorParameters: () => [], propDecorators: { carpeta: [{
480
569
  type: Input
481
570
  }], isMobile: [{
@@ -506,6 +595,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
506
595
  type: Output
507
596
  }] } });
508
597
 
598
+ /**
599
+ * Traduce el error de una llamada del puerto a un texto para el usuario, en español y de usted.
600
+ *
601
+ * Nunca devuelve el mensaje del backend, `err.message`, JSON ni texto en inglés: el texto sale
602
+ * siempre de este archivo, según el código de error. El detalle técnico va a `console.error`
603
+ * con el prefijo `[sf-documents]` para soporte.
604
+ *
605
+ * Formas de error que llegan hoy:
606
+ * - DocumentService directo (documents-manager-ui): `err.error` es su `ApiResponse`,
607
+ * `{ success, statusCode, message, errors: ['CODIGO'] }`.
608
+ * - Vía TFAServices (TFB): la fachada lanza `new Exception(response.Content)` y responde
609
+ * `{ success: false, message: 'Error: {json de DocumentService}' }`. Se desenvuelve ese JSON.
610
+ */
611
+ const GENERIC_ERROR_MESSAGE = 'Ocurrió un error inesperado. Intente de nuevo.';
612
+ const NETWORK_ERROR_MESSAGE = 'No hay conexión con el servidor. Revise su conexión e intente de nuevo.';
613
+ /**
614
+ * Códigos de `errors[0]` que devuelve DocumentService (`ExceptionHandlerMiddleware` y
615
+ * `Core/Exceptions`) → texto para el usuario. Un código que no esté aquí usa el genérico.
616
+ */
617
+ const ERROR_CODE_MESSAGES = {
618
+ DOCUMENT_PART_MISSING: 'Falta un documento requerido en el gestor para esta solicitud. Revise las carpetas e intente de nuevo.',
619
+ DOCUMENT_TOO_LARGE: 'El documento supera el tamaño máximo permitido. Contacte a soporte.',
620
+ DOCUMENT_GENERATION_ERROR: 'Una parte del documento no se pudo producir. Intente de nuevo; si persiste, contacte a soporte.',
621
+ DOCUMENT_CONFIGURATION_ERROR: 'El documento no está configurado correctamente. Contacte a soporte.',
622
+ RESOURCE_NOT_FOUND: 'No se encontró la información solicitada. Recargue la pantalla e intente de nuevo.',
623
+ VALIDATION_ERROR: 'Revise los datos ingresados e intente de nuevo.',
624
+ INVALID_ARGUMENT: 'Revise los datos ingresados e intente de nuevo.',
625
+ BATCH_TOO_LARGE: 'Los archivos superan el tamaño máximo permitido por envío. Suba menos archivos a la vez.',
626
+ REQUEST_TIMEOUT: 'El servidor tardó demasiado en responder. Intente de nuevo.',
627
+ };
628
+ /** Prefijo con el que TFAServices envuelve el cuerpo de DocumentService (`$"Error: {ex.Message}"`). */
629
+ const TFA_WRAPPER_PREFIX = 'Error: ';
630
+ function tryParseObject(text) {
631
+ if (typeof text !== 'string')
632
+ return null;
633
+ const trimmed = text.trim();
634
+ if (!trimmed.startsWith('{'))
635
+ return null;
636
+ try {
637
+ const parsed = JSON.parse(trimmed);
638
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
639
+ ? parsed
640
+ : null;
641
+ }
642
+ catch {
643
+ return null;
644
+ }
645
+ }
646
+ /** Cuerpo de la respuesta de error, ya desenvuelto si viene de TFAServices. */
647
+ function extractBody(err) {
648
+ let body = null;
649
+ const raw = err?.error;
650
+ if (raw && typeof raw === 'object') {
651
+ body = raw;
652
+ }
653
+ else if (typeof raw === 'string') {
654
+ body = tryParseObject(raw);
655
+ }
656
+ else if (err && typeof err === 'object' && Array.isArray(err.errors)) {
657
+ // El host ya entregó el cuerpo (p. ej. un catchError que hace throwError(() => e.error)).
658
+ body = err;
659
+ }
660
+ const message = body?.['message'];
661
+ if (typeof message === 'string' && message.startsWith(TFA_WRAPPER_PREFIX + '{')) {
662
+ const inner = tryParseObject(message.slice(TFA_WRAPPER_PREFIX.length));
663
+ if (inner)
664
+ body = inner;
665
+ }
666
+ return body;
667
+ }
668
+ function extractCode(body) {
669
+ const first = Array.isArray(body?.['errors']) ? body['errors'][0] : null;
670
+ return typeof first === 'string' && first.trim() ? first.trim() : null;
671
+ }
672
+ /**
673
+ * Texto para el usuario a partir de un error del puerto.
674
+ * @param context Qué se estaba haciendo, solo para el log de soporte (p. ej. 'generateDocument').
675
+ */
676
+ function getUserErrorMessage(err, context = '') {
677
+ const e = err;
678
+ const body = extractBody(e);
679
+ const code = extractCode(body);
680
+ const status = typeof e?.status === 'number' ? e.status : null;
681
+ console.error(`[sf-documents]${context ? ' ' + context : ''}`, {
682
+ status,
683
+ statusCode: body?.['statusCode'] ?? null,
684
+ code,
685
+ detail: body?.['message'] ?? e?.message ?? e,
686
+ });
687
+ if (status === 0)
688
+ return NETWORK_ERROR_MESSAGE;
689
+ if (code && ERROR_CODE_MESSAGES[code])
690
+ return ERROR_CODE_MESSAGES[code];
691
+ return GENERIC_ERROR_MESSAGE;
692
+ }
693
+
509
694
  class SfDocumentsComponent {
510
695
  sanitizer;
511
696
  snackBar;
@@ -557,6 +742,9 @@ class SfDocumentsComponent {
557
742
  UsuarioTdoc;
558
743
  idKatios;
559
744
  displayGenerate = false;
745
+ /** Error de la última generación; se muestra dentro del diálogo hasta reintentar o cambiar el tipo. */
746
+ generateError = null;
747
+ toastKey = SF_DOCUMENTS_TOAST_KEY;
560
748
  canGenerate = true;
561
749
  documentTypes = [];
562
750
  documentsToGenerate = [];
@@ -597,6 +785,7 @@ class SfDocumentsComponent {
597
785
  this.scanFileList = new Array();
598
786
  this.displayPDF = false;
599
787
  this.displayGenerate = false;
788
+ this.generateError = null;
600
789
  this.canGenerate = true;
601
790
  this.documentTypes = [];
602
791
  this.documentsToGenerate = [];
@@ -701,7 +890,7 @@ class SfDocumentsComponent {
701
890
  this.documentService.loadingData = false;
702
891
  };
703
892
  errorCargarArbol = (iError) => {
704
- this.message('error', 'Error al traer la información', iError.message);
893
+ this.message('error', 'Error al traer la información', getUserErrorMessage(iError, 'getFolders'));
705
894
  this.documentService.loadingData = false;
706
895
  };
707
896
  // onClickedCheckDelete($event: any, document: any) {
@@ -862,7 +1051,7 @@ class SfDocumentsComponent {
862
1051
  var sIdKatios = this.idKatios;
863
1052
  dataDocs = { data: data };
864
1053
  formData.append('data', JSON.stringify(dataDocs));
865
- formData.append('merge', 'true');
1054
+ formData.append('merge', 'false');
866
1055
  for (let _i = 0; _i < fileList.length; _i++) {
867
1056
  formData.append('files', fileList[_i], fileList[_i].name);
868
1057
  }
@@ -876,8 +1065,7 @@ class SfDocumentsComponent {
876
1065
  },
877
1066
  error: (err) => {
878
1067
  this.documentService.loading = false;
879
- this.message('error', 'Se presentaron inconvenientes almacenando el documento', err.message);
880
- console.error('Error : ' + err);
1068
+ this.message('error', 'Se presentaron inconvenientes almacenando el documento', getUserErrorMessage(err, 'uploadFiles'));
881
1069
  },
882
1070
  });
883
1071
  }
@@ -941,6 +1129,7 @@ class SfDocumentsComponent {
941
1129
  }
942
1130
  message(severity, summary, message) {
943
1131
  this.snackBar.add({
1132
+ key: SF_DOCUMENTS_TOAST_KEY,
944
1133
  severity: severity,
945
1134
  summary: summary,
946
1135
  detail: message,
@@ -1022,11 +1211,14 @@ class SfDocumentsComponent {
1022
1211
  openGenerateDialog() {
1023
1212
  this.selectedDocType = null;
1024
1213
  this.selectedRange = null;
1214
+ this.generateError = null;
1025
1215
  this.displayGenerate = true;
1026
1216
  }
1027
1217
  generateDocument() {
1028
1218
  if (!this.selectedDocType)
1029
1219
  return;
1220
+ // Un error anterior no debe quedar junto al aviso de un parámetro faltante.
1221
+ this.generateError = null;
1030
1222
  // Validación mínima: si hay params, exigir que no estén vacíos
1031
1223
  for (const p of this.dynamicParams || []) {
1032
1224
  const key = p.name;
@@ -1058,7 +1250,13 @@ class SfDocumentsComponent {
1058
1250
  this.enProceso = false;
1059
1251
  },
1060
1252
  error: (err) => {
1061
- this.message('error', 'No se pudo generar el documento', err?.message || err);
1253
+ // El diálogo queda abierto con el error visible (p-message, role="alert") para
1254
+ // corregir o reintentar. El toast solo si el usuario ya lo cerró: así un lector de
1255
+ // pantalla no anuncia el mismo error dos veces.
1256
+ this.generateError = getUserErrorMessage(err, 'generateDocument');
1257
+ if (!this.displayGenerate) {
1258
+ this.message('error', 'No se pudo generar el documento', this.generateError);
1259
+ }
1062
1260
  this.enProceso = false;
1063
1261
  },
1064
1262
  });
@@ -1076,6 +1274,7 @@ class SfDocumentsComponent {
1076
1274
  const doc = this.selectedDocType
1077
1275
  ? this.documentsToGenerateMap[this.selectedDocType]
1078
1276
  : null;
1277
+ this.generateError = null;
1079
1278
  this.dynamicParams = doc?.params ?? [];
1080
1279
  this.dynamicValues = {}; // reset valores
1081
1280
  // valores default opcionales
@@ -1105,8 +1304,8 @@ class SfDocumentsComponent {
1105
1304
  previewFallbackIcon(label, path) {
1106
1305
  return getFileTypeIcon(label || this.current_label || path || this.current_path);
1107
1306
  }
1108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, deps: [{ token: i1.DomSanitizer }, { token: i2$1.MessageService }, { token: i0.ApplicationRef }, { token: i2$1.ConfirmationService }, { token: SfDocumentsService }], target: i0.ɵɵFactoryTarget.Component });
1109
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SfDocumentsComponent, isStandalone: true, selector: "app-sf-documents", inputs: { accion: "accion", entidad: "entidad", ndoc: "ndoc", tdoc: "tdoc", tipo: "tipo", Kasociada: "Kasociada", Producto: "Producto", Solicitud: "Solicitud", oSession: "oSession", perfilDocumentos: "perfilDocumentos", subestado: "subestado", isMobile: "isMobile", bAtras: "bAtras", bFinal: "bFinal", botones: "botones", aplFiltro: "aplFiltro", nmco: "nmco", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes", server: "server", idKatios: "idKatios" }, outputs: { nextTabPapa: "nextTabPapa", onNavigationChange: "onNavigationChange" }, providers: [ConfirmationService], viewQueries: [{ propertyName: "panel", first: true, predicate: ["pdf"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"sf-doc-layout\">\r\n <div class=\"sf-doc-fixed\">\r\n <div class=\"buttons\" *ngIf=\"botones\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n <!-- Toolbar superior (solo tab 1) -->\r\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\r\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\r\n <p-iconfield>\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n placeholder=\"Buscar carpeta...\"\r\n [(ngModel)]=\"valorFiltro\"\r\n (keyup)=\"filtrarDocumentos()\"\r\n class=\"w-full\"\r\n [disabled]=\"documentService.loadingData\"\r\n />\r\n </p-iconfield>\r\n </div>\r\n\r\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar documento\"\r\n icon=\"pi pi-plus\"\r\n class=\"p-button-sm\"\r\n (click)=\"openGenerateDialog()\"\r\n [disabled]=\"enProceso || !canGenerate\"\r\n ></button>\r\n </div>\r\n </div>\r\n </div>\r\n <p-confirmDialog\r\n header=\"Atencion\"\r\n icon=\"pi pi-exclamation-triangle\"\r\n ></p-confirmDialog>\r\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\r\n <div class=\"folder-list\">\r\n @if (!documentService.loadingData) {\r\n <ng-container *ngFor=\"let carpeta of filesFilter\">\r\n <div class=\"folder-list\">\r\n <div\r\n class=\"folder-item\"\r\n *ngFor=\"let item of carpeta.children\"\r\n (click)=\"VerDetalleTab(item)\"\r\n >\r\n <i\r\n class=\"pi pi-folder folder-item__icon\"\r\n [ngStyle]=\"{\r\n color:\r\n item.children?.length > 0 || item.fileCount > 0\r\n ? 'green'\r\n : 'red',\r\n }\"\r\n ></i>\r\n <div class=\"folder-item__info\">\r\n <span class=\"folder-item__name\">{{ item.label }}</span>\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"item.children?.length > 0\"\r\n >{{ item.children.length }}\r\n {{\r\n item.children.length === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n item.fileCount\r\n \"\r\n >{{ item.fileCount }}\r\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n !item.fileCount\r\n \"\r\n >0 archivos</span\r\n >\r\n </div>\r\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\r\n </div>\r\n </div>\r\n </ng-container>\r\n } @else {\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <ng-container *ngIf=\"botones\">\r\n <div class=\"buttons\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\r\n <lib-folder-files\r\n [carpeta]=\"carpetaSeleccionada\"\r\n [isMobile]=\"isMobile\"\r\n [idKatios]=\"idKatios\"\r\n [server]=\"server\"\r\n [subestado]=\"subestado\"\r\n [requestData]=\"requestData\"\r\n [useBreadcrumb]=\"useBreadcrumb\"\r\n [usesApi]=\"usesApi\"\r\n [allowedUploadTypes]=\"allowedUploadTypes\"\r\n (onFileChange)=\"fileChange($event)\"\r\n (onCargarArchivo)=\"cargarArchivo($event)\"\r\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\r\n (onBack)=\"goToTab('1')\"\r\n (viewDocument)=\"openVisorDoc($event)\"\r\n >\r\n </lib-folder-files>\r\n </div>\r\n</div>\r\n\r\n<!-- <ng-template #scanContent>\r\n <div class=\"div-table\">\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <h4>Escanear documentos</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <label (click)=\"takePhotoClick()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\r\n </label>\r\n\r\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template> -->\r\n\r\n<p-dialog\r\n [(visible)]=\"displayView\"\r\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\r\n [modal]=\"true\"\r\n [style]=\"{ width: '70vw' }\"\r\n appendTo=\"body\"\r\n>\r\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\r\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\r\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Abrir en una nueva ventana\"\r\n icon=\"pi pi-external-link\"\r\n (click)=\"openCurrentInNewWindow()\"\r\n ></button>\r\n </div>\r\n <ng-container *ngIf=\"canPreview()\">\r\n <embed\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\r\n [src]=\"current_path | safe\"\r\n style=\"width: 100%; min-height: 600px\"\r\n />\r\n <iframe\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\r\n style=\"width: 100%; min-height: 600px\"\r\n [src]=\"current_path | safe\"\r\n ></iframe>\r\n </ng-container>\r\n</p-dialog>\r\n\r\n<p-dialog\r\n header=\"Generar documento\"\r\n [(visible)]=\"displayGenerate\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\r\n>\r\n <div class=\"gen-form\">\r\n <!-- Tipo de documento -->\r\n <div class=\"gen-field\">\r\n <label class=\"gen-label\">Tipo de documento</label>\r\n <p-dropdown\r\n class=\"gen-control\"\r\n [options]=\"documentTypes\"\r\n optionLabel=\"label\"\r\n optionValue=\"code\"\r\n [(ngModel)]=\"selectedDocType\"\r\n placeholder=\"Seleccione un tipo\"\r\n appendTo=\"body\"\r\n (onChange)=\"onDocTypeChange()\"\r\n >\r\n </p-dropdown>\r\n </div>\r\n\r\n <!-- Par\u00E1metros din\u00E1micos -->\r\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\r\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\r\n <label class=\"gen-label\">\r\n {{ p.description }}\r\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\r\n </label>\r\n\r\n <!-- Date -->\r\n <p-datepicker\r\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n [showIcon]=\"true\"\r\n appendTo=\"body\"\r\n dateFormat=\"yy-mm-dd\"\r\n >\r\n </p-datepicker>\r\n\r\n <!-- String -->\r\n <input\r\n *ngIf=\"\r\n (p.type || '').toLowerCase() === 'nvarchar' ||\r\n (p.type || '').toLowerCase() === 'string'\r\n \"\r\n pInputText\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n placeholder=\"Ingrese un valor\"\r\n />\r\n\r\n <!-- Number -->\r\n <p-inputNumber\r\n *ngIf=\"\r\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\r\n \"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n >\r\n </p-inputNumber>\r\n\r\n <!-- Boolean -->\r\n <div\r\n class=\"gen-control gen-checkbox\"\r\n *ngIf=\"\r\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\r\n \"\r\n >\r\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\r\n </p-checkbox>\r\n <span class=\"gen-checkbox-label\">S\u00ED</span>\r\n </div>\r\n\r\n <!-- helper opcional -->\r\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <ng-template pTemplate=\"footer\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Cancelar\"\r\n class=\"p-button-text\"\r\n (click)=\"displayGenerate = false\"\r\n ></button>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar\"\r\n icon=\"pi pi-cog\"\r\n (click)=\"generateDocument()\"\r\n [disabled]=\"!selectedDocType || enProceso\"\r\n ></button>\r\n </ng-template>\r\n</p-dialog>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"], dependencies: [{ kind: "ngmodule", type: ToastModule }, { kind: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i5$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i7$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i8.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "component", type: FolderFilesComponent, selector: "lib-folder-files", inputs: ["carpeta", "isMobile", "idKatios", "server", "subestado", "requestData", "useBreadcrumb", "usesApi", "allowedUploadTypes"], outputs: ["onFileChange", "onCargarArchivo", "onEliminarMasivo", "onBack", "viewDocument"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i11.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i12.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i13.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
1307
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, deps: [{ token: i1.DomSanitizer }, { token: i2.MessageService }, { token: i0.ApplicationRef }, { token: i2.ConfirmationService }, { token: SfDocumentsService }], target: i0.ɵɵFactoryTarget.Component });
1308
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SfDocumentsComponent, isStandalone: true, selector: "app-sf-documents", inputs: { accion: "accion", entidad: "entidad", ndoc: "ndoc", tdoc: "tdoc", tipo: "tipo", Kasociada: "Kasociada", Producto: "Producto", Solicitud: "Solicitud", oSession: "oSession", perfilDocumentos: "perfilDocumentos", subestado: "subestado", isMobile: "isMobile", bAtras: "bAtras", bFinal: "bFinal", botones: "botones", aplFiltro: "aplFiltro", nmco: "nmco", useBreadcrumb: "useBreadcrumb", usesApi: "usesApi", allowedUploadTypes: "allowedUploadTypes", server: "server", idKatios: "idKatios" }, outputs: { nextTabPapa: "nextTabPapa", onNavigationChange: "onNavigationChange" }, providers: [ConfirmationService, MessageService], viewQueries: [{ propertyName: "panel", first: true, predicate: ["pdf"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atencion\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <label class=\"gen-label\">Tipo de documento</label>\n <p-dropdown\n class=\"gen-control\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-dropdown>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\n <label class=\"gen-label\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\n \"\n >\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\n </p-checkbox>\n <span class=\"gen-checkbox-label\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"], dependencies: [{ kind: "ngmodule", type: ToastModule }, { kind: "component", type: i4$2.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i6$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$1.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SafePipe, name: "safe" }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["styleClass"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["iconPosition", "styleClass"] }, { kind: "component", type: FolderFilesComponent, selector: "lib-folder-files", inputs: ["carpeta", "isMobile", "idKatios", "server", "subestado", "requestData", "useBreadcrumb", "usesApi", "allowedUploadTypes"], outputs: ["onFileChange", "onCargarArchivo", "onEliminarMasivo", "onBack", "viewDocument"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i12.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i13.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i14.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "style", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i15.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
1110
1309
  }
1111
1310
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SfDocumentsComponent, decorators: [{
1112
1311
  type: Component,
@@ -1127,8 +1326,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1127
1326
  DropdownModule,
1128
1327
  DatePickerModule,
1129
1328
  SkeletonModule,
1130
- ], providers: [ConfirmationService], standalone: true, template: "<div class=\"sf-doc-layout\">\r\n <div class=\"sf-doc-fixed\">\r\n <div class=\"buttons\" *ngIf=\"botones\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n <!-- Toolbar superior (solo tab 1) -->\r\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\r\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\r\n <p-iconfield>\r\n <p-inputicon class=\"pi pi-search\" />\r\n <input\r\n type=\"text\"\r\n pInputText\r\n placeholder=\"Buscar carpeta...\"\r\n [(ngModel)]=\"valorFiltro\"\r\n (keyup)=\"filtrarDocumentos()\"\r\n class=\"w-full\"\r\n [disabled]=\"documentService.loadingData\"\r\n />\r\n </p-iconfield>\r\n </div>\r\n\r\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar documento\"\r\n icon=\"pi pi-plus\"\r\n class=\"p-button-sm\"\r\n (click)=\"openGenerateDialog()\"\r\n [disabled]=\"enProceso || !canGenerate\"\r\n ></button>\r\n </div>\r\n </div>\r\n </div>\r\n <p-confirmDialog\r\n header=\"Atencion\"\r\n icon=\"pi pi-exclamation-triangle\"\r\n ></p-confirmDialog>\r\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\r\n <div class=\"folder-list\">\r\n @if (!documentService.loadingData) {\r\n <ng-container *ngFor=\"let carpeta of filesFilter\">\r\n <div class=\"folder-list\">\r\n <div\r\n class=\"folder-item\"\r\n *ngFor=\"let item of carpeta.children\"\r\n (click)=\"VerDetalleTab(item)\"\r\n >\r\n <i\r\n class=\"pi pi-folder folder-item__icon\"\r\n [ngStyle]=\"{\r\n color:\r\n item.children?.length > 0 || item.fileCount > 0\r\n ? 'green'\r\n : 'red',\r\n }\"\r\n ></i>\r\n <div class=\"folder-item__info\">\r\n <span class=\"folder-item__name\">{{ item.label }}</span>\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"item.children?.length > 0\"\r\n >{{ item.children.length }}\r\n {{\r\n item.children.length === 1 ? \"archivo\" : \"archivos\"\r\n }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n item.fileCount\r\n \"\r\n >{{ item.fileCount }}\r\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\r\n >\r\n <span\r\n class=\"folder-item__count\"\r\n *ngIf=\"\r\n (!item.children || item.children.length === 0) &&\r\n !item.fileCount\r\n \"\r\n >0 archivos</span\r\n >\r\n </div>\r\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\r\n </div>\r\n </div>\r\n </ng-container>\r\n } @else {\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n <div class=\"folder-item\">\r\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\r\n <div class=\"self-center\" style=\"flex: 1\">\r\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\r\n <p-skeleton width=\"75%\" />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <ng-container *ngIf=\"botones\">\r\n <div class=\"buttons\">\r\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Atras\"\r\n icon=\"pi pi-arrow-left\"\r\n (click)=\"next(-1)\"\r\n ></button>\r\n </div>\r\n <div\r\n class=\"div-table-col50\"\r\n style=\"text-align: center\"\r\n *ngIf=\"!bFinal && botones\"\r\n >\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Siguiente\"\r\n icon=\"pi pi-arrow-right\"\r\n (click)=\"next(1)\"\r\n ></button>\r\n </div>\r\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Finalizar\"\r\n icon=\"pi pi-home\"\r\n (click)=\"next(0)\"\r\n ></button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\r\n <lib-folder-files\r\n [carpeta]=\"carpetaSeleccionada\"\r\n [isMobile]=\"isMobile\"\r\n [idKatios]=\"idKatios\"\r\n [server]=\"server\"\r\n [subestado]=\"subestado\"\r\n [requestData]=\"requestData\"\r\n [useBreadcrumb]=\"useBreadcrumb\"\r\n [usesApi]=\"usesApi\"\r\n [allowedUploadTypes]=\"allowedUploadTypes\"\r\n (onFileChange)=\"fileChange($event)\"\r\n (onCargarArchivo)=\"cargarArchivo($event)\"\r\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\r\n (onBack)=\"goToTab('1')\"\r\n (viewDocument)=\"openVisorDoc($event)\"\r\n >\r\n </lib-folder-files>\r\n </div>\r\n</div>\r\n\r\n<!-- <ng-template #scanContent>\r\n <div class=\"div-table\">\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <h4>Escanear documentos</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\r\n </div>\r\n <div class=\"div-table-row\" style=\"text-align: center\">\r\n <label (click)=\"takePhotoClick()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\r\n </label>\r\n\r\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\r\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\r\n </label>\r\n </div>\r\n </div>\r\n</ng-template> -->\r\n\r\n<p-dialog\r\n [(visible)]=\"displayView\"\r\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\r\n [modal]=\"true\"\r\n [style]=\"{ width: '70vw' }\"\r\n appendTo=\"body\"\r\n>\r\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\r\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\r\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Abrir en una nueva ventana\"\r\n icon=\"pi pi-external-link\"\r\n (click)=\"openCurrentInNewWindow()\"\r\n ></button>\r\n </div>\r\n <ng-container *ngIf=\"canPreview()\">\r\n <embed\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\r\n [src]=\"current_path | safe\"\r\n style=\"width: 100%; min-height: 600px\"\r\n />\r\n <iframe\r\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\r\n style=\"width: 100%; min-height: 600px\"\r\n [src]=\"current_path | safe\"\r\n ></iframe>\r\n </ng-container>\r\n</p-dialog>\r\n\r\n<p-dialog\r\n header=\"Generar documento\"\r\n [(visible)]=\"displayGenerate\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\r\n>\r\n <div class=\"gen-form\">\r\n <!-- Tipo de documento -->\r\n <div class=\"gen-field\">\r\n <label class=\"gen-label\">Tipo de documento</label>\r\n <p-dropdown\r\n class=\"gen-control\"\r\n [options]=\"documentTypes\"\r\n optionLabel=\"label\"\r\n optionValue=\"code\"\r\n [(ngModel)]=\"selectedDocType\"\r\n placeholder=\"Seleccione un tipo\"\r\n appendTo=\"body\"\r\n (onChange)=\"onDocTypeChange()\"\r\n >\r\n </p-dropdown>\r\n </div>\r\n\r\n <!-- Par\u00E1metros din\u00E1micos -->\r\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\r\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\r\n <label class=\"gen-label\">\r\n {{ p.description }}\r\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\r\n </label>\r\n\r\n <!-- Date -->\r\n <p-datepicker\r\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n [showIcon]=\"true\"\r\n appendTo=\"body\"\r\n dateFormat=\"yy-mm-dd\"\r\n >\r\n </p-datepicker>\r\n\r\n <!-- String -->\r\n <input\r\n *ngIf=\"\r\n (p.type || '').toLowerCase() === 'nvarchar' ||\r\n (p.type || '').toLowerCase() === 'string'\r\n \"\r\n pInputText\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n placeholder=\"Ingrese un valor\"\r\n />\r\n\r\n <!-- Number -->\r\n <p-inputNumber\r\n *ngIf=\"\r\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\r\n \"\r\n class=\"gen-control\"\r\n [(ngModel)]=\"dynamicValues[p.name]\"\r\n >\r\n </p-inputNumber>\r\n\r\n <!-- Boolean -->\r\n <div\r\n class=\"gen-control gen-checkbox\"\r\n *ngIf=\"\r\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\r\n \"\r\n >\r\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\r\n </p-checkbox>\r\n <span class=\"gen-checkbox-label\">S\u00ED</span>\r\n </div>\r\n\r\n <!-- helper opcional -->\r\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <ng-template pTemplate=\"footer\">\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Cancelar\"\r\n class=\"p-button-text\"\r\n (click)=\"displayGenerate = false\"\r\n ></button>\r\n\r\n <button\r\n pButton\r\n type=\"button\"\r\n label=\"Generar\"\r\n icon=\"pi pi-cog\"\r\n (click)=\"generateDocument()\"\r\n [disabled]=\"!selectedDocType || enProceso\"\r\n ></button>\r\n </ng-template>\r\n</p-dialog>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"] }]
1131
- }], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2$1.MessageService }, { type: i0.ApplicationRef }, { type: i2$1.ConfirmationService }, { type: SfDocumentsService }], propDecorators: { accion: [{
1329
+ MessageModule,
1330
+ ], providers: [ConfirmationService, MessageService], standalone: true, template: "<div class=\"sf-doc-layout\">\n <div class=\"sf-doc-fixed\">\n <div class=\"buttons\" *ngIf=\"botones\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n <!-- Toolbar superior (solo tab 1) -->\n <div *ngIf=\"tab == 1\" class=\"doc-toolbar\">\n <div class=\"doc-toolbar-left\" *ngIf=\"aplFiltro\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n placeholder=\"Buscar carpeta...\"\n [(ngModel)]=\"valorFiltro\"\n (keyup)=\"filtrarDocumentos()\"\n class=\"w-full\"\n [disabled]=\"documentService.loadingData\"\n />\n </p-iconfield>\n </div>\n\n <div class=\"doc-toolbar-right\" *ngIf=\"documentTypes.length > 0\">\n <button\n pButton\n type=\"button\"\n label=\"Generar documento\"\n icon=\"pi pi-plus\"\n class=\"p-button-sm\"\n (click)=\"openGenerateDialog()\"\n [disabled]=\"enProceso || !canGenerate\"\n ></button>\n </div>\n </div>\n </div>\n <p-confirmDialog\n header=\"Atencion\"\n icon=\"pi pi-exclamation-triangle\"\n ></p-confirmDialog>\n <!-- Avisos de la librer\u00EDa: solo los de su key, as\u00ED el toast del host no los duplica. -->\n <p-toast\n [key]=\"toastKey\"\n [breakpoints]=\"{ '576px': { width: 'calc(100vw - 40px)' } }\"\n ></p-toast>\n <div class=\"sf-doc-scrollable\" *ngIf=\"tab == 1\">\n <div class=\"folder-list\">\n @if (!documentService.loadingData) {\n <ng-container *ngFor=\"let carpeta of filesFilter\">\n <div class=\"folder-list\">\n <div\n class=\"folder-item\"\n *ngFor=\"let item of carpeta.children\"\n (click)=\"VerDetalleTab(item)\"\n >\n <i\n class=\"pi pi-folder folder-item__icon\"\n [ngStyle]=\"{\n color:\n item.children?.length > 0 || item.fileCount > 0\n ? 'green'\n : 'red',\n }\"\n ></i>\n <div class=\"folder-item__info\">\n <span class=\"folder-item__name\">{{ item.label }}</span>\n <span\n class=\"folder-item__count\"\n *ngIf=\"item.children?.length > 0\"\n >{{ item.children.length }}\n {{\n item.children.length === 1 ? \"archivo\" : \"archivos\"\n }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n item.fileCount\n \"\n >{{ item.fileCount }}\n {{ item.fileCount === 1 ? \"archivo\" : \"archivos\" }}</span\n >\n <span\n class=\"folder-item__count\"\n *ngIf=\"\n (!item.children || item.children.length === 0) &&\n !item.fileCount\n \"\n >0 archivos</span\n >\n </div>\n <i class=\"pi pi-chevron-right folder-item__arrow\"></i>\n </div>\n </div>\n </ng-container>\n } @else {\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n <div class=\"folder-item\">\n <p-skeleton shape=\"circle\" size=\"2rem\" styleClass=\"mr-2\" />\n <div class=\"self-center\" style=\"flex: 1\">\n <p-skeleton width=\"100%\" styleClass=\"mb-2\" />\n <p-skeleton width=\"75%\" />\n </div>\n </div>\n }\n </div>\n <ng-container *ngIf=\"botones\">\n <div class=\"buttons\">\n <div class=\"div-table-col50\" style=\"text-align: center\" *ngIf=\"bAtras\">\n <button\n pButton\n type=\"button\"\n label=\"Atras\"\n icon=\"pi pi-arrow-left\"\n (click)=\"next(-1)\"\n ></button>\n </div>\n <div\n class=\"div-table-col50\"\n style=\"text-align: center\"\n *ngIf=\"!bFinal && botones\"\n >\n <button\n pButton\n type=\"button\"\n label=\"Siguiente\"\n icon=\"pi pi-arrow-right\"\n (click)=\"next(1)\"\n ></button>\n </div>\n <div class=\"div-table-col50\" *ngIf=\"bFinal\">\n <button\n pButton\n type=\"button\"\n label=\"Finalizar\"\n icon=\"pi pi-home\"\n (click)=\"next(0)\"\n ></button>\n </div>\n </div>\n </ng-container>\n </div>\n <div class=\"sf-doc-scrollable sf-doc-scrollable--files\" *ngIf=\"tab == 2\">\n <lib-folder-files\n [carpeta]=\"carpetaSeleccionada\"\n [isMobile]=\"isMobile\"\n [idKatios]=\"idKatios\"\n [server]=\"server\"\n [subestado]=\"subestado\"\n [requestData]=\"requestData\"\n [useBreadcrumb]=\"useBreadcrumb\"\n [usesApi]=\"usesApi\"\n [allowedUploadTypes]=\"allowedUploadTypes\"\n (onFileChange)=\"fileChange($event)\"\n (onCargarArchivo)=\"cargarArchivo($event)\"\n (onEliminarMasivo)=\"eliminarMasivo($event)\"\n (onBack)=\"goToTab('1')\"\n (viewDocument)=\"openVisorDoc($event)\"\n >\n </lib-folder-files>\n </div>\n</div>\n\n<!-- <ng-template #scanContent>\n <div class=\"div-table\">\n <div class=\"div-table-row\" style=\"text-align: center\">\n <h4>Escanear documentos</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n Archivos cargados: <h4>{{scanFileList.length}}</h4>\n </div>\n <div class=\"div-table-row\" style=\"text-align: center\">\n <label (click)=\"takePhotoClick()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">add_to_photos</mat-icon>\n </label>\n\n <label *ngIf=\"scanFileList.length != 0\" (click)=\"subirFotosScan()\" class=\"btn\">\n <mat-icon style=\"font-size: 2.5em; color:#0056b2\">share</mat-icon>\n </label>\n </div>\n </div>\n</ng-template> -->\n\n<p-dialog\n [(visible)]=\"displayView\"\n [header]=\"current_label.replace('#toolbar=0&navpanes=0&statusbar=0', '')\"\n [modal]=\"true\"\n [style]=\"{ width: '70vw' }\"\n appendTo=\"body\"\n>\n <div *ngIf=\"!canPreview()\" class=\"sf-doc-preview-fallback\">\n <i class=\"pi\" [ngClass]=\"previewFallbackIcon()\"></i>\n <p>La vista previa no est\u00E1 disponible para este tipo de archivo.</p>\n <button\n pButton\n type=\"button\"\n label=\"Abrir en una nueva ventana\"\n icon=\"pi pi-external-link\"\n (click)=\"openCurrentInNewWindow()\"\n ></button>\n </div>\n <ng-container *ngIf=\"canPreview()\">\n <embed\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '2'\"\n [src]=\"current_path | safe\"\n style=\"width: 100%; min-height: 600px\"\n />\n <iframe\n *ngIf=\"carpetaSeleccionada.TipoArchivo == '1'\"\n style=\"width: 100%; min-height: 600px\"\n [src]=\"current_path | safe\"\n ></iframe>\n </ng-container>\n</p-dialog>\n\n<p-dialog\n header=\"Generar documento\"\n [(visible)]=\"displayGenerate\"\n [modal]=\"true\"\n [closable]=\"true\"\n [style]=\"{ width: isMobile ? '95vw' : '520px' }\"\n>\n <div class=\"gen-form\">\n <!-- Error de la \u00FAltima generaci\u00F3n: el di\u00E1logo queda abierto para corregir o reintentar -->\n <p-message\n *ngIf=\"generateError\"\n severity=\"error\"\n icon=\"pi pi-times-circle\"\n styleClass=\"w-full\"\n >\n No se pudo generar el documento. {{ generateError }}\n </p-message>\n\n <!-- Tipo de documento -->\n <div class=\"gen-field\">\n <label class=\"gen-label\">Tipo de documento</label>\n <p-dropdown\n class=\"gen-control\"\n [options]=\"documentTypes\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [(ngModel)]=\"selectedDocType\"\n placeholder=\"Seleccione un tipo\"\n appendTo=\"body\"\n (onChange)=\"onDocTypeChange()\"\n >\n </p-dropdown>\n </div>\n\n <!-- Par\u00E1metros din\u00E1micos -->\n <div class=\"gen-section\" *ngIf=\"dynamicParams.length\">\n <div class=\"gen-field\" *ngFor=\"let p of dynamicParams\">\n <label class=\"gen-label\">\n {{ p.description }}\n <span class=\"gen-required\" *ngIf=\"p.required\">*</span>\n </label>\n\n <!-- Date -->\n <p-datepicker\n *ngIf=\"(p.type || '').toLowerCase() === 'date'\"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n [showIcon]=\"true\"\n appendTo=\"body\"\n dateFormat=\"yy-mm-dd\"\n >\n </p-datepicker>\n\n <!-- String -->\n <input\n *ngIf=\"\n (p.type || '').toLowerCase() === 'nvarchar' ||\n (p.type || '').toLowerCase() === 'string'\n \"\n pInputText\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n placeholder=\"Ingrese un valor\"\n />\n\n <!-- Number -->\n <p-inputNumber\n *ngIf=\"\n ['int', 'decimal', 'number'].includes((p.type || '').toLowerCase())\n \"\n class=\"gen-control\"\n [(ngModel)]=\"dynamicValues[p.name]\"\n >\n </p-inputNumber>\n\n <!-- Boolean -->\n <div\n class=\"gen-control gen-checkbox\"\n *ngIf=\"\n ['boolean', 'bit', 'bool'].includes((p.type || '').toLowerCase())\n \"\n >\n <p-checkbox [binary]=\"true\" [(ngModel)]=\"dynamicValues[p.name]\">\n </p-checkbox>\n <span class=\"gen-checkbox-label\">S\u00ED</span>\n </div>\n\n <!-- helper opcional -->\n <small class=\"gen-help\" *ngIf=\"p.help\">{{ p.help }}</small>\n </div>\n </div>\n </div>\n\n <ng-template pTemplate=\"footer\">\n <button\n pButton\n type=\"button\"\n label=\"Cancelar\"\n class=\"p-button-text\"\n (click)=\"displayGenerate = false\"\n ></button>\n\n <button\n pButton\n type=\"button\"\n [label]=\"generateError ? 'Reintentar' : 'Generar'\"\n [icon]=\"generateError ? 'pi pi-refresh' : 'pi pi-cog'\"\n (click)=\"generateDocument()\"\n [loading]=\"enProceso\"\n [disabled]=\"!selectedDocType || enProceso\"\n ></button>\n </ng-template>\n</p-dialog>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-layout{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.sf-doc-fixed{flex-shrink:0}.sf-doc-scrollable{flex:1;min-height:0;overflow-y:auto}.sf-doc-scrollable--files{overflow:hidden;display:flex;flex-direction:column}:host ::ng-deep .sf-doc-scrollable--files>lib-folder-files{flex:1;min-height:0}.iconWhatsApp{font-size:40px;color:#6495ed}.doc-toolbar{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:.5rem}:host ::ng-deep .doc-toolbar .p-inputtext{padding:.45rem .65rem .45rem 2.5rem;font-size:13px}.doc-toolbar-left{flex:1;min-width:180px}.doc-toolbar-right{display:flex;justify-content:flex-end}:host ::ng-deep .doc-toolbar-right .p-button-outlined{background:transparent;border:1px solid #d1d5db;color:#374151;font-weight:500;font-size:13px}:host ::ng-deep .doc-toolbar-right .p-button-outlined:hover{background:#f9fafb;border-color:#9ca3af}:host ::ng-deep .doc-toolbar-right .p-button-outlined:disabled{opacity:.5}@media only screen and (max-width: 656px),(max-device-width: 656px){.doc-toolbar{flex-direction:column;align-items:stretch}.doc-toolbar-right{justify-content:stretch}.doc-toolbar-right button{width:100%}}.folder-list{display:flex;flex-direction:column}.folder-item{display:flex;align-items:center;padding:12px 8px;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:background-color .15s ease}.folder-item:hover{background-color:#f9fafb}.folder-item:last-child{border-bottom:1px solid #e5e7eb}.folder-item__icon{font-size:18px;color:#6b7280;margin-right:12px;flex-shrink:0}.folder-item__info{display:flex;flex-direction:column;flex:1;min-width:0}.folder-item__name{font-size:13.5px;font-weight:500;color:#111827;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.folder-item__count{font-size:12px;color:#9ca3af;margin-top:1px}.folder-item__arrow{font-size:13px;color:#9ca3af;margin-left:12px;flex-shrink:0}.buttons{display:flex;justify-content:space-around;margin-block:15px}.buttonResponsive,buttonResponsiveBotonFinal{display:inline-block;border-radius:4px;background-color:#00f;border:none;color:#fff;text-align:center;font-size:12px;padding:10px;width:200px;transition:all .5s;cursor:pointer;margin:20px 5px 5px}.gen-form{display:flex;flex-direction:column;gap:14px}.gen-section{display:flex;flex-direction:column;gap:12px}.gen-field{display:flex;flex-direction:column;gap:6px}.gen-label{font-size:13px;font-weight:600;color:#111827}.gen-required{color:#ef4444;margin-left:4px}.gen-control{width:100%}:host ::ng-deep .gen-control .p-dropdown,:host ::ng-deep .gen-control .p-inputtext,:host ::ng-deep .gen-control .p-inputnumber,:host ::ng-deep .gen-control .p-datepicker{width:100%}:host ::ng-deep .gen-control .p-inputnumber-input{width:100%}.gen-checkbox{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid #e5e7eb;border-radius:8px}.gen-checkbox-label{font-size:14px;color:#374151}.gen-help{color:#6b7280}.sf-doc-preview-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:300px;text-align:center;color:#374151}.sf-doc-preview-fallback i{font-size:48px;color:#6b7280}.sf-doc-preview-fallback i.pi-file-excel{color:#1d6f42}.sf-doc-preview-fallback i.pi-file-pdf{color:#b91c1c}.sf-doc-preview-fallback i.pi-file-word{color:#1d4ed8}.frameDoc{overflow:hidden;border:none}\n"] }]
1331
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i2.MessageService }, { type: i0.ApplicationRef }, { type: i2.ConfirmationService }, { type: SfDocumentsService }], propDecorators: { accion: [{
1132
1332
  type: Input
1133
1333
  }], entidad: [{
1134
1334
  type: Input