ngx-dsxlibrary 2.21.74 → 2.21.76

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.
@@ -5,7 +5,7 @@ import { FormsModule, NG_VALUE_ACCESSOR, AbstractControl, FormControl, NG_VALIDA
5
5
  import * as i2 from 'primeng/togglebutton';
6
6
  import { ToggleButtonModule } from 'primeng/togglebutton';
7
7
  import * as i1$1 from '@angular/common';
8
- import { CommonModule, AsyncPipe, JsonPipe, DecimalPipe, DatePipe, Location } from '@angular/common';
8
+ import { CommonModule, AsyncPipe, JsonPipe, DecimalPipe, Location } from '@angular/common';
9
9
  import * as i2$1 from 'primeng/tree';
10
10
  import { TreeModule } from 'primeng/tree';
11
11
  import * as i3 from 'primeng/api';
@@ -18,6 +18,8 @@ import * as i2$3 from 'primeng/avatar';
18
18
  import { AvatarModule, Avatar } from 'primeng/avatar';
19
19
  import * as i2$2 from 'primeng/dialog';
20
20
  import { DialogModule } from 'primeng/dialog';
21
+ import * as i4 from 'primeng/button';
22
+ import { ButtonModule, Button } from 'primeng/button';
21
23
  import * as i1$4 from '@angular/platform-browser';
22
24
  import { DomSanitizer } from '@angular/platform-browser';
23
25
  import * as i1$5 from 'primeng/tabs';
@@ -27,8 +29,6 @@ import * as i1$6 from '@angular/common/http';
27
29
  import { HttpClient, HttpHeaders, HttpParams, HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
28
30
  import { debounceTime, distinctUntilChanged, switchMap, shareReplay as shareReplay$1, map as map$1, take as take$1 } from 'rxjs/operators';
29
31
  import { Router, RouterLink } from '@angular/router';
30
- import * as i1$7 from 'primeng/button';
31
- import { Button, ButtonModule } from 'primeng/button';
32
32
  import moment from 'moment-timezone';
33
33
  import { ToastrService } from 'ngx-toastr';
34
34
  import Swal from 'sweetalert2';
@@ -37,7 +37,7 @@ import { LottieComponent } from 'ngx-lottie';
37
37
  import { createTimeline } from 'animejs';
38
38
  import * as i3$1 from 'primeng/image';
39
39
  import { ImageModule } from 'primeng/image';
40
- import * as i4 from 'primeng/menubar';
40
+ import * as i4$1 from 'primeng/menubar';
41
41
  import { MenubarModule } from 'primeng/menubar';
42
42
  import { JwtHelperService } from '@auth0/angular-jwt';
43
43
  import { CookieService } from 'ngx-cookie-service';
@@ -52,6 +52,7 @@ import { AvatarGroupModule } from 'primeng/avatargroup';
52
52
  import { BadgeModule } from 'primeng/badge';
53
53
  import { CardModule } from 'primeng/card';
54
54
  import { CheckboxModule } from 'primeng/checkbox';
55
+ import { ChipModule } from 'primeng/chip';
55
56
  import { ContextMenuModule } from 'primeng/contextmenu';
56
57
  import { DataViewModule } from 'primeng/dataview';
57
58
  import { DatePickerModule, DatePicker } from 'primeng/datepicker';
@@ -60,7 +61,7 @@ import { DrawerModule } from 'primeng/drawer';
60
61
  import { FieldsetModule } from 'primeng/fieldset';
61
62
  import { IconFieldModule } from 'primeng/iconfield';
62
63
  import { InputIconModule } from 'primeng/inputicon';
63
- import * as i1$8 from 'primeng/inputmask';
64
+ import * as i1$7 from 'primeng/inputmask';
64
65
  import { InputMaskModule } from 'primeng/inputmask';
65
66
  import { InputNumberModule, InputNumber } from 'primeng/inputnumber';
66
67
  import { InputTextModule } from 'primeng/inputtext';
@@ -833,7 +834,33 @@ class PdfPreviewComponent {
833
834
  visible = model(false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
834
835
  blob = input(null, ...(ngDevMode ? [{ debugName: "blob" }] : /* istanbul ignore next */ []));
835
836
  objectUrl = null;
836
- pdfUrl = null;
837
+ fileUrl = null;
838
+ fileType = null;
839
+ fileName = '';
840
+ fileSize = '';
841
+ rawBlob = null;
842
+ mimeTypeMap = {
843
+ 'application/pdf': 'PDF',
844
+ 'image/jpeg': 'JPEG',
845
+ 'image/png': 'PNG',
846
+ 'image/gif': 'GIF',
847
+ 'image/webp': 'WebP',
848
+ };
849
+ supportedTypes = [
850
+ 'application/pdf',
851
+ 'image/jpeg',
852
+ 'image/png',
853
+ 'image/gif',
854
+ 'image/webp',
855
+ ];
856
+ // Mapeo de iconos por tipo
857
+ iconMap = {
858
+ 'application/pdf': 'pi pi-file-pdf',
859
+ 'image/jpeg': 'pi pi-image',
860
+ 'image/png': 'pi pi-image',
861
+ 'image/gif': 'pi pi-image',
862
+ 'image/webp': 'pi pi-image',
863
+ };
837
864
  constructor(sanitizer) {
838
865
  this.sanitizer = sanitizer;
839
866
  effect((onCleanup) => {
@@ -841,43 +868,112 @@ class PdfPreviewComponent {
841
868
  const isVisible = this.visible();
842
869
  if (!isVisible || file === null) {
843
870
  this.limpiarUrlAnterior();
871
+ this.fileName = '';
872
+ this.fileSize = '';
873
+ this.fileType = null;
874
+ this.rawBlob = null;
844
875
  return;
845
876
  }
846
- if (file.type !== 'application/pdf') {
877
+ if (!this.isFileSupported(file)) {
847
878
  this.limpiarUrlAnterior();
848
- console.warn('El archivo recibido no es un PDF válido');
879
+ console.warn('Tipo de archivo no soportado:', file.type);
880
+ this.fileType = null;
881
+ this.rawBlob = null;
849
882
  return;
850
883
  }
884
+ this.rawBlob = file;
885
+ this.fileType = file.type;
886
+ this.fileName = this.getFileNameFromBlob(file);
887
+ this.fileSize = this.formatFileSize(file.size);
851
888
  this.limpiarUrlAnterior();
852
889
  const currentObjectUrl = URL.createObjectURL(file);
853
890
  this.objectUrl = currentObjectUrl;
854
- this.pdfUrl =
891
+ this.fileUrl =
855
892
  this.sanitizer.bypassSecurityTrustResourceUrl(currentObjectUrl);
856
893
  onCleanup(() => {
857
894
  URL.revokeObjectURL(currentObjectUrl);
858
895
  if (this.objectUrl === currentObjectUrl) {
859
896
  this.objectUrl = null;
860
- this.pdfUrl = null;
897
+ this.fileUrl = null;
861
898
  }
862
899
  });
863
900
  });
864
901
  }
902
+ isFileSupported(file) {
903
+ return this.supportedTypes.includes(file.type);
904
+ }
905
+ getFileNameFromBlob(blob) {
906
+ if (blob.name) {
907
+ return blob.name;
908
+ }
909
+ const extension = this.mimeTypeMap[blob.type] || 'archivo';
910
+ return `documento_soporte.${extension.toLowerCase()}`;
911
+ }
912
+ formatFileSize(bytes) {
913
+ if (bytes === 0)
914
+ return '0 Bytes';
915
+ const k = 1024;
916
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
917
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
918
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
919
+ }
865
920
  limpiarUrlAnterior() {
866
921
  if (this.objectUrl) {
867
922
  URL.revokeObjectURL(this.objectUrl);
868
923
  this.objectUrl = null;
869
924
  }
870
- this.pdfUrl = null;
925
+ this.fileUrl = null;
926
+ }
927
+ // Getters para el template
928
+ get isPdf() {
929
+ return this.fileType === 'application/pdf';
930
+ }
931
+ get isImage() {
932
+ return this.fileType?.startsWith('image/') || false;
933
+ }
934
+ get fileTypeLabel() {
935
+ return this.fileType
936
+ ? this.mimeTypeMap[this.fileType] || this.fileType
937
+ : '';
938
+ }
939
+ getFileIcon() {
940
+ if (!this.fileType)
941
+ return 'pi pi-file';
942
+ return this.iconMap[this.fileType] || 'pi pi-file';
943
+ }
944
+ // Descargar archivo
945
+ downloadFile() {
946
+ if (!this.rawBlob || !this.fileName) {
947
+ console.warn('No hay archivo para descargar');
948
+ return;
949
+ }
950
+ const link = document.createElement('a');
951
+ link.href = URL.createObjectURL(this.rawBlob);
952
+ link.download = this.fileName;
953
+ document.body.appendChild(link);
954
+ link.click();
955
+ document.body.removeChild(link);
956
+ // Limpiar URL creada para la descarga
957
+ setTimeout(() => {
958
+ URL.revokeObjectURL(link.href);
959
+ }, 100);
960
+ }
961
+ // Eventos de imagen
962
+ onImageLoad() {
963
+ console.log('Imagen cargada correctamente');
964
+ }
965
+ onImageError() {
966
+ console.warn('Error al cargar la imagen');
871
967
  }
872
968
  ngOnDestroy() {
873
969
  this.limpiarUrlAnterior();
874
970
  }
875
971
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PdfPreviewComponent, deps: [{ token: i1$4.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
876
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PdfPreviewComponent, isStandalone: true, selector: "app-pdf-preview", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, blob: { classPropertyName: "blob", publicName: "blob", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange" }, ngImport: i0, template: "<p-dialog\r\n header=\"Vista previa del documento de soporte\"\r\n [(visible)]=\"visible\"\r\n [style]=\"{ width: '80vw', height: '90vh' }\"\r\n [closable]=\"true\"\r\n [maximizable]=\"true\"\r\n>\r\n @if (pdfUrl) {\r\n <iframe\r\n [src]=\"pdfUrl\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n style=\"border: none\"\r\n ></iframe>\r\n }\r\n</p-dialog>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }] });
972
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PdfPreviewComponent, isStandalone: true, selector: "app-pdf-preview", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, blob: { classPropertyName: "blob", publicName: "blob", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange" }, ngImport: i0, template: "<p-dialog\r\n [(visible)]=\"visible\"\r\n [style]=\"{ width: '80vw', height: '90vh' }\"\r\n [closable]=\"true\"\r\n [maximizable]=\"true\"\r\n [modal]=\"true\"\r\n>\r\n <!-- Header personalizado -->\r\n <ng-template pTemplate=\"header\">\r\n <div class=\"dialog-header\">\r\n <div class=\"header-left\">\r\n <i [class]=\"getFileIcon()\" class=\"file-icon\"></i>\r\n <div class=\"header-info\">\r\n <span class=\"header-title\"\r\n >Vista previa del documento de soporte</span\r\n >\r\n @if (fileName) {\r\n <div class=\"header-details\">\r\n <span class=\"file-name\">{{ fileName }}</span>\r\n <span class=\"file-meta\">\r\n <span class=\"file-type\">{{ fileTypeLabel }}</span>\r\n <span class=\"file-size\">{{ fileSize }}</span>\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"header-actions\">\r\n @if (fileUrl) {\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-download\"\r\n class=\"p-button-rounded p-button-text p-button-sm\"\r\n (click)=\"downloadFile()\"\r\n pTooltip=\"Descargar archivo\"\r\n tooltipPosition=\"top\"\r\n ></button>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Contenido -->\r\n <div class=\"preview-wrapper\">\r\n <!-- Caso: Sin archivo -->\r\n @if (!fileUrl) {\r\n <div class=\"empty-state\">\r\n <i class=\"pi pi-file\"></i>\r\n <p>No hay archivo seleccionado</p>\r\n </div>\r\n }\r\n <!-- Caso: PDF -->\r\n @else if (isPdf) {\r\n <iframe\r\n [src]=\"fileUrl\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n style=\"border: none\"\r\n class=\"pdf-iframe\"\r\n ></iframe>\r\n }\r\n <!-- Caso: Imagen -->\r\n @else if (isImage) {\r\n <div class=\"image-container\">\r\n <img\r\n [src]=\"fileUrl\"\r\n [alt]=\"fileName || 'Vista previa de imagen'\"\r\n class=\"preview-image\"\r\n (load)=\"onImageLoad()\"\r\n (error)=\"onImageError()\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n</p-dialog>\r\n", styles: [".dialog-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.5rem 0;gap:1rem}.header-left{display:flex;align-items:center;gap:.75rem;min-width:0;flex:1}.file-icon{font-size:1.5rem;color:var(--primary-color, #3b82f6);flex-shrink:0}.header-info{display:flex;flex-direction:column;gap:.125rem;min-width:0}.header-title{font-size:1rem;font-weight:600;color:var(--text-color, #333);line-height:1.3}.header-details{display:flex;align-items:center;gap:.75rem;font-size:.8rem;color:var(--text-color-secondary, #666);flex-wrap:wrap}.file-name{font-weight:500;color:var(--text-color, #333);max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-meta{display:flex;align-items:center;gap:.5rem}.file-type{background:var(--surface-hover, #f0f0f0);padding:.0625rem .5rem;border-radius:12px;font-size:.7rem;font-weight:500;color:var(--text-color-secondary, #666)}.file-size{font-size:.75rem;color:var(--text-color-secondary, #666)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.header-actions ::ng-deep .p-button.p-button-text{color:var(--text-color-secondary, #666)}.header-actions ::ng-deep .p-button.p-button-text:hover{color:var(--primary-color, #3b82f6);background:var(--surface-hover, #f0f0f0)}.preview-wrapper{width:100%;height:calc(100% - 10px);min-height:400px;position:relative;background:var(--surface-ground, #f8f9fa);border-radius:4px;overflow:hidden}.pdf-iframe{width:100%;height:100%;border:none;background:#fff}.image-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--surface-ground, #f8f9fa)}.preview-image{max-width:100%;max-height:100%;object-fit:contain;border-radius:4px;box-shadow:0 2px 8px #0000001a;transition:transform .2s}.preview-image:hover{transform:scale(1.02)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;color:var(--text-color-secondary, #666);height:100%;min-height:400px}.empty-state i{font-size:4rem;opacity:.4;color:var(--text-color-secondary, #666)}.empty-state p{margin:0;font-size:1rem;font-weight:400}@media(max-width:768px){.dialog-header{flex-direction:column;align-items:stretch;gap:.5rem;padding:.25rem 0}.header-left{gap:.5rem}.file-icon{font-size:1.25rem}.header-title{font-size:.9rem}.header-details{font-size:.7rem;gap:.5rem}.file-name{max-width:150px}.header-actions{justify-content:flex-end;padding-top:.25rem;border-top:1px solid var(--surface-border, #e0e0e0)}.preview-wrapper{min-height:300px}.preview-image{max-height:70vh}}@media(max-width:480px){.file-name{max-width:100px}.header-details{flex-wrap:wrap}}\n"], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
877
973
  }
878
974
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PdfPreviewComponent, decorators: [{
879
975
  type: Component,
880
- args: [{ selector: 'app-pdf-preview', imports: [DialogModule], template: "<p-dialog\r\n header=\"Vista previa del documento de soporte\"\r\n [(visible)]=\"visible\"\r\n [style]=\"{ width: '80vw', height: '90vh' }\"\r\n [closable]=\"true\"\r\n [maximizable]=\"true\"\r\n>\r\n @if (pdfUrl) {\r\n <iframe\r\n [src]=\"pdfUrl\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n style=\"border: none\"\r\n ></iframe>\r\n }\r\n</p-dialog>\r\n" }]
976
+ args: [{ selector: 'app-pdf-preview', imports: [DialogModule, ButtonModule, TooltipModule], template: "<p-dialog\r\n [(visible)]=\"visible\"\r\n [style]=\"{ width: '80vw', height: '90vh' }\"\r\n [closable]=\"true\"\r\n [maximizable]=\"true\"\r\n [modal]=\"true\"\r\n>\r\n <!-- Header personalizado -->\r\n <ng-template pTemplate=\"header\">\r\n <div class=\"dialog-header\">\r\n <div class=\"header-left\">\r\n <i [class]=\"getFileIcon()\" class=\"file-icon\"></i>\r\n <div class=\"header-info\">\r\n <span class=\"header-title\"\r\n >Vista previa del documento de soporte</span\r\n >\r\n @if (fileName) {\r\n <div class=\"header-details\">\r\n <span class=\"file-name\">{{ fileName }}</span>\r\n <span class=\"file-meta\">\r\n <span class=\"file-type\">{{ fileTypeLabel }}</span>\r\n <span class=\"file-size\">{{ fileSize }}</span>\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"header-actions\">\r\n @if (fileUrl) {\r\n <button\r\n pButton\r\n type=\"button\"\r\n icon=\"pi pi-download\"\r\n class=\"p-button-rounded p-button-text p-button-sm\"\r\n (click)=\"downloadFile()\"\r\n pTooltip=\"Descargar archivo\"\r\n tooltipPosition=\"top\"\r\n ></button>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Contenido -->\r\n <div class=\"preview-wrapper\">\r\n <!-- Caso: Sin archivo -->\r\n @if (!fileUrl) {\r\n <div class=\"empty-state\">\r\n <i class=\"pi pi-file\"></i>\r\n <p>No hay archivo seleccionado</p>\r\n </div>\r\n }\r\n <!-- Caso: PDF -->\r\n @else if (isPdf) {\r\n <iframe\r\n [src]=\"fileUrl\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n style=\"border: none\"\r\n class=\"pdf-iframe\"\r\n ></iframe>\r\n }\r\n <!-- Caso: Imagen -->\r\n @else if (isImage) {\r\n <div class=\"image-container\">\r\n <img\r\n [src]=\"fileUrl\"\r\n [alt]=\"fileName || 'Vista previa de imagen'\"\r\n class=\"preview-image\"\r\n (load)=\"onImageLoad()\"\r\n (error)=\"onImageError()\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n</p-dialog>\r\n", styles: [".dialog-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.5rem 0;gap:1rem}.header-left{display:flex;align-items:center;gap:.75rem;min-width:0;flex:1}.file-icon{font-size:1.5rem;color:var(--primary-color, #3b82f6);flex-shrink:0}.header-info{display:flex;flex-direction:column;gap:.125rem;min-width:0}.header-title{font-size:1rem;font-weight:600;color:var(--text-color, #333);line-height:1.3}.header-details{display:flex;align-items:center;gap:.75rem;font-size:.8rem;color:var(--text-color-secondary, #666);flex-wrap:wrap}.file-name{font-weight:500;color:var(--text-color, #333);max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-meta{display:flex;align-items:center;gap:.5rem}.file-type{background:var(--surface-hover, #f0f0f0);padding:.0625rem .5rem;border-radius:12px;font-size:.7rem;font-weight:500;color:var(--text-color-secondary, #666)}.file-size{font-size:.75rem;color:var(--text-color-secondary, #666)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.header-actions ::ng-deep .p-button.p-button-text{color:var(--text-color-secondary, #666)}.header-actions ::ng-deep .p-button.p-button-text:hover{color:var(--primary-color, #3b82f6);background:var(--surface-hover, #f0f0f0)}.preview-wrapper{width:100%;height:calc(100% - 10px);min-height:400px;position:relative;background:var(--surface-ground, #f8f9fa);border-radius:4px;overflow:hidden}.pdf-iframe{width:100%;height:100%;border:none;background:#fff}.image-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--surface-ground, #f8f9fa)}.preview-image{max-width:100%;max-height:100%;object-fit:contain;border-radius:4px;box-shadow:0 2px 8px #0000001a;transition:transform .2s}.preview-image:hover{transform:scale(1.02)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;color:var(--text-color-secondary, #666);height:100%;min-height:400px}.empty-state i{font-size:4rem;opacity:.4;color:var(--text-color-secondary, #666)}.empty-state p{margin:0;font-size:1rem;font-weight:400}@media(max-width:768px){.dialog-header{flex-direction:column;align-items:stretch;gap:.5rem;padding:.25rem 0}.header-left{gap:.5rem}.file-icon{font-size:1.25rem}.header-title{font-size:.9rem}.header-details{font-size:.7rem;gap:.5rem}.file-name{max-width:150px}.header-actions{justify-content:flex-end;padding-top:.25rem;border-top:1px solid var(--surface-border, #e0e0e0)}.preview-wrapper{min-height:300px}.preview-image{max-height:70vh}}@media(max-width:480px){.file-name{max-width:100px}.header-details{flex-wrap:wrap}}\n"] }]
881
977
  }], ctorParameters: () => [{ type: i1$4.DomSanitizer }], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], blob: [{ type: i0.Input, args: [{ isSignal: true, alias: "blob", required: false }] }] } });
882
978
 
883
979
  class TemplateHighlight {
@@ -1792,11 +1888,11 @@ class AppMessageHelpComponent {
1792
1888
  return null;
1793
1889
  }
1794
1890
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageHelpComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1795
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageHelpComponent, isStandalone: true, selector: "dsx-message-help", inputs: { control: "control", currentIdControl: "currentIdControl", helperFunction: "helperFunction", dataSource: "dataSource", key: "key", umbral: "umbral", debugMode: "debugMode", idFieldName: "idFieldName", maxSugerencias: "maxSugerencias" }, ngImport: i0, template: "<div class=\"dsx-help-slot\" [class.is-visible]=\"isHelpVisible()\">\r\n @if (isHelpVisible()) {\r\n <div\r\n class=\"dsx-help-message\"\r\n [class.is-warning]=\"helperFunction === 'similarity'\"\r\n >\r\n @if (helperFunction === \"similarity\") {\r\n <icon-dsx name=\"emergency_home\"></icon-dsx>\r\n } @else {\r\n <icon-dsx name=\"chat_info\"></icon-dsx>\r\n }\r\n <span>{{ getHelpMessage() }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%}.dsx-help-slot{max-height:0;margin-top:0;overflow:hidden;opacity:0;transition:max-height .22s ease,margin-top .22s ease,opacity .18s ease}.dsx-help-slot.is-visible{max-height:4rem;margin-top:.3rem;opacity:1}.dsx-help-message{--dsx-help-color: #067647;--dsx-help-bg: #ecfdf3;color:var(--dsx-help-color);font-family:Roboto,Montserrat,sans-serif;font-size:clamp(.75rem,.72rem + .12vw,.8125rem);font-weight:400;line-height:1.35;letter-spacing:.01em;display:flex;align-items:center;gap:.35rem;position:relative;z-index:1;padding:.2rem .45rem;border-left:3px solid var(--dsx-help-color);border-radius:0 6px 6px 0;background:var(--dsx-help-bg);box-shadow:0 1px 2px #00000014;width:100%;max-width:100%;white-space:normal;word-break:break-word;transform:translateY(-2px);transition:transform .2s ease;box-sizing:border-box}.dsx-help-message.is-warning{--dsx-help-color: #b54708;--dsx-help-bg: #fffaeb}.dsx-help-slot.is-visible .dsx-help-message{transform:translateY(0)}.dsx-help-icon{flex-shrink:0;font-size:.78rem;line-height:1;color:var(--dsx-help-color)}.dsx-help-message svg{width:1rem;height:1rem;flex-shrink:0;display:inline-block;vertical-align:middle;transition:color .2s ease,fill .2s ease,stroke .2s ease}.dsx-help-message svg,.dsx-help-message svg path{fill:var(--dsx-help-color);stroke:var(--dsx-help-color)}.dsx-help-message span{flex:1;word-break:break-word}@media(max-width:640px){.dsx-help-slot.is-visible{max-height:5rem}.dsx-help-message{width:100%;max-width:100%}}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:3;pointer-events:none}:host-context(.p-floatlabel) .dsx-help-slot{max-height:none;margin-top:.25rem;overflow:visible;opacity:0;transform:translateY(-3px);transition:opacity .16s ease,transform .18s ease}:host-context(.p-floatlabel) .dsx-help-slot.is-visible{opacity:1;transform:translateY(0)}:host-context(.p-floatlabel) .dsx-help-message{width:100%;max-width:100%;box-sizing:border-box}\n"], dependencies: [{ kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }] });
1891
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageHelpComponent, isStandalone: true, selector: "dsx-message-help", inputs: { control: "control", currentIdControl: "currentIdControl", helperFunction: "helperFunction", dataSource: "dataSource", key: "key", umbral: "umbral", debugMode: "debugMode", idFieldName: "idFieldName", maxSugerencias: "maxSugerencias" }, ngImport: i0, template: "<div class=\"dsx-help-slot\" [class.is-visible]=\"isHelpVisible()\">\r\n @if (isHelpVisible()) {\r\n <div\r\n class=\"dsx-help-message\"\r\n [class.is-warning]=\"helperFunction === 'similarity'\"\r\n >\r\n <span>{{ getHelpMessage() }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%}.dsx-help-slot{max-height:0;margin-top:0;overflow:hidden;opacity:0;transition:max-height .22s ease,margin-top .22s ease,opacity .18s ease}.dsx-help-slot.is-visible{max-height:4rem;margin-top:.15rem;opacity:1}.dsx-help-message{--dsx-help-color: #059669;color:var(--dsx-help-color);font-family:Roboto,Montserrat,sans-serif;font-size:clamp(.7rem,.68rem + .08vw,.75rem);font-weight:400;line-height:1.4;letter-spacing:.01em;padding:.1rem 0;border:none;background:transparent;box-shadow:none;width:100%;max-width:100%;white-space:normal;word-break:break-word;box-sizing:border-box}.dsx-help-message.is-warning{--dsx-help-color: #d97706}.dsx-help-message span{display:block;word-break:break-word;color:var(--dsx-help-color)}.dsx-help-slot.is-visible .dsx-help-message{animation:fadeInHelp .2s ease}@keyframes fadeInHelp{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}@media(max-width:640px){.dsx-help-slot.is-visible{max-height:5rem}.dsx-help-message{font-size:clamp(.6rem,.55rem + .15vw,.65rem);padding:.05rem 0}}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:3;pointer-events:none}:host-context(.p-floatlabel) .dsx-help-slot{max-height:none;margin-top:.1rem;overflow:visible;opacity:0;transform:translateY(-2px);transition:opacity .16s ease,transform .18s ease}:host-context(.p-floatlabel) .dsx-help-slot.is-visible{opacity:1;transform:translateY(0)}:host-context(.p-floatlabel) .dsx-help-message{width:100%;max-width:100%;padding:.05rem 0;box-sizing:border-box}\n"] });
1796
1892
  }
1797
1893
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageHelpComponent, decorators: [{
1798
1894
  type: Component,
1799
- args: [{ selector: 'dsx-message-help', imports: [IconDsxComponent], template: "<div class=\"dsx-help-slot\" [class.is-visible]=\"isHelpVisible()\">\r\n @if (isHelpVisible()) {\r\n <div\r\n class=\"dsx-help-message\"\r\n [class.is-warning]=\"helperFunction === 'similarity'\"\r\n >\r\n @if (helperFunction === \"similarity\") {\r\n <icon-dsx name=\"emergency_home\"></icon-dsx>\r\n } @else {\r\n <icon-dsx name=\"chat_info\"></icon-dsx>\r\n }\r\n <span>{{ getHelpMessage() }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%}.dsx-help-slot{max-height:0;margin-top:0;overflow:hidden;opacity:0;transition:max-height .22s ease,margin-top .22s ease,opacity .18s ease}.dsx-help-slot.is-visible{max-height:4rem;margin-top:.3rem;opacity:1}.dsx-help-message{--dsx-help-color: #067647;--dsx-help-bg: #ecfdf3;color:var(--dsx-help-color);font-family:Roboto,Montserrat,sans-serif;font-size:clamp(.75rem,.72rem + .12vw,.8125rem);font-weight:400;line-height:1.35;letter-spacing:.01em;display:flex;align-items:center;gap:.35rem;position:relative;z-index:1;padding:.2rem .45rem;border-left:3px solid var(--dsx-help-color);border-radius:0 6px 6px 0;background:var(--dsx-help-bg);box-shadow:0 1px 2px #00000014;width:100%;max-width:100%;white-space:normal;word-break:break-word;transform:translateY(-2px);transition:transform .2s ease;box-sizing:border-box}.dsx-help-message.is-warning{--dsx-help-color: #b54708;--dsx-help-bg: #fffaeb}.dsx-help-slot.is-visible .dsx-help-message{transform:translateY(0)}.dsx-help-icon{flex-shrink:0;font-size:.78rem;line-height:1;color:var(--dsx-help-color)}.dsx-help-message svg{width:1rem;height:1rem;flex-shrink:0;display:inline-block;vertical-align:middle;transition:color .2s ease,fill .2s ease,stroke .2s ease}.dsx-help-message svg,.dsx-help-message svg path{fill:var(--dsx-help-color);stroke:var(--dsx-help-color)}.dsx-help-message span{flex:1;word-break:break-word}@media(max-width:640px){.dsx-help-slot.is-visible{max-height:5rem}.dsx-help-message{width:100%;max-width:100%}}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:3;pointer-events:none}:host-context(.p-floatlabel) .dsx-help-slot{max-height:none;margin-top:.25rem;overflow:visible;opacity:0;transform:translateY(-3px);transition:opacity .16s ease,transform .18s ease}:host-context(.p-floatlabel) .dsx-help-slot.is-visible{opacity:1;transform:translateY(0)}:host-context(.p-floatlabel) .dsx-help-message{width:100%;max-width:100%;box-sizing:border-box}\n"] }]
1895
+ args: [{ selector: 'dsx-message-help', imports: [IconDsxComponent], template: "<div class=\"dsx-help-slot\" [class.is-visible]=\"isHelpVisible()\">\r\n @if (isHelpVisible()) {\r\n <div\r\n class=\"dsx-help-message\"\r\n [class.is-warning]=\"helperFunction === 'similarity'\"\r\n >\r\n <span>{{ getHelpMessage() }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%}.dsx-help-slot{max-height:0;margin-top:0;overflow:hidden;opacity:0;transition:max-height .22s ease,margin-top .22s ease,opacity .18s ease}.dsx-help-slot.is-visible{max-height:4rem;margin-top:.15rem;opacity:1}.dsx-help-message{--dsx-help-color: #059669;color:var(--dsx-help-color);font-family:Roboto,Montserrat,sans-serif;font-size:clamp(.7rem,.68rem + .08vw,.75rem);font-weight:400;line-height:1.4;letter-spacing:.01em;padding:.1rem 0;border:none;background:transparent;box-shadow:none;width:100%;max-width:100%;white-space:normal;word-break:break-word;box-sizing:border-box}.dsx-help-message.is-warning{--dsx-help-color: #d97706}.dsx-help-message span{display:block;word-break:break-word;color:var(--dsx-help-color)}.dsx-help-slot.is-visible .dsx-help-message{animation:fadeInHelp .2s ease}@keyframes fadeInHelp{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}@media(max-width:640px){.dsx-help-slot.is-visible{max-height:5rem}.dsx-help-message{font-size:clamp(.6rem,.55rem + .15vw,.65rem);padding:.05rem 0}}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:3;pointer-events:none}:host-context(.p-floatlabel) .dsx-help-slot{max-height:none;margin-top:.1rem;overflow:visible;opacity:0;transform:translateY(-2px);transition:opacity .16s ease,transform .18s ease}:host-context(.p-floatlabel) .dsx-help-slot.is-visible{opacity:1;transform:translateY(0)}:host-context(.p-floatlabel) .dsx-help-message{width:100%;max-width:100%;padding:.05rem 0;box-sizing:border-box}\n"] }]
1800
1896
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { control: [{
1801
1897
  type: Input
1802
1898
  }], currentIdControl: [{
@@ -2235,22 +2331,23 @@ function provideEnvironment(environment) {
2235
2331
  * - `import` → Importar datos desde archivo (azul acero)
2236
2332
  */
2237
2333
  const ACTION_TYPES = {
2334
+ cancel: 'cancel',
2335
+ create: 'create',
2336
+ details: 'details',
2337
+ download: 'download',
2338
+ edit: 'edit',
2339
+ export: 'export',
2238
2340
  hardDelete: 'hardDelete',
2239
- softDelete: 'softDelete',
2240
- return: 'return',
2241
2341
  home: 'home',
2242
- validate: 'validate',
2342
+ import: 'import',
2343
+ refresh: 'refresh',
2243
2344
  restore: 'restore',
2244
- edit: 'edit',
2245
- create: 'create',
2345
+ return: 'return',
2246
2346
  save: 'save',
2347
+ softDelete: 'softDelete',
2247
2348
  update: 'update',
2248
- refresh: 'refresh',
2249
- details: 'details',
2349
+ validate: 'validate',
2250
2350
  view: 'view',
2251
- export: 'export',
2252
- download: 'download',
2253
- import: 'import',
2254
2351
  };
2255
2352
  function getActionMessageConfig(action, secondArg, thirdArg) {
2256
2353
  const isActive = action === 'softDelete' || action === 'hardDelete'
@@ -4913,14 +5010,14 @@ const ACTION_CONFIG = {
4913
5010
  icon: 'save',
4914
5011
  primeIcon: 'pi pi-save',
4915
5012
  colorToken: 'success',
4916
- tooltip: 'Guardar nuevo registro',
5013
+ tooltip: 'Guardar registro',
4917
5014
  },
4918
5015
  update: {
4919
5016
  label: 'Actualizar',
4920
5017
  icon: 'edit_note',
4921
5018
  primeIcon: 'pi pi-save',
4922
5019
  colorToken: 'primary',
4923
- tooltip: 'Actualizar registro existente',
5020
+ tooltip: 'Actualizar registro',
4924
5021
  },
4925
5022
  refresh: {
4926
5023
  label: 'Refrescar',
@@ -4972,8 +5069,444 @@ const ACTION_CONFIG = {
4972
5069
  colorToken: 'import',
4973
5070
  tooltip: 'Importar desde archivo',
4974
5071
  },
5072
+ cancel: {
5073
+ label: 'Cancelar',
5074
+ icon: 'cancel',
5075
+ primeIcon: 'pi pi-times',
5076
+ colorToken: 'danger',
5077
+ tooltip: 'Cancelar operación',
5078
+ },
4975
5079
  };
4976
5080
 
5081
+ // dsx-calendar-view.component.ts - VERSIÓN CON isDevMode()
5082
+ class DsxCalendarView {
5083
+ // ============================================
5084
+ // INPUTS
5085
+ // ============================================
5086
+ // Two-way binding
5087
+ startDate = model(null, ...(ngDevMode ? [{ debugName: "startDate" }] : /* istanbul ignore next */ []));
5088
+ endDate = model(null, ...(ngDevMode ? [{ debugName: "endDate" }] : /* istanbul ignore next */ []));
5089
+ excludeSundays = model(false, ...(ngDevMode ? [{ debugName: "excludeSundays" }] : /* istanbul ignore next */ []));
5090
+ // Configuración
5091
+ holidays = input([], ...(ngDevMode ? [{ debugName: "holidays" }] : /* istanbul ignore next */ []));
5092
+ compactMode = input(true, ...(ngDevMode ? [{ debugName: "compactMode" }] : /* istanbul ignore next */ []));
5093
+ showKPI = input(true, ...(ngDevMode ? [{ debugName: "showKPI" }] : /* istanbul ignore next */ []));
5094
+ debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
5095
+ isEdit = input(false, ...(ngDevMode ? [{ debugName: "isEdit" }] : /* istanbul ignore next */ []));
5096
+ showControls = input(true, ...(ngDevMode ? [{ debugName: "showControls" }] : /* istanbul ignore next */ []));
5097
+ // Output
5098
+ rangeChanged = output();
5099
+ // ============================================
5100
+ // STATE
5101
+ // ============================================
5102
+ startDateStr = signal('', ...(ngDevMode ? [{ debugName: "startDateStr" }] : /* istanbul ignore next */ []));
5103
+ endDateStr = signal('', ...(ngDevMode ? [{ debugName: "endDateStr" }] : /* istanbul ignore next */ []));
5104
+ // ✅ Exponer isDevMode como propiedad pública para el template si es necesario
5105
+ isDevMode = isDevMode();
5106
+ // ============================================
5107
+ // COMPUTED
5108
+ // ============================================
5109
+ shouldShowControls = computed(() => {
5110
+ return this.isEdit() || this.showControls();
5111
+ }, ...(ngDevMode ? [{ debugName: "shouldShowControls" }] : /* istanbul ignore next */ []));
5112
+ months = computed(() => {
5113
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5114
+ const start = this.startDateStr();
5115
+ const end = this.endDateStr();
5116
+ if (!start || !end) {
5117
+ this.logPerformance('months', perfStart);
5118
+ return [];
5119
+ }
5120
+ const zonaHoraria = 'America/Guatemala';
5121
+ const startDate = moment(start).tz(zonaHoraria).toDate();
5122
+ const endDate = moment(end).tz(zonaHoraria).toDate();
5123
+ if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
5124
+ this.logDebug('Fechas inválidas:', { start, end });
5125
+ this.logPerformance('months', perfStart);
5126
+ return [];
5127
+ }
5128
+ this.logDebug('fecha inicio: ', startDate);
5129
+ this.logDebug('fecha final: ', endDate);
5130
+ const startMonth = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
5131
+ const endMonth = new Date(endDate.getFullYear(), endDate.getMonth(), 1);
5132
+ const monthsToShow = [];
5133
+ monthsToShow.push(this.generateMonth(startMonth, startDate, endDate));
5134
+ if (startMonth.getTime() !== endMonth.getTime()) {
5135
+ monthsToShow.push(this.generateMonth(endMonth, startDate, endDate));
5136
+ }
5137
+ this.logPerformance('months', perfStart);
5138
+ return monthsToShow;
5139
+ }, ...(ngDevMode ? [{ debugName: "months" }] : /* istanbul ignore next */ []));
5140
+ formattedHolidays = computed(() => {
5141
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5142
+ const holidays = this.kpi()?.holidaysList || [];
5143
+ const result = holidays.map((h) => ({
5144
+ date: this.normalizeDateToString(h.dateHoliday),
5145
+ label: h.labelHoliday,
5146
+ }));
5147
+ this.logPerformance('formattedHolidays', perfStart);
5148
+ return result;
5149
+ }, ...(ngDevMode ? [{ debugName: "formattedHolidays" }] : /* istanbul ignore next */ []));
5150
+ // ============================================
5151
+ // KPI: Estadísticas del rango (CORREGIDO)
5152
+ // ============================================
5153
+ kpi = computed(() => {
5154
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5155
+ const start = this.startDateStr();
5156
+ const end = this.endDateStr();
5157
+ if (!start || !end) {
5158
+ this.logPerformance('kpi', perfStart);
5159
+ return null;
5160
+ }
5161
+ const startDate = new Date(start);
5162
+ const endDate = new Date(end);
5163
+ if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
5164
+ this.logPerformance('kpi', perfStart);
5165
+ return null;
5166
+ }
5167
+ const holidays = this.holidays();
5168
+ const excludeSun = this.excludeSundays();
5169
+ // 1. Calcular días totales
5170
+ const totalDays = this.getDaysBetween(startDate, endDate);
5171
+ // 2. Calcular domingos en el rango
5172
+ let sundays = 0;
5173
+ const current = new Date(startDate);
5174
+ while (current <= endDate) {
5175
+ if (current.getDay() === 0) {
5176
+ sundays++;
5177
+ }
5178
+ current.setDate(current.getDate() + 1);
5179
+ }
5180
+ // 3. 🔥 Calcular feriados en el rango
5181
+ const holidaysInRange = holidays.filter((h) => {
5182
+ const hStr = this.normalizeDateToString(h.dateHoliday);
5183
+ return hStr >= start && hStr <= end;
5184
+ });
5185
+ // 4. 🔥 Días hábiles = total - domingos - feriados
5186
+ let businessDays = totalDays;
5187
+ if (excludeSun) {
5188
+ businessDays = totalDays - sundays;
5189
+ }
5190
+ // 🔥 CORRECCIÓN: Restar feriados independientemente de excludeSun
5191
+ businessDays = businessDays - holidaysInRange.length;
5192
+ const kpiResult = {
5193
+ totalDays,
5194
+ businessDays,
5195
+ holidays: holidaysInRange.length,
5196
+ sundays: excludeSun ? sundays : 0,
5197
+ holidaysList: holidaysInRange,
5198
+ startDate: start,
5199
+ endDate: end,
5200
+ };
5201
+ this.logDebug('KPI calculado:', kpiResult);
5202
+ this.logPerformance('kpi', perfStart);
5203
+ return kpiResult;
5204
+ }, ...(ngDevMode ? [{ debugName: "kpi" }] : /* istanbul ignore next */ []));
5205
+ // ============================================
5206
+ // EFFECTS
5207
+ // ============================================
5208
+ constructor() {
5209
+ effect(() => {
5210
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5211
+ const value = this.startDate();
5212
+ const formatted = this.formatInputDate(value);
5213
+ this.startDateStr.set(formatted);
5214
+ this.logDebug('startDate actualizado:', { value, formatted });
5215
+ this.emitRangeChange();
5216
+ this.logPerformance('startDate effect', perfStart);
5217
+ });
5218
+ effect(() => {
5219
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5220
+ const value = this.endDate();
5221
+ const formatted = this.formatInputDate(value);
5222
+ this.endDateStr.set(formatted);
5223
+ this.logDebug('endDate actualizado:', { value, formatted });
5224
+ this.emitRangeChange();
5225
+ this.logPerformance('endDate effect', perfStart);
5226
+ });
5227
+ effect(() => {
5228
+ this.logDebug('excludeSundays actualizado:', this.excludeSundays());
5229
+ });
5230
+ }
5231
+ // ============================================
5232
+ // PRIVATE METHODS
5233
+ // ============================================
5234
+ normalizeDateToString(date) {
5235
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5236
+ let result = '';
5237
+ if (!date) {
5238
+ this.logPerformance('normalizeDateToString', perfStart);
5239
+ return result;
5240
+ }
5241
+ if (date instanceof Date) {
5242
+ if (isNaN(date.getTime())) {
5243
+ this.logPerformance('normalizeDateToString', perfStart);
5244
+ return result;
5245
+ }
5246
+ result = this.formatDate(date);
5247
+ }
5248
+ if (typeof date === 'string') {
5249
+ if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
5250
+ result = date;
5251
+ }
5252
+ else {
5253
+ const parsed = new Date(date);
5254
+ if (!isNaN(parsed.getTime())) {
5255
+ result = this.formatDate(parsed);
5256
+ }
5257
+ }
5258
+ }
5259
+ this.logPerformance('normalizeDateToString', perfStart);
5260
+ return result;
5261
+ }
5262
+ formatInputDate(value) {
5263
+ if (!value)
5264
+ return '';
5265
+ if (value instanceof Date) {
5266
+ if (isNaN(value.getTime()))
5267
+ return '';
5268
+ return this.formatDate(value);
5269
+ }
5270
+ if (typeof value === 'string') {
5271
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
5272
+ return value;
5273
+ }
5274
+ const date = new Date(value);
5275
+ if (!isNaN(date.getTime())) {
5276
+ return this.formatDate(date);
5277
+ }
5278
+ return '';
5279
+ }
5280
+ return '';
5281
+ }
5282
+ emitRangeChange() {
5283
+ const start = this.startDateStr();
5284
+ const end = this.endDateStr();
5285
+ if (start && end) {
5286
+ this.logDebug('Emitiendo rangeChanged:', { start, end });
5287
+ this.rangeChanged.emit({ start, end });
5288
+ }
5289
+ }
5290
+ // ============================================
5291
+ // PUBLIC METHODS (Template)
5292
+ // ============================================
5293
+ onStartDateChange(event) {
5294
+ if (!this.isEdit())
5295
+ return;
5296
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5297
+ const value = event.target.value;
5298
+ this.startDate.set(value);
5299
+ this.logDebug('onStartDateChange:', value);
5300
+ this.logPerformance('onStartDateChange', perfStart);
5301
+ }
5302
+ onEndDateChange(event) {
5303
+ if (!this.isEdit())
5304
+ return;
5305
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5306
+ const value = event.target.value;
5307
+ this.endDate.set(value);
5308
+ this.logDebug('onEndDateChange:', value);
5309
+ this.logPerformance('onEndDateChange', perfStart);
5310
+ }
5311
+ onToggleSundays(event) {
5312
+ if (!this.isEdit())
5313
+ return;
5314
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5315
+ const checked = event.target.checked;
5316
+ this.excludeSundays.set(checked);
5317
+ this.logDebug('onToggleSundays:', checked);
5318
+ this.logPerformance('onToggleSundays', perfStart);
5319
+ }
5320
+ // ============================================
5321
+ // GENERATE MONTH
5322
+ // ============================================
5323
+ generateMonth(monthDate, rangeStart, rangeEnd) {
5324
+ const perfStart = this.shouldLog() ? performance.now() : 0;
5325
+ const year = monthDate.getFullYear();
5326
+ const month = monthDate.getMonth();
5327
+ const firstDay = new Date(year, month, 1);
5328
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
5329
+ const startDayOfWeek = firstDay.getDay();
5330
+ const days = [];
5331
+ const holidays = this.holidays();
5332
+ const totalRangeDays = this.getDaysBetween(rangeStart, rangeEnd);
5333
+ // Días anteriores
5334
+ const prevMonthLastDay = new Date(year, month, 0).getDate();
5335
+ for (let i = startDayOfWeek - 1; i >= 0; i--) {
5336
+ const d = new Date(year, month, -i);
5337
+ days.push({
5338
+ date: d,
5339
+ day: prevMonthLastDay - i,
5340
+ isCurrentMonth: false,
5341
+ isSunday: d.getDay() === 0,
5342
+ isInRange: false,
5343
+ isStart: false,
5344
+ isEnd: false,
5345
+ isHoliday: false,
5346
+ disabled: false,
5347
+ });
5348
+ }
5349
+ // Días del mes actual
5350
+ for (let i = 1; i <= daysInMonth; i++) {
5351
+ const d = new Date(year, month, i);
5352
+ const dateStr = this.formatDate(d);
5353
+ const holiday = holidays.find((h) => {
5354
+ const hStr = this.normalizeDateToString(h.dateHoliday);
5355
+ return hStr === dateStr;
5356
+ });
5357
+ const isSunday = d.getDay() === 0;
5358
+ const isInRange = this.isDateInRange(d, rangeStart, rangeEnd);
5359
+ const isStart = this.isSameDay(d, rangeStart);
5360
+ const isEnd = this.isSameDay(d, rangeEnd);
5361
+ const disabled = this.excludeSundays() && isSunday;
5362
+ let rangePosition = 0;
5363
+ if (isInRange && !disabled) {
5364
+ const dayDiff = this.getDaysBetween(rangeStart, d) - 1;
5365
+ rangePosition = totalRangeDays > 1 ? dayDiff / (totalRangeDays - 1) : 0;
5366
+ }
5367
+ days.push({
5368
+ date: d,
5369
+ day: i,
5370
+ isCurrentMonth: true,
5371
+ isSunday,
5372
+ isInRange,
5373
+ isStart,
5374
+ isEnd,
5375
+ isHoliday: !!holiday,
5376
+ holidayLabel: holiday?.labelHoliday,
5377
+ disabled,
5378
+ rangePosition,
5379
+ });
5380
+ }
5381
+ // Días siguientes
5382
+ const totalCells = Math.ceil((startDayOfWeek + daysInMonth) / 7) * 7;
5383
+ const remaining = totalCells - days.length;
5384
+ for (let i = 1; i <= remaining; i++) {
5385
+ const d = new Date(year, month + 1, i);
5386
+ days.push({
5387
+ date: d,
5388
+ day: i,
5389
+ isCurrentMonth: false,
5390
+ isSunday: d.getDay() === 0,
5391
+ isInRange: false,
5392
+ isStart: false,
5393
+ isEnd: false,
5394
+ isHoliday: false,
5395
+ disabled: false,
5396
+ });
5397
+ }
5398
+ // Recalcular para días del mes actual
5399
+ for (const day of days) {
5400
+ if (day.isCurrentMonth) {
5401
+ const d = day.date;
5402
+ day.isInRange = this.isDateInRange(d, rangeStart, rangeEnd);
5403
+ day.isStart = this.isSameDay(d, rangeStart);
5404
+ day.isEnd = this.isSameDay(d, rangeEnd);
5405
+ day.disabled = this.excludeSundays() && day.isSunday;
5406
+ if (day.isInRange && !day.disabled) {
5407
+ const dayDiff = this.getDaysBetween(rangeStart, d) - 1;
5408
+ day.rangePosition =
5409
+ totalRangeDays > 1 ? dayDiff / (totalRangeDays - 1) : 0;
5410
+ }
5411
+ }
5412
+ }
5413
+ const monthNames = [
5414
+ 'Enero',
5415
+ 'Febrero',
5416
+ 'Marzo',
5417
+ 'Abril',
5418
+ 'Mayo',
5419
+ 'Junio',
5420
+ 'Julio',
5421
+ 'Agosto',
5422
+ 'Septiembre',
5423
+ 'Octubre',
5424
+ 'Noviembre',
5425
+ 'Diciembre',
5426
+ ];
5427
+ this.logPerformance('generateMonth', perfStart);
5428
+ return {
5429
+ label: `${monthNames[month]} ${year}`,
5430
+ days,
5431
+ };
5432
+ }
5433
+ // ============================================
5434
+ // HELPERS
5435
+ // ============================================
5436
+ getDaysBetween(start, end) {
5437
+ const s = new Date(start.getFullYear(), start.getMonth(), start.getDate());
5438
+ const e = new Date(end.getFullYear(), end.getMonth(), end.getDate());
5439
+ const diffTime = Math.abs(e.getTime() - s.getTime());
5440
+ return Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
5441
+ }
5442
+ isDateInRange(date, start, end) {
5443
+ const d = new Date(date.getFullYear(), date.getMonth(), date.getDate());
5444
+ const s = new Date(start.getFullYear(), start.getMonth(), start.getDate());
5445
+ const e = new Date(end.getFullYear(), end.getMonth(), end.getDate());
5446
+ return d >= s && d <= e;
5447
+ }
5448
+ isSameDay(d1, d2) {
5449
+ if (!d2)
5450
+ return false;
5451
+ return (d1.getFullYear() === d2.getFullYear() &&
5452
+ d1.getMonth() === d2.getMonth() &&
5453
+ d1.getDate() === d2.getDate());
5454
+ }
5455
+ formatDate(date) {
5456
+ const y = date.getFullYear();
5457
+ const m = String(date.getMonth() + 1).padStart(2, '0');
5458
+ const d = String(date.getDate()).padStart(2, '0');
5459
+ return `${y}-${m}-${d}`;
5460
+ }
5461
+ // ============================================
5462
+ // LOGGING - SIMPLE Y SEGURO
5463
+ // ============================================
5464
+ /**
5465
+ * Verifica si debemos mostrar logs
5466
+ * ✅ Usa isDevMode() de Angular - simple y confiable
5467
+ */
5468
+ shouldLog() {
5469
+ return isDevMode() && this.debugMode();
5470
+ }
5471
+ /**
5472
+ * Log de depuración - Solo visible en desarrollo con debugMode=true
5473
+ * 🔥 NUNCA se ejecuta en producción
5474
+ */
5475
+ logDebug(...args) {
5476
+ if (this.shouldLog()) {
5477
+ console.log('[DsxCalendarView]', ...args);
5478
+ }
5479
+ }
5480
+ /**
5481
+ * Log de rendimiento - Mide tiempos de ejecución
5482
+ * 🔥 NUNCA se ejecuta en producción
5483
+ */
5484
+ logPerformance(method, startTime) {
5485
+ if (this.shouldLog() && startTime > 0) {
5486
+ const elapsed = (performance.now() - startTime).toFixed(2);
5487
+ if (Number(elapsed) > 0.1) {
5488
+ console.log(`[DsxCalendarView] ⚡ ${method} - ${elapsed}ms`);
5489
+ }
5490
+ }
5491
+ }
5492
+ // ============================================
5493
+ // TEMPLATE HELPERS
5494
+ // ============================================
5495
+ chunk(arr, size) {
5496
+ const result = [];
5497
+ for (let i = 0; i < arr.length; i += size) {
5498
+ result.push(arr.slice(i, i + size));
5499
+ }
5500
+ return result;
5501
+ }
5502
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxCalendarView, deps: [], target: i0.ɵɵFactoryTarget.Component });
5503
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: DsxCalendarView, isStandalone: true, selector: "dsx-calendar-view", inputs: { startDate: { classPropertyName: "startDate", publicName: "startDate", isSignal: true, isRequired: false, transformFunction: null }, endDate: { classPropertyName: "endDate", publicName: "endDate", isSignal: true, isRequired: false, transformFunction: null }, excludeSundays: { classPropertyName: "excludeSundays", publicName: "excludeSundays", isSignal: true, isRequired: false, transformFunction: null }, holidays: { classPropertyName: "holidays", publicName: "holidays", isSignal: true, isRequired: false, transformFunction: null }, compactMode: { classPropertyName: "compactMode", publicName: "compactMode", isSignal: true, isRequired: false, transformFunction: null }, showKPI: { classPropertyName: "showKPI", publicName: "showKPI", isSignal: true, isRequired: false, transformFunction: null }, debugMode: { classPropertyName: "debugMode", publicName: "debugMode", isSignal: true, isRequired: false, transformFunction: null }, isEdit: { classPropertyName: "isEdit", publicName: "isEdit", isSignal: true, isRequired: false, transformFunction: null }, showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { startDate: "startDateChange", endDate: "endDateChange", excludeSundays: "excludeSundaysChange", rangeChanged: "rangeChanged" }, ngImport: i0, template: "<!-- dsx-calendar-view.html - ACTUALIZADO CON showControls -->\r\n\r\n<div class=\"calendar-range\" [class.compact]=\"compactMode()\">\r\n <!-- ==========================================\r\n CONTROLES - Ocultables con showControls\r\n ========================================== -->\r\n @if (shouldShowControls()) {\r\n <div class=\"controls\">\r\n <div class=\"control-group\">\r\n <label>Fecha Inicio</label>\r\n <input\r\n type=\"date\"\r\n [value]=\"startDateStr()\"\r\n (input)=\"onStartDateChange($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n </div>\r\n <div class=\"control-group\">\r\n <label>Fecha Fin</label>\r\n <input\r\n type=\"date\"\r\n [value]=\"endDateStr()\"\r\n (input)=\"onEndDateChange($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n </div>\r\n <div class=\"control-group checkbox\">\r\n <label>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"excludeSundays()\"\r\n (change)=\"onToggleSundays($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n Excluir Domingos\r\n </label>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- ==========================================\r\n KPIs\r\n ========================================== -->\r\n @if (showKPI() && kpi()) {\r\n <div class=\"kpi-container\">\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-regular fa-calendar-days\"></i>\r\n D\u00EDas calendario\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.totalDays }}</span>\r\n </div>\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-regular fa-circle-check\"></i>\r\n D\u00EDas h\u00E1biles\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.businessDays }}</span>\r\n </div>\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-solid fa-not-equal\"></i>\r\n Feriados\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.holidays }}</span>\r\n </div>\r\n @if (excludeSundays()) {\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-solid fa-calendar-day\"></i>\r\n Domingos\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.sundays }}</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- ==========================================\r\n CALENDARIO\r\n ========================================== -->\r\n <div class=\"months-grid\">\r\n @for (month of months(); track month.label) {\r\n <div class=\"month-card\">\r\n <div class=\"month-title\">{{ month.label }}</div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n @for (dia of ['Do','Lu','Ma','Mi','Ju','Vi','Sa']; track dia) {\r\n <th>{{ dia }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of chunk(month.days, 7); track $index) {\r\n <tr>\r\n @for (day of row; track day.date) {\r\n <td\r\n [class.other-month]=\"!day.isCurrentMonth\"\r\n [class.sunday]=\"day.isSunday && !day.disabled && day.isCurrentMonth\"\r\n [class.disabled-sunday]=\"day.disabled\"\r\n [class.in-range]=\"day.isInRange && day.isCurrentMonth\"\r\n [class.start-date]=\"day.isStart && day.isCurrentMonth\"\r\n [class.end-date]=\"day.isEnd && day.isCurrentMonth\"\r\n [class.holiday]=\"day.isHoliday && day.isCurrentMonth\"\r\n [class.same-day]=\"day.isStart && day.isEnd\"\r\n [style.--range-position]=\"day.rangePosition\"\r\n [title]=\"day.isHoliday ? day.holidayLabel : ''\"\r\n >\r\n <span class=\"day-number\">{{ day.day }}</span>\r\n @if (day.isHoliday && day.isCurrentMonth) {\r\n <span class=\"holiday-label\">{{ day.holidayLabel }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- ==========================================\r\n FERIADOS DETALLE\r\n ========================================== -->\r\n @if (kpi()?.holidays && formattedHolidays().length) {\r\n <div class=\"holidays-detail\">\r\n <div class=\"holidays-detail-title\">\r\n <i class=\"fa-solid fa-calendar-day\"></i>\r\n Feriados en el per\u00EDodo\r\n </div>\r\n <div class=\"holidays-detail-list\">\r\n @for (h of formattedHolidays(); track h.date) {\r\n <span class=\"holiday-detail-tag\">\r\n <i class=\"fa-regular fa-calendar\"></i>\r\n {{ h.date }} - {{ h.label }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".calendar-range{font-family:system-ui,-apple-system,sans-serif;max-width:100%;padding:8px}.calendar-range.compact{max-width:750px;margin:0 auto}.controls{display:flex;flex-wrap:wrap;gap:16px 24px;margin-bottom:12px;padding:10px 16px;background:#f8f9fa;border-radius:6px;border:1px solid #e9ecef;align-items:center;justify-content:center}.control-group{display:flex;align-items:center;gap:8px}.control-group label{font-size:.8rem;font-weight:600;color:#495057;white-space:nowrap}.control-group input[type=date]{padding:4px 8px;border:1px solid #ced4da;border-radius:4px;font-size:.8rem;background:#fff;min-width:130px}.control-group.checkbox{margin-left:0;padding-left:8px;border-left:1px solid #dee2e6}.control-group.checkbox label{font-weight:400;font-size:.75rem;cursor:pointer;display:flex;align-items:center;gap:4px}.kpi-container{display:flex;flex-wrap:wrap;gap:20px 32px;padding:10px 20px;margin-bottom:12px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:8px;border:1px solid #dee2e6;justify-content:center;align-items:center}.kpi-item{display:flex;align-items:center;gap:6px;font-size:.85rem}.kpi-label{color:#6c757d;font-weight:500}.kpi-value{font-weight:700;color:#212529;font-size:1.1rem;min-width:24px;text-align:center;background:#fff;padding:0 8px;border-radius:4px}.kpi-holidays{display:none}.months-grid{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}.month-card{flex:1 1 auto;min-width:230px;max-width:300px;background:#fff;border:1px solid #dee2e6;border-radius:6px;padding:6px 4px 4px}.month-title{text-align:center;font-size:.85rem;font-weight:600;color:#212529;margin-bottom:4px;padding:2px 0}.calendar-table{width:100%;border-collapse:collapse;font-size:.7rem;table-layout:fixed}.calendar-table th{text-align:center;font-weight:600;color:#6c757d;padding:2px 0;font-size:.65rem}.calendar-table td{text-align:center;padding:2px 0;border-radius:3px;height:28px;vertical-align:middle;font-size:.7rem;transition:background .1s;position:relative}.other-month{color:#ced4da;background:transparent}.sunday{background:#ffe0e0}.disabled-sunday{background:#f1f3f5!important;color:#adb5bd!important;cursor:default}.in-range{background:#c4eeff}.start-date{background:#28a745!important;color:#fff!important;border-radius:3px 0 0 3px;font-weight:700}.end-date{background:#d17015!important;color:#fff!important;border-radius:0 3px 3px 0;font-weight:700}.same-day{background:#28a745!important;color:#fff!important;border-radius:3px}.day-number{display:block;font-size:.75rem;line-height:1.2}.holiday:not(.other-month){background:#e8f0fe!important;border:2px solid #1a5a8c!important;border-radius:4px!important;position:relative;z-index:1}.holiday .day-number{font-weight:700!important;color:#1a3a5c!important}.holiday-label{display:block;font-size:.45rem;line-height:1.2;color:#1a3a5c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:95%;margin:0 auto;background:#1a5a8c1a;border-radius:2px;padding:0 2px;font-weight:600}.holiday:hover .holiday-label{white-space:normal;overflow:visible;position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:#1a3a5c;color:#fff;padding:4px 10px;border-radius:4px;font-size:.6rem;z-index:10;box-shadow:0 2px 8px #0003;max-width:180px;white-space:nowrap}.holidays-detail{margin-top:12px;padding:10px 16px;background:#f0f4f8;border:1px solid #1a5a8c;border-radius:8px;border-left:4px solid #1a5a8c}.holidays-detail-title{font-size:.8rem;font-weight:600;color:#1a3a5c;margin-bottom:6px;display:flex;align-items:center;gap:6px}.holidays-detail-title i{color:#1a5a8c}.holidays-detail-list{display:flex;flex-wrap:wrap;gap:6px 12px}.holiday-detail-tag{font-size:.7rem;color:#1a3a5c;background:#e8f0fe;padding:2px 12px;border-radius:12px;border:1px solid #b3cfe5;display:inline-flex;align-items:center;gap:4px;white-space:nowrap}.holiday-detail-tag i{font-size:.6rem;color:#1a5a8c}.control-group input:disabled,.control-group input[disabled]{background:#f1f3f5!important;color:#6c757d!important;cursor:not-allowed;opacity:.7}.control-group input[type=checkbox]:disabled{cursor:not-allowed;opacity:.6}.control-group.checkbox label:has(input:disabled){color:#6c757d;cursor:not-allowed}@media(max-width:600px){.month-card{min-width:180px;max-width:100%}.controls{gap:10px;padding:8px 12px;flex-direction:column;align-items:stretch}.control-group{justify-content:space-between}.control-group input[type=date]{min-width:100px;flex:1}.control-group.checkbox{border-left:none;padding-left:0;justify-content:center}.kpi-container{gap:10px 16px;padding:8px 12px;justify-content:center}.kpi-item{font-size:.75rem}.kpi-value{font-size:.9rem;min-width:20px;padding:0 4px}.holidays-detail{padding:8px 12px}.holiday-detail-tag{font-size:.6rem;padding:2px 8px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
5504
+ }
5505
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxCalendarView, decorators: [{
5506
+ type: Component,
5507
+ args: [{ selector: 'dsx-calendar-view', standalone: true, imports: [CommonModule, FormsModule], template: "<!-- dsx-calendar-view.html - ACTUALIZADO CON showControls -->\r\n\r\n<div class=\"calendar-range\" [class.compact]=\"compactMode()\">\r\n <!-- ==========================================\r\n CONTROLES - Ocultables con showControls\r\n ========================================== -->\r\n @if (shouldShowControls()) {\r\n <div class=\"controls\">\r\n <div class=\"control-group\">\r\n <label>Fecha Inicio</label>\r\n <input\r\n type=\"date\"\r\n [value]=\"startDateStr()\"\r\n (input)=\"onStartDateChange($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n </div>\r\n <div class=\"control-group\">\r\n <label>Fecha Fin</label>\r\n <input\r\n type=\"date\"\r\n [value]=\"endDateStr()\"\r\n (input)=\"onEndDateChange($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n </div>\r\n <div class=\"control-group checkbox\">\r\n <label>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"excludeSundays()\"\r\n (change)=\"onToggleSundays($event)\"\r\n [disabled]=\"!isEdit()\"\r\n />\r\n Excluir Domingos\r\n </label>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- ==========================================\r\n KPIs\r\n ========================================== -->\r\n @if (showKPI() && kpi()) {\r\n <div class=\"kpi-container\">\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-regular fa-calendar-days\"></i>\r\n D\u00EDas calendario\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.totalDays }}</span>\r\n </div>\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-regular fa-circle-check\"></i>\r\n D\u00EDas h\u00E1biles\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.businessDays }}</span>\r\n </div>\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-solid fa-not-equal\"></i>\r\n Feriados\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.holidays }}</span>\r\n </div>\r\n @if (excludeSundays()) {\r\n <div class=\"kpi-item\">\r\n <span class=\"kpi-label\">\r\n <i class=\"fa-solid fa-calendar-day\"></i>\r\n Domingos\r\n </span>\r\n <span class=\"kpi-value\">{{ kpi()?.sundays }}</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- ==========================================\r\n CALENDARIO\r\n ========================================== -->\r\n <div class=\"months-grid\">\r\n @for (month of months(); track month.label) {\r\n <div class=\"month-card\">\r\n <div class=\"month-title\">{{ month.label }}</div>\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr>\r\n @for (dia of ['Do','Lu','Ma','Mi','Ju','Vi','Sa']; track dia) {\r\n <th>{{ dia }}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of chunk(month.days, 7); track $index) {\r\n <tr>\r\n @for (day of row; track day.date) {\r\n <td\r\n [class.other-month]=\"!day.isCurrentMonth\"\r\n [class.sunday]=\"day.isSunday && !day.disabled && day.isCurrentMonth\"\r\n [class.disabled-sunday]=\"day.disabled\"\r\n [class.in-range]=\"day.isInRange && day.isCurrentMonth\"\r\n [class.start-date]=\"day.isStart && day.isCurrentMonth\"\r\n [class.end-date]=\"day.isEnd && day.isCurrentMonth\"\r\n [class.holiday]=\"day.isHoliday && day.isCurrentMonth\"\r\n [class.same-day]=\"day.isStart && day.isEnd\"\r\n [style.--range-position]=\"day.rangePosition\"\r\n [title]=\"day.isHoliday ? day.holidayLabel : ''\"\r\n >\r\n <span class=\"day-number\">{{ day.day }}</span>\r\n @if (day.isHoliday && day.isCurrentMonth) {\r\n <span class=\"holiday-label\">{{ day.holidayLabel }}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- ==========================================\r\n FERIADOS DETALLE\r\n ========================================== -->\r\n @if (kpi()?.holidays && formattedHolidays().length) {\r\n <div class=\"holidays-detail\">\r\n <div class=\"holidays-detail-title\">\r\n <i class=\"fa-solid fa-calendar-day\"></i>\r\n Feriados en el per\u00EDodo\r\n </div>\r\n <div class=\"holidays-detail-list\">\r\n @for (h of formattedHolidays(); track h.date) {\r\n <span class=\"holiday-detail-tag\">\r\n <i class=\"fa-regular fa-calendar\"></i>\r\n {{ h.date }} - {{ h.label }}\r\n </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".calendar-range{font-family:system-ui,-apple-system,sans-serif;max-width:100%;padding:8px}.calendar-range.compact{max-width:750px;margin:0 auto}.controls{display:flex;flex-wrap:wrap;gap:16px 24px;margin-bottom:12px;padding:10px 16px;background:#f8f9fa;border-radius:6px;border:1px solid #e9ecef;align-items:center;justify-content:center}.control-group{display:flex;align-items:center;gap:8px}.control-group label{font-size:.8rem;font-weight:600;color:#495057;white-space:nowrap}.control-group input[type=date]{padding:4px 8px;border:1px solid #ced4da;border-radius:4px;font-size:.8rem;background:#fff;min-width:130px}.control-group.checkbox{margin-left:0;padding-left:8px;border-left:1px solid #dee2e6}.control-group.checkbox label{font-weight:400;font-size:.75rem;cursor:pointer;display:flex;align-items:center;gap:4px}.kpi-container{display:flex;flex-wrap:wrap;gap:20px 32px;padding:10px 20px;margin-bottom:12px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:8px;border:1px solid #dee2e6;justify-content:center;align-items:center}.kpi-item{display:flex;align-items:center;gap:6px;font-size:.85rem}.kpi-label{color:#6c757d;font-weight:500}.kpi-value{font-weight:700;color:#212529;font-size:1.1rem;min-width:24px;text-align:center;background:#fff;padding:0 8px;border-radius:4px}.kpi-holidays{display:none}.months-grid{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}.month-card{flex:1 1 auto;min-width:230px;max-width:300px;background:#fff;border:1px solid #dee2e6;border-radius:6px;padding:6px 4px 4px}.month-title{text-align:center;font-size:.85rem;font-weight:600;color:#212529;margin-bottom:4px;padding:2px 0}.calendar-table{width:100%;border-collapse:collapse;font-size:.7rem;table-layout:fixed}.calendar-table th{text-align:center;font-weight:600;color:#6c757d;padding:2px 0;font-size:.65rem}.calendar-table td{text-align:center;padding:2px 0;border-radius:3px;height:28px;vertical-align:middle;font-size:.7rem;transition:background .1s;position:relative}.other-month{color:#ced4da;background:transparent}.sunday{background:#ffe0e0}.disabled-sunday{background:#f1f3f5!important;color:#adb5bd!important;cursor:default}.in-range{background:#c4eeff}.start-date{background:#28a745!important;color:#fff!important;border-radius:3px 0 0 3px;font-weight:700}.end-date{background:#d17015!important;color:#fff!important;border-radius:0 3px 3px 0;font-weight:700}.same-day{background:#28a745!important;color:#fff!important;border-radius:3px}.day-number{display:block;font-size:.75rem;line-height:1.2}.holiday:not(.other-month){background:#e8f0fe!important;border:2px solid #1a5a8c!important;border-radius:4px!important;position:relative;z-index:1}.holiday .day-number{font-weight:700!important;color:#1a3a5c!important}.holiday-label{display:block;font-size:.45rem;line-height:1.2;color:#1a3a5c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:95%;margin:0 auto;background:#1a5a8c1a;border-radius:2px;padding:0 2px;font-weight:600}.holiday:hover .holiday-label{white-space:normal;overflow:visible;position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:#1a3a5c;color:#fff;padding:4px 10px;border-radius:4px;font-size:.6rem;z-index:10;box-shadow:0 2px 8px #0003;max-width:180px;white-space:nowrap}.holidays-detail{margin-top:12px;padding:10px 16px;background:#f0f4f8;border:1px solid #1a5a8c;border-radius:8px;border-left:4px solid #1a5a8c}.holidays-detail-title{font-size:.8rem;font-weight:600;color:#1a3a5c;margin-bottom:6px;display:flex;align-items:center;gap:6px}.holidays-detail-title i{color:#1a5a8c}.holidays-detail-list{display:flex;flex-wrap:wrap;gap:6px 12px}.holiday-detail-tag{font-size:.7rem;color:#1a3a5c;background:#e8f0fe;padding:2px 12px;border-radius:12px;border:1px solid #b3cfe5;display:inline-flex;align-items:center;gap:4px;white-space:nowrap}.holiday-detail-tag i{font-size:.6rem;color:#1a5a8c}.control-group input:disabled,.control-group input[disabled]{background:#f1f3f5!important;color:#6c757d!important;cursor:not-allowed;opacity:.7}.control-group input[type=checkbox]:disabled{cursor:not-allowed;opacity:.6}.control-group.checkbox label:has(input:disabled){color:#6c757d;cursor:not-allowed}@media(max-width:600px){.month-card{min-width:180px;max-width:100%}.controls{gap:10px;padding:8px 12px;flex-direction:column;align-items:stretch}.control-group{justify-content:space-between}.control-group input[type=date]{min-width:100px;flex:1}.control-group.checkbox{border-left:none;padding-left:0;justify-content:center}.kpi-container{gap:10px 16px;padding:8px 12px;justify-content:center}.kpi-item{font-size:.75rem}.kpi-value{font-size:.9rem;min-width:20px;padding:0 4px}.holidays-detail{padding:8px 12px}.holiday-detail-tag{font-size:.6rem;padding:2px 8px}}\n"] }]
5508
+ }], ctorParameters: () => [], propDecorators: { startDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "startDate", required: false }] }, { type: i0.Output, args: ["startDateChange"] }], endDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "endDate", required: false }] }, { type: i0.Output, args: ["endDateChange"] }], excludeSundays: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeSundays", required: false }] }, { type: i0.Output, args: ["excludeSundaysChange"] }], holidays: [{ type: i0.Input, args: [{ isSignal: true, alias: "holidays", required: false }] }], compactMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "compactMode", required: false }] }], showKPI: [{ type: i0.Input, args: [{ isSignal: true, alias: "showKPI", required: false }] }], debugMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "debugMode", required: false }] }], isEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEdit", required: false }] }], showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: false }] }], rangeChanged: [{ type: i0.Output, args: ["rangeChanged"] }] } });
5509
+
4977
5510
  class FileComponent {
4978
5511
  // Inputs
4979
5512
  existingFile = input(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : /* istanbul ignore next */ []));
@@ -5073,15 +5606,18 @@ class FileComponent {
5073
5606
  const acceptStr = this.accept();
5074
5607
  if (!acceptStr)
5075
5608
  return 'archivo';
5076
- const extensions = acceptStr.split(',').map((ext) => ext.trim());
5077
- const cleanExtensions = extensions
5078
- .map((ext) => ext.replace('.', '').toUpperCase())
5609
+ const cleanExtensions = acceptStr
5610
+ .split(',')
5611
+ .map((ext) => ext.trim().replace('.', '').toUpperCase())
5079
5612
  .filter((ext) => ext.length > 0);
5080
5613
  if (cleanExtensions.length === 0)
5081
5614
  return 'archivo';
5082
- if (cleanExtensions.length === 1)
5083
- return cleanExtensions[0];
5084
- return cleanExtensions.join(' o ');
5615
+ // Formateador nativo en español para listas disyuntivas ("o")
5616
+ const formatter = new Intl.ListFormat('es', {
5617
+ style: 'long',
5618
+ type: 'disjunction',
5619
+ });
5620
+ return formatter.format(cleanExtensions);
5085
5621
  }, ...(ngDevMode ? [{ debugName: "allowedFileTypeLabel" }] : /* istanbul ignore next */ []));
5086
5622
  // --- Constructor ---
5087
5623
  constructor() {
@@ -5412,7 +5948,7 @@ class FileComponent {
5412
5948
  useExisting: forwardRef(() => FileComponent),
5413
5949
  multi: true,
5414
5950
  },
5415
- ], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"`${pTooltipOverride()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#22994a}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"], dependencies: [{ kind: "component", type: FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: JsonPipe, name: "json" }] });
5951
+ ], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"`${pTooltipOverride()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-solid fa-paperclip file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <i\r\n class=\"fa-regular fa-file-lines fa-fade placeholder-icon\"\r\n ></i>\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado.</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado.</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#3f3e37;background:#dfc800;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#3ad46d}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"], dependencies: [{ kind: "component", type: FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: JsonPipe, name: "json" }] });
5416
5952
  }
5417
5953
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, decorators: [{
5418
5954
  type: Component,
@@ -5427,7 +5963,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
5427
5963
  useExisting: forwardRef(() => FileComponent),
5428
5964
  multi: true,
5429
5965
  },
5430
- ], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"`${pTooltipOverride()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#22994a}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"] }]
5966
+ ], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"`${pTooltipOverride()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-solid fa-paperclip file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <i\r\n class=\"fa-regular fa-file-lines fa-fade placeholder-icon\"\r\n ></i>\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado.</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado.</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#3f3e37;background:#dfc800;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#3ad46d}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"] }]
5431
5967
  }], ctorParameters: () => [], propDecorators: { existingFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFile", required: false }] }], existingFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFileName", required: false }] }], overrideFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideFileName", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], pTooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "pTooltipOverride", required: false }] }], tooltipPositionOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPositionOverride", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], invalidSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSummary", required: false }] }], invalidDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidDetail", required: false }] }], invalidSizeSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeSummary", required: false }] }], invalidSizeDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeDetail", required: false }] }], fileUpload: [{ type: i0.ViewChild, args: ['fileUpload', { isSignal: true }] }] } });
5432
5968
 
5433
5969
  function uid() {
@@ -5626,64 +6162,91 @@ class JsonValuesDebujComponent {
5626
6162
  }
5627
6163
  return files;
5628
6164
  }
5629
- updateSerializedValue(value) {
5630
- if (!value) {
5631
- this.serializedValue.set('');
5632
- return;
6165
+ // ✅ Método para serializar cualquier valor (incluyendo fechas)
6166
+ serializeValue(value) {
6167
+ // Si es null o undefined
6168
+ if (value === null || value === undefined) {
6169
+ return null;
5633
6170
  }
5634
- try {
5635
- // Clonar y procesar archivos en toda la estructura
5636
- const copy = this.cloneWithFileProcessing(value);
5637
- this.serializedValue.set(JSON.stringify(copy, null, 2));
6171
+ // ✅ Si es un objeto Date, convertirlo a string ISO
6172
+ if (value instanceof Date) {
6173
+ return value.toISOString();
5638
6174
  }
5639
- catch (error) {
5640
- this.serializedValue.set('Error al serializar: ' + error);
5641
- if (this.shouldShowLogs()) {
5642
- console.error('[JsonDebug] Error serializing value:', error);
5643
- }
6175
+ // ✅ Si es un objeto moment (si usas moment.js)
6176
+ if (value && typeof value === 'object' && value._isAMomentObject) {
6177
+ return value.toISOString();
5644
6178
  }
5645
- }
5646
- // Clonar objeto procesando archivos recursivamente
5647
- cloneWithFileProcessing(obj) {
5648
- if (!obj || typeof obj !== 'object') {
5649
- return obj;
6179
+ // ✅ Si es un objeto dayjs (si usas dayjs)
6180
+ if (value &&
6181
+ typeof value === 'object' &&
6182
+ value.$d &&
6183
+ value.$d instanceof Date) {
6184
+ return value.toISOString();
6185
+ }
6186
+ // ✅ Si es un objeto con propiedades de fecha (como { year, month, day })
6187
+ if (value &&
6188
+ typeof value === 'object' &&
6189
+ value.year !== undefined &&
6190
+ value.month !== undefined &&
6191
+ value.day !== undefined) {
6192
+ try {
6193
+ const date = new Date(value.year, value.month - 1, value.day);
6194
+ return date.toISOString();
6195
+ }
6196
+ catch (e) {
6197
+ return value;
6198
+ }
5650
6199
  }
5651
6200
  // Si es un File o Blob, extraer sus propiedades
5652
- if (obj instanceof File || obj instanceof Blob) {
6201
+ if (value instanceof File || value instanceof Blob) {
5653
6202
  const fileProps = {
5654
- __type: obj instanceof File ? 'File' : 'Blob',
6203
+ __type: value instanceof File ? 'File' : 'Blob',
5655
6204
  };
5656
- if ('name' in obj && obj.name !== undefined) {
5657
- fileProps.name = obj.name;
6205
+ if ('name' in value && value.name !== undefined) {
6206
+ fileProps.name = value.name;
5658
6207
  }
5659
- if ('size' in obj && obj.size !== undefined) {
5660
- fileProps.size = obj.size;
6208
+ if ('size' in value && value.size !== undefined) {
6209
+ fileProps.size = value.size;
5661
6210
  }
5662
- if ('type' in obj && obj.type !== undefined) {
5663
- fileProps.type = obj.type;
6211
+ if ('type' in value && value.type !== undefined) {
6212
+ fileProps.type = value.type;
5664
6213
  }
5665
- if ('lastModified' in obj && obj.lastModified !== undefined) {
5666
- fileProps.lastModified = obj.lastModified;
6214
+ if ('lastModified' in value && value.lastModified !== undefined) {
6215
+ fileProps.lastModified = value.lastModified;
5667
6216
  }
5668
6217
  return fileProps;
5669
6218
  }
5670
6219
  // Si es un array, procesar cada elemento
5671
- if (Array.isArray(obj)) {
5672
- return obj.map((item) => this.cloneWithFileProcessing(item));
6220
+ if (Array.isArray(value)) {
6221
+ return value.map((item) => this.serializeValue(item));
5673
6222
  }
5674
6223
  // Si es un objeto, procesar cada propiedad
5675
- const result = {};
5676
- Object.keys(obj).forEach((key) => {
5677
- // Si la propiedad es 'file' y es un File/Blob, procesarla
5678
- if (key === 'file' &&
5679
- (obj[key] instanceof File || obj[key] instanceof Blob)) {
5680
- result[key] = this.cloneWithFileProcessing(obj[key]);
5681
- }
5682
- else {
5683
- result[key] = this.cloneWithFileProcessing(obj[key]);
6224
+ if (typeof value === 'object') {
6225
+ const result = {};
6226
+ Object.keys(value).forEach((key) => {
6227
+ result[key] = this.serializeValue(value[key]);
6228
+ });
6229
+ return result;
6230
+ }
6231
+ // Primitivos (string, number, boolean)
6232
+ return value;
6233
+ }
6234
+ updateSerializedValue(value) {
6235
+ if (!value) {
6236
+ this.serializedValue.set('');
6237
+ return;
6238
+ }
6239
+ try {
6240
+ // ✅ Serializar todo el objeto (incluyendo fechas)
6241
+ const serialized = this.serializeValue(value);
6242
+ this.serializedValue.set(JSON.stringify(serialized, null, 2));
6243
+ }
6244
+ catch (error) {
6245
+ this.serializedValue.set('Error al serializar: ' + error);
6246
+ if (this.shouldShowLogs()) {
6247
+ console.error('[JsonDebug] Error serializing value:', error);
5684
6248
  }
5685
- });
5686
- return result;
6249
+ }
5687
6250
  }
5688
6251
  updateFileInfo(value) {
5689
6252
  if (!value) {
@@ -5691,7 +6254,7 @@ class JsonValuesDebujComponent {
5691
6254
  this.filesSummary.set('');
5692
6255
  return;
5693
6256
  }
5694
- // Buscar todos los archivos en la estructura
6257
+ // Buscar todos los archivos en la estructura
5695
6258
  const files = this.findFilesInObject(value);
5696
6259
  if (files.length === 0) {
5697
6260
  this.fileInfo.set({
@@ -5703,7 +6266,7 @@ class JsonValuesDebujComponent {
5703
6266
  this.filesSummary.set('📭 Sin archivos');
5704
6267
  return;
5705
6268
  }
5706
- // Resumir información de archivos
6269
+ // Resumir información de archivos
5707
6270
  const summary = files
5708
6271
  .map((f) => {
5709
6272
  const name = f.file?.name || 'sin nombre';
@@ -5713,7 +6276,7 @@ class JsonValuesDebujComponent {
5713
6276
  })
5714
6277
  .join('; ');
5715
6278
  this.filesSummary.set(`📁 ${files.length} archivo(s): ${summary}`);
5716
- // Información detallada
6279
+ // Información detallada
5717
6280
  const info = {
5718
6281
  exists: true,
5719
6282
  count: files.length,
@@ -5731,7 +6294,6 @@ class JsonValuesDebujComponent {
5731
6294
  const value = this.debugValue();
5732
6295
  if (!value)
5733
6296
  return false;
5734
- // ✅ Buscar archivos en toda la estructura
5735
6297
  const files = this.findFilesInObject(value);
5736
6298
  return files.length > 0;
5737
6299
  }
@@ -5758,7 +6320,7 @@ class JsonValuesDebujComponent {
5758
6320
  }
5759
6321
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JsonValuesDebujComponent, decorators: [{
5760
6322
  type: Component,
5761
- args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [DatePipe, DecimalPipe], encapsulation: ViewEncapsulation.None, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- \u2705 Informaci\u00F3n de archivos encontrados en toda la estructura -->\r\n @if (hasFileProperty()) {\r\n <div class=\"file-info-box\">\r\n <div class=\"file-info-header\">\r\n \uD83D\uDCC1 Archivos encontrados ({{ getFileInfo()?.count || 0 }})\r\n </div>\r\n <div class=\"file-info-grid\">\r\n @for (file of getFileInfo()?.files || []; track file.path) {\r\n <div class=\"file-info-item file-item\">\r\n <div class=\"file-path\">\uD83D\uDCC4 {{ file.path }}</div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Nombre:</span>\r\n <span class=\"value\">{{ file.name }}</span>\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tama\u00F1o:</span>\r\n <span class=\"value\"\r\n >{{ file.size / 1024 | number: \"1.1-1\" }} KB</span\r\n >\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tipo:</span>\r\n <span class=\"value\">{{ file.type || \"Desconocido\" }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"file-info-box file-empty\">\r\n <div class=\"file-info-header\">\uD83D\uDCED Sin archivos seleccionados</div>\r\n </div>\r\n }\r\n\r\n <!-- JSON -->\r\n <div class=\"json-display\">\r\n <pre class=\"json-colored\">{{ serializedValue() }}</pre>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".json-debug-container{margin:10px 0;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;font-family:Consolas,Monaco,Courier New,monospace;font-size:13px;box-shadow:0 2px 8px #0000001a}.json-debug-header{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;background:linear-gradient(135deg,#667eea,#764ba2);border-radius:8px 8px 0 0;color:#fff}.json-debug-id{font-weight:700;font-size:14px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}.badge{padding:4px 14px;border-radius:20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.badge-success{background-color:#10b981;color:#fff;box-shadow:0 2px 4px #10b9814d}.badge-danger{background-color:#ef4444;color:#fff;box-shadow:0 2px 4px #ef44444d}.json-debug-content{padding:16px 20px}.file-info-box{background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border:1px solid #bae6fd;border-radius:6px;padding:12px 16px;margin-bottom:16px}.file-info-header{font-weight:600;color:#0369a1;font-size:13px;margin-bottom:8px}.file-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:6px}.file-info-item{padding:4px 8px;background-color:#fff;border-radius:4px;border:1px solid #e5e7eb}.file-info-item .label{font-weight:600;color:#6b7280;margin-right:8px;font-size:12px}.file-info-item .value{color:#0369a1;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px}.json-display{margin-top:0}.json-colored{margin:0;padding:16px 20px;background-color:#1e1e1e;border-radius:6px;overflow:auto;font-size:13px;line-height:1.7;color:#d4d4d4;min-height:50px;max-height:500px;font-family:Consolas,Monaco,Courier New,monospace;white-space:pre}.json-colored::-webkit-scrollbar{width:10px;height:10px}.json-colored::-webkit-scrollbar-track{background:#2d2d2d;border-radius:4px}.json-colored::-webkit-scrollbar-thumb{background:#666;border-radius:4px}.json-colored::-webkit-scrollbar-thumb:hover{background:#888}@media(max-width:768px){.json-debug-header{flex-direction:column;gap:8px;padding:10px 16px}.json-debug-content{padding:12px 16px}.file-info-grid{grid-template-columns:1fr}.json-colored{font-size:11px;padding:12px 14px;max-height:300px}}\n"] }]
6323
+ args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [DecimalPipe], encapsulation: ViewEncapsulation.None, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- \u2705 Informaci\u00F3n de archivos encontrados en toda la estructura -->\r\n @if (hasFileProperty()) {\r\n <div class=\"file-info-box\">\r\n <div class=\"file-info-header\">\r\n \uD83D\uDCC1 Archivos encontrados ({{ getFileInfo()?.count || 0 }})\r\n </div>\r\n <div class=\"file-info-grid\">\r\n @for (file of getFileInfo()?.files || []; track file.path) {\r\n <div class=\"file-info-item file-item\">\r\n <div class=\"file-path\">\uD83D\uDCC4 {{ file.path }}</div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Nombre:</span>\r\n <span class=\"value\">{{ file.name }}</span>\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tama\u00F1o:</span>\r\n <span class=\"value\"\r\n >{{ file.size / 1024 | number: \"1.1-1\" }} KB</span\r\n >\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tipo:</span>\r\n <span class=\"value\">{{ file.type || \"Desconocido\" }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"file-info-box file-empty\">\r\n <div class=\"file-info-header\">\uD83D\uDCED Sin archivos seleccionados</div>\r\n </div>\r\n }\r\n\r\n <!-- JSON -->\r\n <div class=\"json-display\">\r\n <pre class=\"json-colored\">{{ serializedValue() }}</pre>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".json-debug-container{margin:10px 0;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;font-family:Consolas,Monaco,Courier New,monospace;font-size:13px;box-shadow:0 2px 8px #0000001a}.json-debug-header{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;background:linear-gradient(135deg,#667eea,#764ba2);border-radius:8px 8px 0 0;color:#fff}.json-debug-id{font-weight:700;font-size:14px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}.badge{padding:4px 14px;border-radius:20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.badge-success{background-color:#10b981;color:#fff;box-shadow:0 2px 4px #10b9814d}.badge-danger{background-color:#ef4444;color:#fff;box-shadow:0 2px 4px #ef44444d}.json-debug-content{padding:16px 20px}.file-info-box{background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border:1px solid #bae6fd;border-radius:6px;padding:12px 16px;margin-bottom:16px}.file-info-header{font-weight:600;color:#0369a1;font-size:13px;margin-bottom:8px}.file-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:6px}.file-info-item{padding:4px 8px;background-color:#fff;border-radius:4px;border:1px solid #e5e7eb}.file-info-item .label{font-weight:600;color:#6b7280;margin-right:8px;font-size:12px}.file-info-item .value{color:#0369a1;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px}.json-display{margin-top:0}.json-colored{margin:0;padding:16px 20px;background-color:#1e1e1e;border-radius:6px;overflow:auto;font-size:13px;line-height:1.7;color:#d4d4d4;min-height:50px;max-height:500px;font-family:Consolas,Monaco,Courier New,monospace;white-space:pre}.json-colored::-webkit-scrollbar{width:10px;height:10px}.json-colored::-webkit-scrollbar-track{background:#2d2d2d;border-radius:4px}.json-colored::-webkit-scrollbar-thumb{background:#666;border-radius:4px}.json-colored::-webkit-scrollbar-thumb:hover{background:#888}@media(max-width:768px){.json-debug-header{flex-direction:column;gap:8px;padding:10px 16px}.json-debug-content{padding:12px 16px}.file-info-grid{grid-template-columns:1fr}.json-colored{font-size:11px;padding:12px 14px;max-height:300px}}\n"] }]
5762
6324
  }], ctorParameters: () => [], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }] } });
5763
6325
 
5764
6326
  class IcoLabel {
@@ -6643,7 +7205,7 @@ class NavbarDsxComponent {
6643
7205
  });
6644
7206
  }
6645
7207
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NavbarDsxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6646
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: NavbarDsxComponent, isStandalone: true, selector: "app-navbar-dsx", inputs: { appVersion: { classPropertyName: "appVersion", publicName: "appVersion", isSignal: true, isRequired: false, transformFunction: null }, logoWidth: { classPropertyName: "logoWidth", publicName: "logoWidth", isSignal: true, isRequired: false, transformFunction: null }, urlLogo: { classPropertyName: "urlLogo", publicName: "urlLogo", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<p-menubar>\r\n <ng-template #start>\r\n <p-image\r\n class=\"ms-15\"\r\n [src]=\"urlLogo()\"\r\n alt=\"Image\"\r\n [width]=\"logoWidth()\"\r\n />\r\n <span class=\"version-text\">{{ appVersion() }}</span>\r\n </ng-template>\r\n <ng-template #end>\r\n <div>\r\n <!-- Datos del usuario -->\r\n <div class=\"navbar-user-info\">\r\n <icon-dsx name=\"verified_user\" class=\"navbar-user-icon\"></icon-dsx>\r\n <div class=\"navbar-user-text\">\r\n <span class=\"navbar-user-name\">\r\n {{ _authorizeService.getTokenValues.userName }}\r\n </span>\r\n <span class=\"navbar-user-role\">\r\n {{ currentRole }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Componente de estado de red -->\r\n <app-network-status></app-network-status>\r\n\r\n <!-- Actualizaci\u00F3n de permisos -->\r\n <p-button\r\n size=\"small\"\r\n class=\"ml-2 mr-2\"\r\n label=\"Permisos\"\r\n variant=\"text\"\r\n severity=\"secondary\"\r\n (click)=\"actualizarSeguridadIT()\"\r\n >\r\n <span class=\"material-symbols-outlined mr-1\">local_police</span>\r\n </p-button>\r\n\r\n <label class=\"ui-switch\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"checked\"\r\n (click)=\"onThemeChange(!checked ? true : false)\"\r\n />\r\n <div class=\"slider\">\r\n <div class=\"circle\"></div>\r\n </div>\r\n </label>\r\n <!-- <p-inputSwitch\r\n [(ngModel)]=\"checked\"\r\n (onChange)=\"onThemeChange($event.checked)\"\r\n ></p-inputSwitch> -->\r\n </div>\r\n </ng-template>\r\n</p-menubar>\r\n", styles: [":host ::ng-deep .p-menubar{display:flex;align-items:center!important;padding:.25rem 1.5rem!important;border-radius:999px;border:1px solid rgba(255,255,255,.25);background:#ffffff73!important;backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 10px 30px #0f172a14;margin-left:4rem;margin-right:2.5rem}:host ::ng-deep .p-menubar-end>*{display:flex;align-items:center}.version-text{font-size:1.3rem;font-family:Montserrat,sans-serif!important;margin-left:.5rem;font-weight:600;background-image:linear-gradient(to right,#38bdf8,#630cb4);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 2px 4px rgba(0,0,0,.1);padding:.2rem 0}.navbar-user-info{display:flex;align-items:center;gap:.35rem;padding:0 .75rem;border-radius:999px;background-color:#00000005}.navbar-user-icon{font-size:1.5rem;color:#374151}.navbar-user-name{font-size:.8rem;font-weight:500;color:#374151;white-space:nowrap}.navbar-user-text{display:flex;flex-direction:column;line-height:1.1}.navbar-user-role{font-size:.7rem;color:#6b7280;white-space:nowrap}.ui-switch{--switch-bg: rgb(135, 150, 165);--switch-width: 48px;--switch-height: 20px;--circle-diameter: 32px;--circle-bg: rgb(232, 89, 15);--circle-inset: calc((var(--circle-diameter) - var(--switch-height)) / 2)}.ui-switch input{display:none}.slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--switch-width);height:var(--switch-height);background:var(--switch-bg);border-radius:999px;position:relative;cursor:pointer}.slider .circle{top:calc(var(--circle-inset) * -1);left:0;width:var(--circle-diameter);height:var(--circle-diameter);position:absolute;background:var(--circle-bg);border-radius:inherit;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTkuMzA1IDEuNjY3VjMuNzVoMS4zODlWMS42NjdoLTEuMzl6bS00LjcwNyAxLjk1bC0uOTgyLjk4Mkw1LjA5IDYuMDcybC45ODItLjk4Mi0xLjQ3My0xLjQ3M3ptMTAuODAyIDBMMTMuOTI3IDUuMDlsLjk4Mi45ODIgMS40NzMtMS40NzMtLjk4Mi0uOTgyek0xMCA1LjEzOWE0Ljg3MiA0Ljg3MiAwIDAwLTQuODYyIDQuODZBNC44NzIgNC44NzIgMCAwMDEwIDE0Ljg2MiA0Ljg3MiA0Ljg3MiAwIDAwMTQuODYgMTAgNC44NzIgNC44NzIgMCAwMDEwIDUuMTM5em0wIDEuMzg5QTMuNDYyIDMuNDYyIDAgMDExMy40NzEgMTBhMy40NjIgMy40NjIgMCAwMS0zLjQ3MyAzLjQ3MkEzLjQ2MiAzLjQ2MiAwIDAxNi41MjcgMTAgMy40NjIgMy40NjIgMCAwMTEwIDYuNTI4ek0xLjY2NSA5LjMwNXYxLjM5aDIuMDgzdi0xLjM5SDEuNjY2em0xNC41ODMgMHYxLjM5aDIuMDg0di0xLjM5aC0yLjA4NHpNNS4wOSAxMy45MjhMMy42MTYgMTUuNGwuOTgyLjk4MiAxLjQ3My0xLjQ3My0uOTgyLS45ODJ6bTkuODIgMGwtLjk4Mi45ODIgMS40NzMgMS40NzMuOTgyLS45ODItMS40NzMtMS40NzN6TTkuMzA1IDE2LjI1djIuMDgzaDEuMzg5VjE2LjI1aC0xLjM5eiIgLz4KPC9zdmc+);background-repeat:no-repeat;background-position:center center;transition:left .15s cubic-bezier(.4,0,.2,1) 0ms;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 1px -1px #0003,0 1px 1px #00000024,0 1px 3px #0000001f}.slider .circle:before{content:\"\";position:absolute;width:100%;height:100%;background:#ffffffbf;border-radius:inherit;transition:all .5s;opacity:0}.ui-switch input:checked+.slider .circle{left:calc(100% - var(--circle-diameter));background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTQuMiAyLjVsLS43IDEuOC0xLjguNyAxLjguNy43IDEuOC42LTEuOEw2LjcgNWwtMS45LS43LS42LTEuOHptMTUgOC4zYTYuNyA2LjcgMCAxMS02LjYtNi42IDUuOCA1LjggMCAwMDYuNiA2LjZ6IiAvPgo8L3N2Zz4=);background-color:#003892}.ui-switch input:active+.slider .circle:before{transition:0s;opacity:1;width:0;height:0}.navbar-user-info,.ui-switch .slider,.version-text{cursor:pointer}.navbar-user-info:active{transform:scale(.98);transition:transform .05s ease}.ui-switch:active .slider .circle{transform:scale(.95);transition:transform .05s ease}[data-title]{position:relative}[data-title]:hover:after{content:attr(data-title);position:absolute;bottom:125%;left:50%;transform:translate(-50%);background:#000c;color:#fff;font-size:.7rem;padding:.25rem .5rem;border-radius:.25rem;white-space:nowrap;z-index:1000;pointer-events:none;font-family:sans-serif}.navbar-user-info:focus-visible,.ui-switch .slider:focus-visible{outline:2px solid #38bdf8;outline-offset:2px}@media(prefers-reduced-motion:reduce){.navbar-user-info:active,.ui-switch:active .slider .circle{transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$7.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "ngmodule", type: ImageModule }, { kind: "component", type: i3$1.Image, selector: "p-image", inputs: ["imageClass", "imageStyle", "styleClass", "src", "srcSet", "sizes", "previewImageSrc", "previewImageSrcSet", "previewImageSizes", "alt", "width", "height", "loading", "preview", "showTransitionOptions", "hideTransitionOptions", "modalEnterAnimation", "modalLeaveAnimation", "appendTo", "maskMotionOptions", "motionOptions"], outputs: ["onShow", "onHide", "onImageError"] }, { kind: "ngmodule", type: MenubarModule }, { kind: "component", type: i4.Menubar, selector: "p-menubar", inputs: ["model", "styleClass", "autoZIndex", "baseZIndex", "autoDisplay", "autoHide", "breakpoint", "autoHideDelay", "id", "ariaLabel", "ariaLabelledBy"], outputs: ["onFocus", "onBlur"] }, { kind: "component", type: NetworkStatusComponent, selector: "app-network-status" }] });
7208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: NavbarDsxComponent, isStandalone: true, selector: "app-navbar-dsx", inputs: { appVersion: { classPropertyName: "appVersion", publicName: "appVersion", isSignal: true, isRequired: false, transformFunction: null }, logoWidth: { classPropertyName: "logoWidth", publicName: "logoWidth", isSignal: true, isRequired: false, transformFunction: null }, urlLogo: { classPropertyName: "urlLogo", publicName: "urlLogo", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<p-menubar>\r\n <ng-template #start>\r\n <p-image\r\n class=\"ms-15\"\r\n [src]=\"urlLogo()\"\r\n alt=\"Image\"\r\n [width]=\"logoWidth()\"\r\n />\r\n <span class=\"version-text\">{{ appVersion() }}</span>\r\n </ng-template>\r\n <ng-template #end>\r\n <div>\r\n <!-- Datos del usuario -->\r\n <div class=\"navbar-user-info\">\r\n <icon-dsx name=\"verified_user\" class=\"navbar-user-icon\"></icon-dsx>\r\n <div class=\"navbar-user-text\">\r\n <span class=\"navbar-user-name\">\r\n {{ _authorizeService.getTokenValues.userName }}\r\n </span>\r\n <span class=\"navbar-user-role\">\r\n {{ currentRole }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Componente de estado de red -->\r\n <app-network-status></app-network-status>\r\n\r\n <!-- Actualizaci\u00F3n de permisos -->\r\n <p-button\r\n size=\"small\"\r\n class=\"ml-2 mr-2\"\r\n label=\"Permisos\"\r\n variant=\"text\"\r\n severity=\"secondary\"\r\n (click)=\"actualizarSeguridadIT()\"\r\n >\r\n <span class=\"material-symbols-outlined mr-1\">local_police</span>\r\n </p-button>\r\n\r\n <label class=\"ui-switch\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"checked\"\r\n (click)=\"onThemeChange(!checked ? true : false)\"\r\n />\r\n <div class=\"slider\">\r\n <div class=\"circle\"></div>\r\n </div>\r\n </label>\r\n <!-- <p-inputSwitch\r\n [(ngModel)]=\"checked\"\r\n (onChange)=\"onThemeChange($event.checked)\"\r\n ></p-inputSwitch> -->\r\n </div>\r\n </ng-template>\r\n</p-menubar>\r\n", styles: [":host ::ng-deep .p-menubar{display:flex;align-items:center!important;padding:.25rem 1.5rem!important;border-radius:999px;border:1px solid rgba(255,255,255,.25);background:#ffffff73!important;backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 10px 30px #0f172a14;margin-left:4rem;margin-right:2.5rem}:host ::ng-deep .p-menubar-end>*{display:flex;align-items:center}.version-text{font-size:1.3rem;font-family:Montserrat,sans-serif!important;margin-left:.5rem;font-weight:600;background-image:linear-gradient(to right,#38bdf8,#630cb4);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 2px 4px rgba(0,0,0,.1);padding:.2rem 0}.navbar-user-info{display:flex;align-items:center;gap:.35rem;padding:0 .75rem;border-radius:999px;background-color:#00000005}.navbar-user-icon{font-size:1.5rem;color:#374151}.navbar-user-name{font-size:.8rem;font-weight:500;color:#374151;white-space:nowrap}.navbar-user-text{display:flex;flex-direction:column;line-height:1.1}.navbar-user-role{font-size:.7rem;color:#6b7280;white-space:nowrap}.ui-switch{--switch-bg: rgb(135, 150, 165);--switch-width: 48px;--switch-height: 20px;--circle-diameter: 32px;--circle-bg: rgb(232, 89, 15);--circle-inset: calc((var(--circle-diameter) - var(--switch-height)) / 2)}.ui-switch input{display:none}.slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--switch-width);height:var(--switch-height);background:var(--switch-bg);border-radius:999px;position:relative;cursor:pointer}.slider .circle{top:calc(var(--circle-inset) * -1);left:0;width:var(--circle-diameter);height:var(--circle-diameter);position:absolute;background:var(--circle-bg);border-radius:inherit;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTkuMzA1IDEuNjY3VjMuNzVoMS4zODlWMS42NjdoLTEuMzl6bS00LjcwNyAxLjk1bC0uOTgyLjk4Mkw1LjA5IDYuMDcybC45ODItLjk4Mi0xLjQ3My0xLjQ3M3ptMTAuODAyIDBMMTMuOTI3IDUuMDlsLjk4Mi45ODIgMS40NzMtMS40NzMtLjk4Mi0uOTgyek0xMCA1LjEzOWE0Ljg3MiA0Ljg3MiAwIDAwLTQuODYyIDQuODZBNC44NzIgNC44NzIgMCAwMDEwIDE0Ljg2MiA0Ljg3MiA0Ljg3MiAwIDAwMTQuODYgMTAgNC44NzIgNC44NzIgMCAwMDEwIDUuMTM5em0wIDEuMzg5QTMuNDYyIDMuNDYyIDAgMDExMy40NzEgMTBhMy40NjIgMy40NjIgMCAwMS0zLjQ3MyAzLjQ3MkEzLjQ2MiAzLjQ2MiAwIDAxNi41MjcgMTAgMy40NjIgMy40NjIgMCAwMTEwIDYuNTI4ek0xLjY2NSA5LjMwNXYxLjM5aDIuMDgzdi0xLjM5SDEuNjY2em0xNC41ODMgMHYxLjM5aDIuMDg0di0xLjM5aC0yLjA4NHpNNS4wOSAxMy45MjhMMy42MTYgMTUuNGwuOTgyLjk4MiAxLjQ3My0xLjQ3My0uOTgyLS45ODJ6bTkuODIgMGwtLjk4Mi45ODIgMS40NzMgMS40NzMuOTgyLS45ODItMS40NzMtMS40NzN6TTkuMzA1IDE2LjI1djIuMDgzaDEuMzg5VjE2LjI1aC0xLjM5eiIgLz4KPC9zdmc+);background-repeat:no-repeat;background-position:center center;transition:left .15s cubic-bezier(.4,0,.2,1) 0ms;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 1px -1px #0003,0 1px 1px #00000024,0 1px 3px #0000001f}.slider .circle:before{content:\"\";position:absolute;width:100%;height:100%;background:#ffffffbf;border-radius:inherit;transition:all .5s;opacity:0}.ui-switch input:checked+.slider .circle{left:calc(100% - var(--circle-diameter));background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTQuMiAyLjVsLS43IDEuOC0xLjguNyAxLjguNy43IDEuOC42LTEuOEw2LjcgNWwtMS45LS43LS42LTEuOHptMTUgOC4zYTYuNyA2LjcgMCAxMS02LjYtNi42IDUuOCA1LjggMCAwMDYuNiA2LjZ6IiAvPgo8L3N2Zz4=);background-color:#003892}.ui-switch input:active+.slider .circle:before{transition:0s;opacity:1;width:0;height:0}.navbar-user-info,.ui-switch .slider,.version-text{cursor:pointer}.navbar-user-info:active{transform:scale(.98);transition:transform .05s ease}.ui-switch:active .slider .circle{transform:scale(.95);transition:transform .05s ease}[data-title]{position:relative}[data-title]:hover:after{content:attr(data-title);position:absolute;bottom:125%;left:50%;transform:translate(-50%);background:#000c;color:#fff;font-size:.7rem;padding:.25rem .5rem;border-radius:.25rem;white-space:nowrap;z-index:1000;pointer-events:none;font-family:sans-serif}.navbar-user-info:focus-visible,.ui-switch .slider:focus-visible{outline:2px solid #38bdf8;outline-offset:2px}@media(prefers-reduced-motion:reduce){.navbar-user-info:active,.ui-switch:active .slider .circle{transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "ngmodule", type: ImageModule }, { kind: "component", type: i3$1.Image, selector: "p-image", inputs: ["imageClass", "imageStyle", "styleClass", "src", "srcSet", "sizes", "previewImageSrc", "previewImageSrcSet", "previewImageSizes", "alt", "width", "height", "loading", "preview", "showTransitionOptions", "hideTransitionOptions", "modalEnterAnimation", "modalLeaveAnimation", "appendTo", "maskMotionOptions", "motionOptions"], outputs: ["onShow", "onHide", "onImageError"] }, { kind: "ngmodule", type: MenubarModule }, { kind: "component", type: i4$1.Menubar, selector: "p-menubar", inputs: ["model", "styleClass", "autoZIndex", "baseZIndex", "autoDisplay", "autoHide", "breakpoint", "autoHideDelay", "id", "ariaLabel", "ariaLabelledBy"], outputs: ["onFocus", "onBlur"] }, { kind: "component", type: NetworkStatusComponent, selector: "app-network-status" }] });
6647
7209
  }
6648
7210
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NavbarDsxComponent, decorators: [{
6649
7211
  type: Component,
@@ -7023,7 +7585,7 @@ class TokenPurposeLogin {
7023
7585
  }
7024
7586
  }
7025
7587
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TokenPurposeLogin, deps: [], target: i0.ɵɵFactoryTarget.Component });
7026
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TokenPurposeLogin, isStandalone: true, selector: "app-token-purpose-login", ngImport: i0, template: "<div class=\"flex\">\r\n <p-button\r\n (click)=\"showDialog()\"\r\n label=\"Generar Token\"\r\n pTooltip=\"Ingrese sus credenciales para generar un token de acceso.\"\r\n tooltipPosition=\"top\"\r\n severity=\"secondary\"\r\n icon=\"pi pi-lock\"\r\n [rounded]=\"true\"\r\n [raised]=\"true\"\r\n />\r\n</div>\r\n<form [formGroup]=\"form\">\r\n <p-dialog [(visible)]=\"visible\" [modal]=\"true\" [style]=\"{ width: '30rem' }\">\r\n <ng-template #header>\r\n <div class=\"flex items-center gap-2 px-2\">\r\n <p-avatar image=\"icon/folder.png\" size=\"large\" />\r\n <h5>Token de Seguridad</h5>\r\n </div>\r\n </ng-template>\r\n <span class=\"text-surface-500 dark:text-surface-400 block\"\r\n >Ingrese sus credenciales para generar un token de acceso.</span\r\n >\r\n <div class=\"mt-3\">\r\n <p-floatLabel variant=\"in\">\r\n <p-password\r\n formControlName=\"password\"\r\n [invalid]=\"form.get('password')?.invalid && (form.get('password')?.dirty || form.get('password')?.touched)\"\r\n [feedback]=\"false\"\r\n [toggleMask]=\"true\"\r\n fluid\r\n />\r\n <label>Contrase\u00F1a</label>\r\n </p-floatLabel>\r\n @if (form.get('password')?.invalid && (form.get('password')?.dirty ||\r\n form.get('password')?.touched)) {\r\n <small class=\"text-red-500\">La contrase\u00F1a es obligatoria.</small>\r\n }\r\n </div>\r\n <ng-template #footer>\r\n <p-button\r\n label=\"Cancelar\"\r\n variant=\"outlined\"\r\n [rounded]=\"true\"\r\n icon=\"pi pi-times\"\r\n severity=\"danger\"\r\n (click)=\"visible = false\"\r\n />\r\n <p-button\r\n label=\"Generar\"\r\n variant=\"outlined\"\r\n [rounded]=\"true\"\r\n icon=\"pi pi-unlock\"\r\n severity=\"success\"\r\n [disabled]=\"!form.valid\"\r\n (click)=\"generarTokenPurpose()\"\r\n />\r\n </ng-template>\r\n </p-dialog>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$7.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i6.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i7.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }] });
7588
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TokenPurposeLogin, isStandalone: true, selector: "app-token-purpose-login", ngImport: i0, template: "<div class=\"flex\">\r\n <p-button\r\n (click)=\"showDialog()\"\r\n label=\"Generar Token\"\r\n pTooltip=\"Ingrese sus credenciales para generar un token de acceso.\"\r\n tooltipPosition=\"top\"\r\n severity=\"secondary\"\r\n icon=\"pi pi-lock\"\r\n [rounded]=\"true\"\r\n [raised]=\"true\"\r\n />\r\n</div>\r\n<form [formGroup]=\"form\">\r\n <p-dialog [(visible)]=\"visible\" [modal]=\"true\" [style]=\"{ width: '30rem' }\">\r\n <ng-template #header>\r\n <div class=\"flex items-center gap-2 px-2\">\r\n <p-avatar image=\"icon/folder.png\" size=\"large\" />\r\n <h5>Token de Seguridad</h5>\r\n </div>\r\n </ng-template>\r\n <span class=\"text-surface-500 dark:text-surface-400 block\"\r\n >Ingrese sus credenciales para generar un token de acceso.</span\r\n >\r\n <div class=\"mt-3\">\r\n <p-floatLabel variant=\"in\">\r\n <p-password\r\n formControlName=\"password\"\r\n [invalid]=\"form.get('password')?.invalid && (form.get('password')?.dirty || form.get('password')?.touched)\"\r\n [feedback]=\"false\"\r\n [toggleMask]=\"true\"\r\n fluid\r\n />\r\n <label>Contrase\u00F1a</label>\r\n </p-floatLabel>\r\n @if (form.get('password')?.invalid && (form.get('password')?.dirty ||\r\n form.get('password')?.touched)) {\r\n <small class=\"text-red-500\">La contrase\u00F1a es obligatoria.</small>\r\n }\r\n </div>\r\n <ng-template #footer>\r\n <p-button\r\n label=\"Cancelar\"\r\n variant=\"outlined\"\r\n [rounded]=\"true\"\r\n icon=\"pi pi-times\"\r\n severity=\"danger\"\r\n (click)=\"visible = false\"\r\n />\r\n <p-button\r\n label=\"Generar\"\r\n variant=\"outlined\"\r\n [rounded]=\"true\"\r\n icon=\"pi pi-unlock\"\r\n severity=\"success\"\r\n [disabled]=\"!form.valid\"\r\n (click)=\"generarTokenPurpose()\"\r\n />\r\n </ng-template>\r\n </p-dialog>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i6.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i7.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }] });
7027
7589
  }
7028
7590
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TokenPurposeLogin, decorators: [{
7029
7591
  type: Component,
@@ -8419,6 +8981,7 @@ const PRIME_NG_MODULES = [
8419
8981
  ButtonModule,
8420
8982
  CardModule,
8421
8983
  CheckboxModule,
8984
+ ChipModule,
8422
8985
  ContextMenuModule,
8423
8986
  DataViewModule,
8424
8987
  DatePickerModule,
@@ -8478,6 +9041,7 @@ class PrimeNgModule {
8478
9041
  ButtonModule,
8479
9042
  CardModule,
8480
9043
  CheckboxModule,
9044
+ ChipModule,
8481
9045
  ContextMenuModule,
8482
9046
  DataViewModule,
8483
9047
  DatePickerModule,
@@ -8534,6 +9098,7 @@ class PrimeNgModule {
8534
9098
  ButtonModule,
8535
9099
  CardModule,
8536
9100
  CheckboxModule,
9101
+ ChipModule,
8537
9102
  ContextMenuModule,
8538
9103
  DataViewModule,
8539
9104
  DatePickerModule,
@@ -8992,7 +9557,7 @@ class DsxdateShort {
8992
9557
  useExisting: forwardRef(() => DsxdateShort),
8993
9558
  multi: true,
8994
9559
  },
8995
- ], ngImport: i0, template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: InputMaskModule }, { kind: "directive", type: i1$8.InputMaskDirective, selector: "[pInputMask]", inputs: ["pInputMaskPT", "pInputMaskUnstyled", "pInputMask", "slotChar", "autoClear", "characterPattern", "keepBuffer"], outputs: ["onComplete", "onUnmaskedChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
9560
+ ], ngImport: i0, template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n size=\"small\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<dsx-message-help [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: InputMaskModule }, { kind: "directive", type: i1$7.InputMaskDirective, selector: "[pInputMask]", inputs: ["pInputMaskPT", "pInputMaskUnstyled", "pInputMask", "slotChar", "autoClear", "characterPattern", "keepBuffer"], outputs: ["onComplete", "onUnmaskedChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: AppMessageHelpComponent, selector: "dsx-message-help", inputs: ["control", "currentIdControl", "helperFunction", "dataSource", "key", "umbral", "debugMode", "idFieldName", "maxSugerencias"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
8996
9561
  }
8997
9562
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxdateShort, decorators: [{
8998
9563
  type: Component,
@@ -9004,13 +9569,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
9004
9569
  InputMaskModule,
9005
9570
  JsonPipe,
9006
9571
  ReactiveFormsModule,
9572
+ AppMessageHelpComponent,
9007
9573
  ], providers: [
9008
9574
  {
9009
9575
  provide: NG_VALUE_ACCESSOR,
9010
9576
  useExisting: forwardRef(() => DsxdateShort),
9011
9577
  multi: true,
9012
9578
  },
9013
- ], template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n" }]
9579
+ ], template: "<!-- dsxdate-short.html -->\r\n<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n size=\"small\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<dsx-message-help [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n" }]
9014
9580
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], showOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOnFocus", required: false }] }], showButtonBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButtonBar", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
9015
9581
 
9016
9582
  class DsxdateTime {
@@ -9211,7 +9777,7 @@ class DsxdateTime {
9211
9777
  useExisting: forwardRef(() => DsxdateTime),
9212
9778
  multi: true,
9213
9779
  },
9214
- ], ngImport: i0, template: "<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [showTime]=\"showTime()\"\r\n [hourFormat]=\"hourFormat()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999 99:99\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: InputMaskModule }, { kind: "directive", type: i1$8.InputMaskDirective, selector: "[pInputMask]", inputs: ["pInputMaskPT", "pInputMaskUnstyled", "pInputMask", "slotChar", "autoClear", "characterPattern", "keepBuffer"], outputs: ["onComplete", "onUnmaskedChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
9780
+ ], ngImport: i0, template: "<p-floatLabel variant=\"on\">\r\n <p-datepicker\r\n fluid\r\n appendTo=\"body\"\r\n [formControl]=\"fechaControl\"\r\n [fluid]=\"true\"\r\n [showIcon]=\"showIcon()\"\r\n [showOnFocus]=\"showOnFocus()\"\r\n [showButtonBar]=\"showButtonBar()\"\r\n [showTime]=\"showTime()\"\r\n [hourFormat]=\"hourFormat()\"\r\n [dateFormat]=\"dateFormat()\"\r\n [placeholder]=\"placeholder()\"\r\n pInputMask=\"99/99/9999 99:99\"\r\n />\r\n <label>{{ label() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 SIN CONDICI\u00D3N - IGUAL QUE EL ORIGINAL -->\r\n<dsx-message-error [control]=\"fechaControl\" />\r\n\r\n<!-- Debug info -->\r\n@if (debugEnabled() && isDevMode) {\r\n<div\r\n class=\"debug-info\"\r\n style=\"\r\n font-size: 12px;\r\n color: #666;\r\n margin-top: 4px;\r\n border-top: 1px dashed #ccc;\r\n padding-top: 4px;\r\n \"\r\n>\r\n <small>\r\n <strong>Debug:</strong>\r\n Value: {{ fechaControl.value | json }} | Valid: {{ fechaControl.valid }} |\r\n Invalid: {{ fechaControl.invalid }} | Errors: {{ fechaControl.errors | json\r\n }} | Dirty: {{ fechaControl.dirty }} | Touched: {{ fechaControl.touched }} |\r\n Status: {{ fechaControl.status }}\r\n </small>\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: InputMaskModule }, { kind: "directive", type: i1$7.InputMaskDirective, selector: "[pInputMask]", inputs: ["pInputMaskPT", "pInputMaskUnstyled", "pInputMask", "slotChar", "autoClear", "characterPattern", "keepBuffer"], outputs: ["onComplete", "onUnmaskedChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }] });
9215
9781
  }
9216
9782
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxdateTime, decorators: [{
9217
9783
  type: Component,
@@ -10154,7 +10720,7 @@ class DsxSelect {
10154
10720
  virtualScrollItemSize = input(40, ...(ngDevMode ? [{ debugName: "virtualScrollItemSize" }] : /* istanbul ignore next */ []));
10155
10721
  // Iconos
10156
10722
  useIcon = input(true, ...(ngDevMode ? [{ debugName: "useIcon" }] : /* istanbul ignore next */ []));
10157
- itemIcon = input('keyboard_arrow_right', ...(ngDevMode ? [{ debugName: "itemIcon" }] : /* istanbul ignore next */ []));
10723
+ itemIcon = input('check_small', ...(ngDevMode ? [{ debugName: "itemIcon" }] : /* istanbul ignore next */ []));
10158
10724
  selectedIcon = input('done_outline', ...(ngDevMode ? [{ debugName: "selectedIcon" }] : /* istanbul ignore next */ []));
10159
10725
  // Debug solo consola
10160
10726
  debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
@@ -10356,7 +10922,7 @@ class DsxSelect {
10356
10922
  useExisting: forwardRef(() => DsxSelect),
10357
10923
  multi: true,
10358
10924
  },
10359
- ], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }] });
10925
+ ], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n size=\"small\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-1\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-gray-500!\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-1\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }] });
10360
10926
  }
10361
10927
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxSelect, decorators: [{
10362
10928
  type: Component,
@@ -10372,7 +10938,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10372
10938
  useExisting: forwardRef(() => DsxSelect),
10373
10939
  multi: true,
10374
10940
  },
10375
- ], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-cyan-500! mr-1\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-2\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"] }]
10941
+ ], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n size=\"small\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [virtualScroll]=\"virtualScroll()\"\r\n [virtualScrollItemSize]=\"virtualScrollItemSize()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n (onFocus)=\"onFocus()\"\r\n (onHide)=\"onHide()\"\r\n >\r\n <!-- Item template -->\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center gap-1\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\" class=\"text-gray-500!\"></icon-dsx>\r\n } @if (showSecondaryField()) {\r\n <div class=\"flex flex-col\">\r\n <span class=\"font-semibold text-sky-800\">\r\n {{ item[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-xs text-gray-400\">\r\n {{ item[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ item[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Selected item template -->\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center gap-1\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"selectedIcon()\" class=\"text-green-600!\"></icon-dsx>\r\n } @if (showSecondaryField() && selectedOptions) {\r\n <div class=\"flex gap-x-2\">\r\n <span class=\"font-semibold text-sky-700\">\r\n {{ selectedOptions[resolvedOptionLabel()] }}\r\n </span>\r\n <span class=\"text-gray-400\">\r\n {{ selectedOptions[secondaryField()!] }}\r\n </span>\r\n </div>\r\n } @else { {{ selectedOptions?.[resolvedOptionLabel()] }} }\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- Mensaje de error condicional -->\r\n@if (showError() && errorControl()) {\r\n<dsx-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"] }]
10376
10942
  }], ctorParameters: () => [], propDecorators: { dataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataList", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], secondaryField: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryField", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollItemSize", required: false }] }], useIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIcon", required: false }] }], itemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemIcon", required: false }] }], selectedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIcon", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], selectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedValue", required: false }] }, { type: i0.Output, args: ["selectedValueChange"] }] } });
10377
10943
 
10378
10944
  /**
@@ -12540,9 +13106,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
12540
13106
  // form-preview.service.ts
12541
13107
  class FormPreviewService {
12542
13108
  environment;
13109
+ isDev;
12543
13110
  constructor() {
12544
- // Inyectar el token en el constructor
12545
13111
  this.environment = inject(ENVIRONMENT);
13112
+ this.isDev = !this.environment.production;
12546
13113
  }
12547
13114
  /**
12548
13115
  * Construye el HTML para el preview de un objeto
@@ -12553,17 +13120,30 @@ class FormPreviewService {
12553
13120
  *
12554
13121
  * @example
12555
13122
  * ```typescript
13123
+ * // Ejemplo básico
12556
13124
  * const data = {
12557
- * usuario: {
12558
- * nombre: 'Juan Pérez',
12559
- * email: 'juan@email.com'
12560
- * },
13125
+ * empleadoId: 2,
13126
+ * fechaIngreso: '2026-04-07',
12561
13127
  * estado: 1
12562
13128
  * };
12563
13129
  *
13130
+ * const empleados = [
13131
+ * { id: 1, nombreCompleto: 'Juan Pérez' },
13132
+ * { id: 2, nombreCompleto: 'María García' }
13133
+ * ];
13134
+ *
12564
13135
  * const fields = [
12565
- * { key: 'usuario.nombre', label: 'Nombre' },
12566
- * { key: 'usuario.email', label: 'Email' },
13136
+ * {
13137
+ * key: 'empleadoId',
13138
+ * label: 'Empleado',
13139
+ * referenceMap: empleados,
13140
+ * referenceLabel: 'nombreCompleto'
13141
+ * },
13142
+ * {
13143
+ * key: 'fechaIngreso',
13144
+ * label: 'Fecha de Ingreso',
13145
+ * format: 'dateLong' // "07 de abril de 2026"
13146
+ * },
12567
13147
  * {
12568
13148
  * key: 'estado',
12569
13149
  * label: 'Estado',
@@ -12571,30 +13151,33 @@ class FormPreviewService {
12571
13151
  * }
12572
13152
  * ];
12573
13153
  *
12574
- * const html = this.formPreviewService.buildObjectSummaryHtml(data, fields, {
12575
- * title: 'Datos del Usuario',
12576
- * showEmpty: false,
12577
- * compact: true,
12578
- * debug: false
12579
- * });
13154
+ * const html = this.formPreviewService.buildObjectSummaryHtml(
13155
+ * data,
13156
+ * fields,
13157
+ * {
13158
+ * title: 'Datos del Usuario',
13159
+ * showEmpty: false,
13160
+ * compact: true,
13161
+ * debug: true // Solo en desarrollo
13162
+ * }
13163
+ * );
12580
13164
  * ```
12581
13165
  */
12582
13166
  buildObjectSummaryHtml(data, fields, options) {
12583
13167
  const debug = options?.debug ?? false;
12584
- const isDev = !this.environment.production;
12585
- // Solo ejecutar logs si estamos en desarrollo y debug está activado
12586
- if (debug && isDev) {
13168
+ // 🔍 Debug solo en desarrollo
13169
+ if (debug && this.isDev) {
12587
13170
  this.debugInputData(data, fields, options);
12588
13171
  }
12589
- // Logs de error siempre se muestran en desarrollo si debug está activado
13172
+ // Validaciones
12590
13173
  if (!data) {
12591
- if (debug && isDev) {
13174
+ if (debug && this.isDev) {
12592
13175
  console.error('❌ FormPreview: data es null o undefined');
12593
13176
  }
12594
13177
  return '';
12595
13178
  }
12596
13179
  if (!fields || fields.length === 0) {
12597
- if (debug && isDev) {
13180
+ if (debug && this.isDev) {
12598
13181
  console.error('❌ FormPreview: fields está vacío');
12599
13182
  }
12600
13183
  return '';
@@ -12610,11 +13193,13 @@ class FormPreviewService {
12610
13193
  if (field.referenceMap && value !== undefined && value !== null) {
12611
13194
  const originalValue = value;
12612
13195
  value = this.resolveReferenceValue(value, field);
12613
- // Logs de depuración solo en desarrollo
12614
- if (debug && isDev) {
13196
+ // 🔍 Debug solo en desarrollo
13197
+ if (debug && this.isDev) {
12615
13198
  console.log(`🔍 Resolviendo referencia para "${field.key}":`, {
12616
13199
  original: originalValue,
12617
13200
  resuelto: value,
13201
+ referenciaId: field.referenceId || field.key || 'id',
13202
+ referenciaLabel: field.referenceLabel || 'nombre',
12618
13203
  tipoMapa: Array.isArray(field.referenceMap)
12619
13204
  ? 'Array'
12620
13205
  : field.referenceMap instanceof Map
@@ -12625,9 +13210,10 @@ class FormPreviewService {
12625
13210
  });
12626
13211
  }
12627
13212
  }
13213
+ // Aplicar formato
12628
13214
  const valueText = field.format
12629
- ? field.format(value)
12630
- : this.formatValue(value);
13215
+ ? this.formatValue(value, field.format)
13216
+ : this.formatDefault(value);
12631
13217
  if (value === undefined) {
12632
13218
  propiedadesNoEncontradas.push(field.key);
12633
13219
  }
@@ -12638,8 +13224,8 @@ class FormPreviewService {
12638
13224
  value: valueText || '—',
12639
13225
  });
12640
13226
  }
12641
- // Logs de depuración solo en desarrollo
12642
- if (debug && isDev) {
13227
+ // 🔍 Debug solo en desarrollo
13228
+ if (debug && this.isDev) {
12643
13229
  if (propiedadesNoEncontradas.length > 0) {
12644
13230
  console.warn('⚠️ FormPreview: Propiedades no encontradas:', propiedadesNoEncontradas);
12645
13231
  console.warn('📋 Propiedades disponibles en data:', Object.keys(data));
@@ -12651,19 +13237,29 @@ class FormPreviewService {
12651
13237
  console.log('📋 Fields:', fields);
12652
13238
  }
12653
13239
  else {
12654
- console.log('✅ FormPreview: HTML generado correctamente', { cells });
13240
+ console.log('✅ FormPreview: HTML generado correctamente', {
13241
+ totalCeldas: cells.length,
13242
+ campos: cells.map((c) => c.label),
13243
+ });
12655
13244
  }
12656
13245
  }
12657
13246
  if (!cells.length)
12658
13247
  return '';
12659
13248
  return this.generateHtml(title, cells, compact);
12660
13249
  }
13250
+ /**
13251
+ * Resuelve el valor de referencia
13252
+ * Soporta: arrays, maps, objetos literales y funciones
13253
+ */
12661
13254
  resolveReferenceValue(value, field) {
12662
13255
  if (Array.isArray(value)) {
12663
13256
  return value.map((item) => this.resolveSingleReference(item, field));
12664
13257
  }
12665
13258
  return this.resolveSingleReference(value, field);
12666
13259
  }
13260
+ /**
13261
+ * Resuelve un valor individual de referencia
13262
+ */
12667
13263
  resolveSingleReference(value, field) {
12668
13264
  if (!value)
12669
13265
  return value;
@@ -12680,8 +13276,31 @@ class FormPreviewService {
12680
13276
  referencedItem = map.get(value);
12681
13277
  }
12682
13278
  else if (Array.isArray(map)) {
12683
- const idKey = field.referenceId || 'id';
12684
- referencedItem = map.find((item) => item[idKey] === value);
13279
+ // Si no se especifica referenceId, usar el key del campo
13280
+ const idKey = field.referenceId || field.key || 'id';
13281
+ const labelKey = field.referenceLabel || 'nombre';
13282
+ const found = map.find((item) => {
13283
+ if (item[idKey] !== undefined) {
13284
+ return item[idKey] === value;
13285
+ }
13286
+ if (item.id !== undefined) {
13287
+ return item.id === value;
13288
+ }
13289
+ return false;
13290
+ });
13291
+ if (found) {
13292
+ if (found[labelKey] !== undefined && found[labelKey] !== null) {
13293
+ return found[labelKey];
13294
+ }
13295
+ // Fallback: buscar otras propiedades comunes
13296
+ for (const prop of ['label', 'nombre', 'name', 'text', 'value']) {
13297
+ if (found[prop] !== undefined && found[prop] !== null) {
13298
+ return found[prop];
13299
+ }
13300
+ }
13301
+ return found;
13302
+ }
13303
+ return value;
12685
13304
  }
12686
13305
  else if (typeof map === 'object') {
12687
13306
  referencedItem = map[String(value)];
@@ -12693,12 +13312,23 @@ class FormPreviewService {
12693
13312
  referencedItem[labelProp] !== null) {
12694
13313
  return referencedItem[labelProp];
12695
13314
  }
13315
+ for (const prop of ['label', 'nombre', 'name', 'text', 'value']) {
13316
+ if (referencedItem[prop] !== undefined &&
13317
+ referencedItem[prop] !== null) {
13318
+ return referencedItem[prop];
13319
+ }
13320
+ }
12696
13321
  return referencedItem;
12697
13322
  }
12698
13323
  return referencedItem;
12699
13324
  }
12700
13325
  return value;
12701
13326
  }
13327
+ /**
13328
+ * Obtiene un valor anidado usando notación punto
13329
+ * @example
13330
+ * getNestedValue({ user: { name: 'Juan' } }, 'user.name') // 'Juan'
13331
+ */
12702
13332
  getNestedValue(obj, path) {
12703
13333
  if (!obj || !path)
12704
13334
  return undefined;
@@ -12711,7 +13341,29 @@ class FormPreviewService {
12711
13341
  }
12712
13342
  return result;
12713
13343
  }
12714
- formatValue(value) {
13344
+ /**
13345
+ * Formatea un valor usando el formato especificado
13346
+ * @param value - Valor a formatear
13347
+ * @param format - Formato a aplicar (string predefinido o función personalizada)
13348
+ * @returns String formateado
13349
+ */
13350
+ formatValue(value, format) {
13351
+ if (value === null || value === undefined)
13352
+ return '';
13353
+ // Si es función personalizada, ejecutarla
13354
+ if (typeof format === 'function') {
13355
+ return format(value);
13356
+ }
13357
+ // Si es string, verificar si es un formato de fecha
13358
+ if (typeof format === 'string') {
13359
+ return this.formatDate(value, format);
13360
+ }
13361
+ return this.formatDefault(value);
13362
+ }
13363
+ /**
13364
+ * Formato por defecto para cualquier valor
13365
+ */
13366
+ formatDefault(value) {
12715
13367
  if (value === null || value === undefined)
12716
13368
  return '';
12717
13369
  if (value instanceof Date)
@@ -12727,6 +13379,68 @@ class FormPreviewService {
12727
13379
  }
12728
13380
  return String(value);
12729
13381
  }
13382
+ /**
13383
+ * 🗓️ FORMATOS DE FECHA DISPONIBLES
13384
+ *
13385
+ * Para agregar un nuevo formato:
13386
+ * 1. Agrega el tipo en DateFormat
13387
+ * 2. Agrega el case en el switch del método formatDate
13388
+ * 3. Define las opciones de Intl.DateTimeFormatOptions
13389
+ *
13390
+ * @example
13391
+ * // Agregar 'dateShort' para mostrar "07-abr-2026"
13392
+ * // 1. type DateFormat = 'date' | 'dateLong' | 'dateTime' | 'dateShort'
13393
+ * // 2. case 'dateShort':
13394
+ * // options.day = '2-digit';
13395
+ * // options.month = 'short';
13396
+ * // options.year = 'numeric';
13397
+ * // break;
13398
+ */
13399
+ formatDate(value, format) {
13400
+ if (!value)
13401
+ return '';
13402
+ const date = value instanceof Date ? value : new Date(value);
13403
+ if (isNaN(date.getTime())) {
13404
+ // Si no es una fecha válida, devolver el valor original
13405
+ return String(value);
13406
+ }
13407
+ const options = {};
13408
+ switch (format) {
13409
+ case 'date':
13410
+ // "07/04/2026"
13411
+ options.day = '2-digit';
13412
+ options.month = '2-digit';
13413
+ options.year = 'numeric';
13414
+ break;
13415
+ case 'dateLong':
13416
+ // "martes 07 de abril de 2026"
13417
+ options.weekday = 'long';
13418
+ options.day = '2-digit';
13419
+ options.month = 'long';
13420
+ options.year = 'numeric';
13421
+ break;
13422
+ case 'dateTime':
13423
+ // "07/04/2026 14:30"
13424
+ options.day = '2-digit';
13425
+ options.month = '2-digit';
13426
+ options.year = 'numeric';
13427
+ options.hour = '2-digit';
13428
+ options.minute = '2-digit';
13429
+ break;
13430
+ default:
13431
+ return this.formatDefault(value);
13432
+ }
13433
+ try {
13434
+ return date.toLocaleDateString('es-ES', options);
13435
+ }
13436
+ catch (error) {
13437
+ // Si hay error al formatear, devolver el valor original
13438
+ return String(value);
13439
+ }
13440
+ }
13441
+ /**
13442
+ * Formatea un valor individual (para objetos y arrays)
13443
+ */
12730
13444
  formatSingleValue(value) {
12731
13445
  if (!value || typeof value !== 'object')
12732
13446
  return String(value);
@@ -12758,6 +13472,9 @@ class FormPreviewService {
12758
13472
  return '[Objeto]';
12759
13473
  }
12760
13474
  }
13475
+ /**
13476
+ * Genera el HTML del preview
13477
+ */
12761
13478
  generateHtml(title, cells, compact) {
12762
13479
  if (compact) {
12763
13480
  return `
@@ -12808,15 +13525,20 @@ class FormPreviewService {
12808
13525
  </div>
12809
13526
  `;
12810
13527
  }
13528
+ /**
13529
+ * 🔍 Debug: Muestra información detallada para depuración
13530
+ * ⚠️ SOLO se ejecuta en entorno de desarrollo
13531
+ */
12811
13532
  debugInputData(data, fields, options) {
12812
- const isDev = !this.environment.production;
12813
- if (!isDev)
13533
+ // ⚠️ Seguridad: Si es producción, NO ejecutar nada
13534
+ if (!this.isDev)
12814
13535
  return;
12815
13536
  console.group('🔍 FormPreview Debug');
12816
13537
  console.log('📊 Data:', data);
12817
13538
  console.log('📋 Propiedades disponibles:', data ? Object.keys(data) : 'data es null');
12818
13539
  console.log('🎯 Fields solicitados:', fields);
12819
13540
  console.log('⚙️ Options:', options);
13541
+ console.log('🌍 Entorno:', this.environment.production ? 'Producción' : 'Desarrollo');
12820
13542
  if (data) {
12821
13543
  for (const field of fields) {
12822
13544
  const value = this.getNestedValue(data, field.key);
@@ -12830,11 +13552,18 @@ class FormPreviewService {
12830
13552
  }
12831
13553
  else {
12832
13554
  console.log(`✅ Campo "${field.key}" existe:`, value);
13555
+ // Mostrar información del formato si existe
13556
+ if (field.format) {
13557
+ console.log(` 📝 Formato: ${typeof field.format === 'function' ? 'Función personalizada' : field.format}`);
13558
+ }
12833
13559
  }
12834
13560
  }
12835
13561
  }
12836
13562
  console.groupEnd();
12837
13563
  }
13564
+ /**
13565
+ * Encuentra propiedades similares para sugerencias en debug
13566
+ */
12838
13567
  findSimilarProperties(search, properties) {
12839
13568
  const searchLower = search.toLowerCase();
12840
13569
  return properties
@@ -12844,6 +13573,9 @@ class FormPreviewService {
12844
13573
  })
12845
13574
  .slice(0, 3);
12846
13575
  }
13576
+ /**
13577
+ * Escapa caracteres HTML para evitar inyección
13578
+ */
12847
13579
  escapeHtml(str) {
12848
13580
  if (!str)
12849
13581
  return '';
@@ -13150,6 +13882,147 @@ function createCurrencyFormatter(locale, currency) {
13150
13882
  });
13151
13883
  }
13152
13884
 
13885
+ /**
13886
+ * Guarda un valor en localStorage
13887
+ * Soporta: strings, números, objetos, arrays, null, undefined
13888
+ */
13889
+ function setStorage(key, value) {
13890
+ try {
13891
+ // 🔧 Manejar null y undefined explícitamente
13892
+ if (value === null) {
13893
+ localStorage.setItem(key, 'null');
13894
+ }
13895
+ else if (value === undefined) {
13896
+ localStorage.setItem(key, 'undefined');
13897
+ }
13898
+ else {
13899
+ localStorage.setItem(key, JSON.stringify(value));
13900
+ }
13901
+ }
13902
+ catch (error) {
13903
+ console.error(`Error guardando en localStorage (${key})`, error);
13904
+ }
13905
+ }
13906
+ /**
13907
+ * Obtiene un valor desde localStorage
13908
+ * @param defaultValue - Valor por defecto si no existe la clave
13909
+ * @returns El valor guardado o el defaultValue
13910
+ */
13911
+ function getStorage(key, defaultValue) {
13912
+ try {
13913
+ const data = localStorage.getItem(key);
13914
+ // Si no existe la clave en el storage
13915
+ if (data === null) {
13916
+ return defaultValue;
13917
+ }
13918
+ // 🔧 Manejar valores especiales
13919
+ if (data === 'null') {
13920
+ return null; // Retorna null explícitamente
13921
+ }
13922
+ if (data === 'undefined') {
13923
+ return undefined;
13924
+ }
13925
+ // Intentar parsear como JSON
13926
+ try {
13927
+ return JSON.parse(data);
13928
+ }
13929
+ catch {
13930
+ // Si no es JSON válido, devolver como string
13931
+ return data;
13932
+ }
13933
+ }
13934
+ catch (error) {
13935
+ console.error(`Error recuperando de localStorage (${key})`, error);
13936
+ return defaultValue;
13937
+ }
13938
+ }
13939
+ // Función específica para objetos con merge
13940
+ function setStorageObject(key, values = {}, merge = true) {
13941
+ try {
13942
+ if (merge) {
13943
+ const current = getStorage(key, {});
13944
+ localStorage.setItem(key, JSON.stringify({ ...current, ...values }));
13945
+ }
13946
+ else {
13947
+ localStorage.setItem(key, JSON.stringify(values));
13948
+ }
13949
+ }
13950
+ catch (error) {
13951
+ console.error(`Error guardando en localStorage (${key})`, error);
13952
+ }
13953
+ }
13954
+ /**
13955
+ * 🆕 Función para eliminar una clave del storage
13956
+ */
13957
+ function removeStorage(key) {
13958
+ try {
13959
+ localStorage.removeItem(key);
13960
+ }
13961
+ catch (error) {
13962
+ console.error(`Error eliminando de localStorage (${key})`, error);
13963
+ }
13964
+ }
13965
+ /**
13966
+ * 🆕 Función para verificar si existe una clave en el storage
13967
+ */
13968
+ function hasStorage(key) {
13969
+ try {
13970
+ return localStorage.getItem(key) !== null;
13971
+ }
13972
+ catch (error) {
13973
+ console.error(`Error verificando en localStorage (${key})`, error);
13974
+ return false;
13975
+ }
13976
+ }
13977
+
13978
+ /**
13979
+ * Calcula la fecha sumando días hábiles (Lunes a Sábado, Domingos no cuentan)
13980
+ * Los feriados en el rango no consumen días
13981
+ *
13982
+ * @param fechaInicio - Fecha desde donde empezar
13983
+ * @param cantidadDias - Días hábiles a sumar
13984
+ * @param feriados - Lista de feriados (opcional)
13985
+ * @returns Fecha calculada o null si fechaInicio es null
13986
+ *
13987
+ * @example
13988
+ * // Sin feriados
13989
+ * calcularFechaFin(new Date('2026-07-07'), 15) // 2026-07-25
13990
+ *
13991
+ * @example
13992
+ * // Con feriados
13993
+ * calcularFechaFin(
13994
+ * new Date('2026-07-07'),
13995
+ * 15,
13996
+ * [{ date: '2026-07-14' }, { date: '2026-07-21' }]
13997
+ * ) // 2026-07-27
13998
+ */
13999
+ function dsxCalcularRangoFecha(fechaInicio, cantidadDias, feriados) {
14000
+ // Validación básica
14001
+ if (!fechaInicio)
14002
+ return null;
14003
+ if (cantidadDias === 0)
14004
+ return new Date(fechaInicio);
14005
+ // Crear Set de feriados con moment para comparación directa
14006
+ const feriadosSet = new Set(feriados?.map((f) => moment(f.dateHoliday).format('YYYY-MM-DD')));
14007
+ // Usar moment para la fecha
14008
+ const fecha = moment(fechaInicio).startOf('day');
14009
+ let dias = cantidadDias;
14010
+ while (dias > 0) {
14011
+ fecha.add(1, 'day');
14012
+ const diaSemana = fecha.day(); // 0=domingo
14013
+ const fechaStr = fecha.format('YYYY-MM-DD');
14014
+ // Días que NO consumen días (se saltan):
14015
+ // 1. Domingos
14016
+ // 2. Feriados
14017
+ if (diaSemana === 0 || feriadosSet.has(fechaStr)) {
14018
+ continue;
14019
+ }
14020
+ // Sábado = medio día, resto = día completo
14021
+ dias -= diaSemana === 6 ? 0.5 : 1;
14022
+ }
14023
+ return fecha.toDate();
14024
+ }
14025
+
13153
14026
  function chainControlGroups(form, groups) {
13154
14027
  groups.forEach((group) => {
13155
14028
  chainControls(form, group);
@@ -13783,5 +14656,5 @@ function sorensenDiceValidator(dataSource, key, umbral = 0.7) {
13783
14656
  * Generated bundle index. Do not edit.
13784
14657
  */
13785
14658
 
13786
- export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, AppMessageHelpComponent, ArrowNavigationDirective, AuthorizeService, AutoScrollHeightDirective, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxAutocomplete, DsxButtonComponent, DsxEnableDisable, DsxInputCurrency, DsxMessagesService, DsxSelect, DsxStatusToggle, DsxdateShort, DsxdateTime, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, FormPreviewService, GTQFormatter, HeaderDsx, HelpersService, HttpHelpersService, INITIAL_PARAMETERS, IcoLabel, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, QrGenerator, ResultFileService, SWEET_ALERT_THEMES, ScreenInspector, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, SweetAlert2DialogService, TablePreviewService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, getActionMessageConfig, getZeroBasedRolIndex, guardTokenPurposeGuard, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, sorensenDiceValidator, templateStructureValidator, templateVariablesValidator, validateEnvironmentConfig };
14659
+ export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, AppMessageHelpComponent, ArrowNavigationDirective, AuthorizeService, AutoScrollHeightDirective, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxAutocomplete, DsxButtonComponent, DsxCalendarView, DsxEnableDisable, DsxInputCurrency, DsxMessagesService, DsxSelect, DsxStatusToggle, DsxdateShort, DsxdateTime, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, FormPreviewService, GTQFormatter, HeaderDsx, HelpersService, HttpHelpersService, INITIAL_PARAMETERS, IcoLabel, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, QrGenerator, ResultFileService, SWEET_ALERT_THEMES, ScreenInspector, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, SweetAlert2DialogService, TablePreviewService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, dsxCalcularRangoFecha, getActionMessageConfig, getStorage, getZeroBasedRolIndex, guardTokenPurposeGuard, hasStorage, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, removeStorage, setStorage, setStorageObject, sorensenDiceValidator, templateStructureValidator, templateVariablesValidator, validateEnvironmentConfig };
13787
14660
  //# sourceMappingURL=ngx-dsxlibrary.mjs.map