@solcre-org/core-ui 2.17.0 → 2.17.2

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.
@@ -578,6 +578,95 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
578
578
  args: [{ selector: 'core-checkbox-field', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, FieldErrorsComponent], hostDirectives: [CoreHostDirective], template: "<!-- Clase para layout inline cuando hay m\u00FAltiples opciones -->\n<div class=\"c-entry-toggle-holder\" [class.hasSeparatedOptions]=\"hasSeparatedOptions()\" [class.multiple-inline]=\"hasMultipleOptions()\">\n\n <span class=\"c-entry-text\"\n *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredIndicator()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n \n @if (hasMultipleOptions()) {\n @for (option of options(); track option.value) {\n\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"cannotDeselect(option)\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (!allowMultiple() && isRequired()) {\n <!-- Cuando allowMultiple: false y required: true, usar radio buttons para todas las opciones -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else if (cannotDeselect(option)) {\n <!-- Usar radio cuando no se puede deseleccionar (modo m\u00FAltiple con una sola opci\u00F3n) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString() + '_' + option.value\"\n [attr.name]=\"allowMultiple() ? field().key.toString() + '[]' : field().key.toString()\"\n [checked]=\"isOptionSelected(option)\"\n (change)=\"handleOptionChange(option, $event)\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n\n <span class=\"c-entry-toggle__text\">\n {{ option.label | translate }}\n @if(option.externalLink) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"option.externalLink\" target=\"_blank\"></a>\n }\n </span>\n @if(option.detail) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ option.detail }}</span>\n }\n </label>\n\n }\n } @else {\n <!-- ! Solcre: Este .c-entry-toggle deber\u00EDa ser un componente en s\u00ED mismo. -->\n <!-- ! Solcre: El cannot-deselect no est\u00E1 over-engineered. Deber\u00EDa ser un Radio. -->\n <label class=\"c-entry-toggle\"\n [class.is-invalid]=\"hasError()\"\n [class.is-disabled]=\"isDisabled()\"\n [class.cannot-deselect]=\"isRequired() && !!formControl().value\">\n\n <!-- onBlurInput() maneja validaciones y marca el campo como touched para mostrar errores -->\n @if (isRequired() && !!formControl().value) {\n <!-- Usar radio cuando es requerido y tiene valor (cannot-deselect) -->\n <input\n type=\"radio\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [checked]=\"!!formControl().value\"\n (change)=\"onRadioChange($event)\"\n (blur)=\"onBlurInput()\"\n />\n } @else {\n <!-- Usar checkbox normal cuando se puede deseleccionar -->\n <input\n type=\"checkbox\"\n [attr.id]=\"field().key.toString()\"\n [attr.name]=\"field().key.toString()\"\n [formControl]=\"formControl()\"\n (blur)=\"onBlurInput()\"\n />\n }\n <span class=\"c-entry-toggle__toggle\"></span>\n <span class=\"c-entry-toggle__text\">\n {{ field().label | translate }}\n @if (hasRequiredIndicator()) {\n <span class=\"c-required\">*</span>\n }\n @if(externalLink()) {\n <!-- Link externo funcional implementado -->\n <a class=\"icon-external-link-thin\" [href]=\"externalLink()\" target=\"_blank\"></a>\n }\n </span>\n @if(detail()) {\n <!-- Texto de detalle funcional implementado -->\n <span class=\"c-form-checkbox__detail\">{{ detail() }}</span>\n }\n </label>\n }\n\n <core-field-errors [errors]=\"errors()\" />\n</div> \n ", styles: [".cannot-deselect{pointer-events:none;cursor:not-allowed}.c-entry-text+.c-entry-toggle-holder.hasSeparatedOptions{margin-top:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions{display:grid;grid-template-columns:1fr 1fr;gap:calc(var(--_entry-group-gap) * .8)}.c-entry-toggle-holder.hasSeparatedOptions .c-entry-text{grid-column:span 2;margin-top:1em}\n"] }]
579
579
  }], ctorParameters: () => [] });
580
580
 
581
+ const DEFAULT_COLORS = [
582
+ '#4285f4', '#ea4335', '#34a853', '#fbbc04',
583
+ '#9c27b0', '#00bcd4', '#ff5722', '#795548',
584
+ '#607d8b', '#e91e63', '#3f51b5', '#009688',
585
+ '#ff9800', '#673ab7', '#2196f3', '#4caf50'
586
+ ];
587
+ class ColorPickerFieldComponent extends BaseFieldComponent {
588
+ isPickerOpen = signal(false);
589
+ presetColors = signal(DEFAULT_COLORS);
590
+ constructor() {
591
+ super();
592
+ effect(() => {
593
+ const shouldDisable = this.mode() === ModalMode.VIEW || this.evaluateReadonly();
594
+ const control = this.formControl();
595
+ if (shouldDisable && control.enabled) {
596
+ control.disable();
597
+ }
598
+ else if (!shouldDisable && control.disabled) {
599
+ control.enable();
600
+ }
601
+ });
602
+ effect(() => {
603
+ const fieldConfig = this.field();
604
+ if (fieldConfig.presetColors && Array.isArray(fieldConfig.presetColors)) {
605
+ this.presetColors.set(fieldConfig.presetColors);
606
+ }
607
+ });
608
+ }
609
+ isDisabled() {
610
+ return this.mode() === ModalMode.VIEW || this.evaluateReadonly();
611
+ }
612
+ togglePicker() {
613
+ if (!this.isDisabled()) {
614
+ this.isPickerOpen.update(open => !open);
615
+ }
616
+ }
617
+ closePicker() {
618
+ this.isPickerOpen.set(false);
619
+ }
620
+ selectColor(color) {
621
+ if (!this.isDisabled()) {
622
+ this.formControl().setValue(color);
623
+ this.valueChange.emit(color);
624
+ this.closePicker();
625
+ }
626
+ }
627
+ onColorInputChange(event) {
628
+ const input = event.target;
629
+ const color = input.value;
630
+ this.formControl().setValue(color);
631
+ this.valueChange.emit(color);
632
+ }
633
+ onTextInputChange(event) {
634
+ const input = event.target;
635
+ let color = input.value;
636
+ if (color && !color.startsWith('#')) {
637
+ color = '#' + color;
638
+ }
639
+ if (this.isValidHexColor(color)) {
640
+ this.formControl().setValue(color);
641
+ this.valueChange.emit(color);
642
+ }
643
+ }
644
+ isValidHexColor(color) {
645
+ return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);
646
+ }
647
+ getCurrentColor() {
648
+ const value = this.formControl().value;
649
+ return value && this.isValidHexColor(value) ? value : '#4783E1';
650
+ }
651
+ onBlurInput(event) {
652
+ setTimeout(() => {
653
+ if (!this.isPickerOpen()) {
654
+ this.onBlur(event);
655
+ }
656
+ }, 200);
657
+ }
658
+ handleEnterKey(event) {
659
+ const keyboardEvent = event;
660
+ this.onEnterInput(keyboardEvent);
661
+ }
662
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ColorPickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
663
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: ColorPickerFieldComponent, isStandalone: true, selector: "core-color-picker-field", usesInheritance: true, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n <span class=\"c-entry-text\" *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n\n <div class=\"c-entry-input c-entry-input--color\"\n [class.is-readonly]=\"isReadonly()\"\n [class.is-disabled]=\"isDisabled()\">\n <div class=\"c-color-picker\">\n <div class=\"c-color-picker__preview-wrapper\">\n <div \n class=\"c-color-picker__preview\"\n [style.background-color]=\"getCurrentColor()\"\n (click)=\"togglePicker()\"\n [class.c-color-picker__preview--disabled]=\"isDisabled()\">\n </div>\n \n <input\n type=\"text\"\n class=\"c-color-picker__text-input\"\n [id]=\"field().key\"\n [formControl]=\"formControl()\"\n [placeholder]=\"(field().placeholder ?? '#4783E1') | translate\"\n [class.c-color-picker__text-input--disabled]=\"isDisabled()\"\n [class.c-color-picker__text-input--error]=\"hasError()\"\n (input)=\"onTextInputChange($event)\"\n (blur)=\"onBlurInput($event)\"\n (keydown.enter)=\"handleEnterKey($event)\"\n maxlength=\"7\"\n />\n \n <input\n type=\"color\"\n class=\"c-color-picker__native-input\"\n [value]=\"getCurrentColor()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onColorInputChange($event)\"\n />\n </div>\n\n @if (isPickerOpen()) {\n <div class=\"c-color-picker__dropdown\">\n <div class=\"c-color-picker__preset-colors\">\n @for (color of presetColors(); track color) {\n <button\n type=\"button\"\n class=\"c-color-picker__preset-color\"\n [style.background-color]=\"color\"\n [class.c-color-picker__preset-color--selected]=\"getCurrentColor() === color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n\n <core-field-errors [errors]=\"errors()\"></core-field-errors>\n</label>\n", styles: [".c-color-picker{position:relative;width:100%}.c-color-picker__preview-wrapper{display:flex;align-items:center;gap:8px}.c-color-picker__preview{width:36px;height:36px;border-radius:6px;border:2px solid var(--color-border, #e0e0e0);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease;flex-shrink:0}.c-color-picker__preview:hover:not(.c-color-picker__preview--disabled){border-color:var(--color-primary, #4783E1);box-shadow:0 0 0 2px #4783e133}.c-color-picker__preview--disabled{cursor:not-allowed;opacity:.6}.c-color-picker__text-input{flex:1;height:36px;padding:0 12px;font-size:14px;font-family:monospace;text-transform:uppercase;border:1px solid var(--color-border, #e0e0e0);border-radius:6px;background-color:var(--color-background, #fff);transition:border-color .2s ease,box-shadow .2s ease}.c-color-picker__text-input:focus{outline:none;border-color:var(--color-primary, #4783E1);box-shadow:0 0 0 2px #4783e133}.c-color-picker__text-input--disabled{background-color:var(--color-disabled-bg, #f5f5f5);cursor:not-allowed;opacity:.6}.c-color-picker__text-input--error{border-color:var(--color-danger, #dc3545)}.c-color-picker__text-input--error:focus{box-shadow:0 0 0 2px #dc354533}.c-color-picker__native-input{width:36px;height:36px;padding:0;border:none;border-radius:6px;cursor:pointer;flex-shrink:0}.c-color-picker__native-input::-webkit-color-swatch-wrapper{padding:0}.c-color-picker__native-input::-webkit-color-swatch{border:2px solid var(--color-border, #e0e0e0);border-radius:6px}.c-color-picker__native-input:disabled{cursor:not-allowed;opacity:.6}.c-color-picker__dropdown{position:absolute;top:calc(100% + 8px);left:0;z-index:1000;background-color:var(--color-background, #fff);border:1px solid var(--color-border, #e0e0e0);border-radius:8px;box-shadow:0 4px 12px #00000026;padding:12px;min-width:200px}.c-color-picker__preset-colors{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.c-color-picker__preset-color{width:32px;height:32px;border:2px solid transparent;border-radius:6px;cursor:pointer;padding:0;transition:transform .15s ease,border-color .15s ease}.c-color-picker__preset-color:hover{transform:scale(1.1)}.c-color-picker__preset-color--selected{border-color:var(--color-text, #333);box-shadow:0 0 0 2px var(--color-background, #fff),0 0 0 4px var(--color-primary, #4783E1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FieldErrorsComponent, selector: "core-field-errors", inputs: ["errors"] }] });
664
+ }
665
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ColorPickerFieldComponent, decorators: [{
666
+ type: Component,
667
+ args: [{ selector: 'core-color-picker-field', standalone: true, imports: [CommonModule, FormsModule, TranslateModule, ReactiveFormsModule, FieldErrorsComponent], hostDirectives: [CoreHostDirective], template: "<label class=\"c-entry-item\" [class.c-entry-item--inline]=\"field().inline\">\n <span class=\"c-entry-text\" *ngIf=\"field().label\">\n {{ field().label | translate }}\n @if (hasRequiredValidators()) {\n <span class=\"c-required\">*</span>\n }\n </span>\n\n <div class=\"c-entry-input c-entry-input--color\"\n [class.is-readonly]=\"isReadonly()\"\n [class.is-disabled]=\"isDisabled()\">\n <div class=\"c-color-picker\">\n <div class=\"c-color-picker__preview-wrapper\">\n <div \n class=\"c-color-picker__preview\"\n [style.background-color]=\"getCurrentColor()\"\n (click)=\"togglePicker()\"\n [class.c-color-picker__preview--disabled]=\"isDisabled()\">\n </div>\n \n <input\n type=\"text\"\n class=\"c-color-picker__text-input\"\n [id]=\"field().key\"\n [formControl]=\"formControl()\"\n [placeholder]=\"(field().placeholder ?? '#4783E1') | translate\"\n [class.c-color-picker__text-input--disabled]=\"isDisabled()\"\n [class.c-color-picker__text-input--error]=\"hasError()\"\n (input)=\"onTextInputChange($event)\"\n (blur)=\"onBlurInput($event)\"\n (keydown.enter)=\"handleEnterKey($event)\"\n maxlength=\"7\"\n />\n \n <input\n type=\"color\"\n class=\"c-color-picker__native-input\"\n [value]=\"getCurrentColor()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onColorInputChange($event)\"\n />\n </div>\n\n @if (isPickerOpen()) {\n <div class=\"c-color-picker__dropdown\">\n <div class=\"c-color-picker__preset-colors\">\n @for (color of presetColors(); track color) {\n <button\n type=\"button\"\n class=\"c-color-picker__preset-color\"\n [style.background-color]=\"color\"\n [class.c-color-picker__preset-color--selected]=\"getCurrentColor() === color\"\n (click)=\"selectColor(color)\"\n [title]=\"color\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n\n <core-field-errors [errors]=\"errors()\"></core-field-errors>\n</label>\n", styles: [".c-color-picker{position:relative;width:100%}.c-color-picker__preview-wrapper{display:flex;align-items:center;gap:8px}.c-color-picker__preview{width:36px;height:36px;border-radius:6px;border:2px solid var(--color-border, #e0e0e0);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease;flex-shrink:0}.c-color-picker__preview:hover:not(.c-color-picker__preview--disabled){border-color:var(--color-primary, #4783E1);box-shadow:0 0 0 2px #4783e133}.c-color-picker__preview--disabled{cursor:not-allowed;opacity:.6}.c-color-picker__text-input{flex:1;height:36px;padding:0 12px;font-size:14px;font-family:monospace;text-transform:uppercase;border:1px solid var(--color-border, #e0e0e0);border-radius:6px;background-color:var(--color-background, #fff);transition:border-color .2s ease,box-shadow .2s ease}.c-color-picker__text-input:focus{outline:none;border-color:var(--color-primary, #4783E1);box-shadow:0 0 0 2px #4783e133}.c-color-picker__text-input--disabled{background-color:var(--color-disabled-bg, #f5f5f5);cursor:not-allowed;opacity:.6}.c-color-picker__text-input--error{border-color:var(--color-danger, #dc3545)}.c-color-picker__text-input--error:focus{box-shadow:0 0 0 2px #dc354533}.c-color-picker__native-input{width:36px;height:36px;padding:0;border:none;border-radius:6px;cursor:pointer;flex-shrink:0}.c-color-picker__native-input::-webkit-color-swatch-wrapper{padding:0}.c-color-picker__native-input::-webkit-color-swatch{border:2px solid var(--color-border, #e0e0e0);border-radius:6px}.c-color-picker__native-input:disabled{cursor:not-allowed;opacity:.6}.c-color-picker__dropdown{position:absolute;top:calc(100% + 8px);left:0;z-index:1000;background-color:var(--color-background, #fff);border:1px solid var(--color-border, #e0e0e0);border-radius:8px;box-shadow:0 4px 12px #00000026;padding:12px;min-width:200px}.c-color-picker__preset-colors{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.c-color-picker__preset-color{width:32px;height:32px;border:2px solid transparent;border-radius:6px;cursor:pointer;padding:0;transition:transform .15s ease,border-color .15s ease}.c-color-picker__preset-color:hover{transform:scale(1.1)}.c-color-picker__preset-color--selected{border-color:var(--color-text, #333);box-shadow:0 0 0 2px var(--color-background, #fff),0 0 0 4px var(--color-primary, #4783E1)}\n"] }]
668
+ }], ctorParameters: () => [] });
669
+
581
670
  class DateFieldComponent extends BaseFieldComponent {
582
671
  elementRef;
583
672
  isPickerOpen = false;
@@ -2409,6 +2498,7 @@ var FieldType;
2409
2498
  FieldType["FILE"] = "file";
2410
2499
  FieldType["PHONE"] = "phone";
2411
2500
  FieldType["DOCUMENT"] = "document";
2501
+ FieldType["COLOR"] = "color";
2412
2502
  })(FieldType || (FieldType = {}));
2413
2503
  var NumberFieldType;
2414
2504
  (function (NumberFieldType) {
@@ -4969,6 +5059,7 @@ class DynamicFieldDirective {
4969
5059
  document: DocumentFieldComponent,
4970
5060
  file: FileFieldComponent,
4971
5061
  phone: PhoneFieldComponent,
5062
+ color: ColorPickerFieldComponent,
4972
5063
  };
4973
5064
  ngOnChanges(changes) {
4974
5065
  if (changes['field']?.firstChange || this.shouldReloadComponent(changes)) {
@@ -15052,7 +15143,8 @@ class GenericDocumentationComponent {
15052
15143
  allowHelp: false,
15053
15144
  customDateFormat: 'dd/MM/yyyy HH:mm',
15054
15145
  emptyStateMessage: 'documentation.noDocuments',
15055
- emptyStateIcon: 'icon-file-not-found'
15146
+ emptyStateIcon: 'icon-file-not-found',
15147
+ showUploadButton: true,
15056
15148
  });
15057
15149
  loading = input(false);
15058
15150
  permissions = input({});
@@ -15190,11 +15282,11 @@ class GenericDocumentationComponent {
15190
15282
  return this.config().emptyStateMessage || 'documentation.noDocuments';
15191
15283
  }
15192
15284
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericDocumentationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15193
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: GenericDocumentationComponent, isStandalone: true, selector: "core-generic-documentation", inputs: { documents: { classPropertyName: "documents", publicName: "documents", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionTriggered: "actionTriggered", uploadRequested: "uploadRequested" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div *ngIf=\"!loading() && hasDocuments() && isGridMode()\" class=\"c-components-grid\">\n <div \n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\" \n class=\"c-doc\">\n \n <div class=\"c-bulleted-text\" *ngIf=\"config().showUploadDate || config().showUploadedBy\">\n <time \n *ngIf=\"config().showUploadDate\"\n \n [attr.datetime]=\"document.uploadedDate\">\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span \n *ngIf=\"config().showUploadedBy\"\n >\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p \n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\">\n {{ document.description }}\n </p>\n </div>\n <!-- DEV: Ajustar botones -->\n <div class=\"c-doc__group-btns\">\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DOWNLOAD, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\">\n </core-generic-button>\n </div>\n </div>\n </div>\n</div>\n\n<div *ngIf=\"!loading() && hasDocuments() && isListMode()\" class=\"c-components-grid\">\n <ul class=\"c-doc-list\">\n <li \n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\" \n class=\"c-doc-list__item\">\n \n <div class=\"c-doc\">\n <div class=\"c-bulleted-text\" *ngIf=\"config().showUploadDate || config().showUploadedBy\">\n <time \n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\">\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span \n *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p \n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\">\n {{ document.description }}\n </p>\n </div>\n\n <div class=\"c-doc__group-btns\">\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DOWNLOAD, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\">\n </core-generic-button>\n </div>\n </div>\n </div>\n </li>\n </ul>\n</div>\n\n<!-- Loading state -->\n<div *ngIf=\"loading()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon icon-loading\"></span>\n <p class=\"c-empty-state__message\">{{ 'commons.loading' | translate }}</p>\n </div>\n</div>\n\n<!-- Empty state - No documents -->\n<div *ngIf=\"!loading() && !hasDocuments()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon\" [class]=\"getEmptyStateIcon()\"></span>\n <p class=\"c-empty-state__message\">{{ getEmptyStateMessage() | translate }}</p>\n \n <!-- Upload button if user can upload -->\n <core-generic-button \n *ngIf=\"canUpload()\"\n [config]=\"uploadButtonConfig()\"\n (buttonClick)=\"onUploadClick($event.originalEvent)\">\n </core-generic-button>\n </div>\n</div>\n", styles: [".c-empty-state{--_color-main-hsl: var(--color-neutral-800-hsl);--_color-text-hsl: var(--color-neutral-800-hsl);--_py: 4em;--_px: 1.5em;--_br: var(--core-main-br);--_fz: var(--fz-200);display:flex;justify-content:center;align-items:center;text-align:center;padding:var(--_py) var(--_px);background-color:hsl(var(--_color-main-hsl)/4%);border-radius:var(--_br);font-size:var(--_fz);font-weight:600;max-width:100rem}.c-empty-state__content{max-width:25em}.c-empty-state__icon{display:block;font-size:2.4em;margin-bottom:.6em;opacity:.7}.c-empty-state__icon.icon-loading{animation:spin 1s linear infinite}.c-empty-state__message{color:#6b7280;line-height:1.5}.c-empty-state core-generic-button{display:block;margin-top:1.8em}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }] });
15285
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.6", type: GenericDocumentationComponent, isStandalone: true, selector: "core-generic-documentation", inputs: { documents: { classPropertyName: "documents", publicName: "documents", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionTriggered: "actionTriggered", uploadRequested: "uploadRequested" }, hostDirectives: [{ directive: CoreHostDirective }], ngImport: i0, template: "<div\n *ngIf=\"!loading() && hasDocuments() && isGridMode()\"\n class=\"c-components-grid\"\n>\n <div\n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\"\n class=\"c-doc\"\n >\n <div\n class=\"c-bulleted-text\"\n *ngIf=\"config().showUploadDate || config().showUploadedBy\"\n >\n <time\n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\"\n >\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p\n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\"\n >\n {{ document.description }}\n </p>\n </div>\n <!-- DEV: Ajustar botones -->\n <div class=\"c-doc__group-btns\">\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DOWNLOAD,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\n \"\n >\n </core-generic-button>\n </div>\n </div>\n </div>\n</div>\n\n<div\n *ngIf=\"!loading() && hasDocuments() && isListMode()\"\n class=\"c-components-grid\"\n>\n <ul class=\"c-doc-list\">\n <li\n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\"\n class=\"c-doc-list__item\"\n >\n <div class=\"c-doc\">\n <div\n class=\"c-bulleted-text\"\n *ngIf=\"config().showUploadDate || config().showUploadedBy\"\n >\n <time\n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\"\n >\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p\n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\"\n >\n {{ document.description }}\n </p>\n </div>\n\n <div class=\"c-doc__group-btns\">\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DOWNLOAD,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DELETE,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.HELP,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n </div>\n </div>\n </div>\n </li>\n </ul>\n</div>\n\n<!-- Loading state -->\n<div *ngIf=\"loading()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon icon-loading\"></span>\n <p class=\"c-empty-state__message\">{{ \"commons.loading\" | translate }}</p>\n </div>\n</div>\n\n<!-- Empty state - No documents -->\n<div\n *ngIf=\"!loading() && !hasDocuments() && config().showUploadButton\"\n class=\"c-empty-state\"\n>\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon\" [class]=\"getEmptyStateIcon()\"></span>\n <p class=\"c-empty-state__message\">\n {{ getEmptyStateMessage() | translate }}\n </p>\n\n <!-- Upload button if user can upload -->\n <core-generic-button\n *ngIf=\"canUpload()\"\n [config]=\"uploadButtonConfig()\"\n (buttonClick)=\"onUploadClick($event.originalEvent)\"\n >\n </core-generic-button>\n </div>\n</div>\n", styles: [".c-empty-state{--_color-main-hsl: var(--color-neutral-800-hsl);--_color-text-hsl: var(--color-neutral-800-hsl);--_py: 4em;--_px: 1.5em;--_br: var(--core-main-br);--_fz: var(--fz-200);display:flex;justify-content:center;align-items:center;text-align:center;padding:var(--_py) var(--_px);background-color:hsl(var(--_color-main-hsl)/4%);border-radius:var(--_br);font-size:var(--_fz);font-weight:600;max-width:100rem}.c-empty-state__content{max-width:25em}.c-empty-state__icon{display:block;font-size:2.4em;margin-bottom:.6em;opacity:.7}.c-empty-state__icon.icon-loading{animation:spin 1s linear infinite}.c-empty-state__message{color:#6b7280;line-height:1.5}.c-empty-state core-generic-button{display:block;margin-top:1.8em}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "component", type: GenericButtonComponent, selector: "core-generic-button", inputs: ["config", "data"], outputs: ["buttonClick"] }] });
15194
15286
  }
15195
15287
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericDocumentationComponent, decorators: [{
15196
15288
  type: Component,
15197
- args: [{ selector: 'core-generic-documentation', standalone: true, imports: [CommonModule, TranslateModule, GenericButtonComponent], hostDirectives: [CoreHostDirective], template: "<div *ngIf=\"!loading() && hasDocuments() && isGridMode()\" class=\"c-components-grid\">\n <div \n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\" \n class=\"c-doc\">\n \n <div class=\"c-bulleted-text\" *ngIf=\"config().showUploadDate || config().showUploadedBy\">\n <time \n *ngIf=\"config().showUploadDate\"\n \n [attr.datetime]=\"document.uploadedDate\">\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span \n *ngIf=\"config().showUploadedBy\"\n >\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p \n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\">\n {{ document.description }}\n </p>\n </div>\n <!-- DEV: Ajustar botones -->\n <div class=\"c-doc__group-btns\">\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DOWNLOAD, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\">\n </core-generic-button>\n </div>\n </div>\n </div>\n</div>\n\n<div *ngIf=\"!loading() && hasDocuments() && isListMode()\" class=\"c-components-grid\">\n <ul class=\"c-doc-list\">\n <li \n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\" \n class=\"c-doc-list__item\">\n \n <div class=\"c-doc\">\n <div class=\"c-bulleted-text\" *ngIf=\"config().showUploadDate || config().showUploadedBy\">\n <time \n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\">\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span \n *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p \n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\">\n {{ document.description }}\n </p>\n </div>\n\n <div class=\"c-doc__group-btns\">\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DOWNLOAD, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\">\n </core-generic-button>\n\n <core-generic-button \n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\">\n </core-generic-button>\n </div>\n </div>\n </div>\n </li>\n </ul>\n</div>\n\n<!-- Loading state -->\n<div *ngIf=\"loading()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon icon-loading\"></span>\n <p class=\"c-empty-state__message\">{{ 'commons.loading' | translate }}</p>\n </div>\n</div>\n\n<!-- Empty state - No documents -->\n<div *ngIf=\"!loading() && !hasDocuments()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon\" [class]=\"getEmptyStateIcon()\"></span>\n <p class=\"c-empty-state__message\">{{ getEmptyStateMessage() | translate }}</p>\n \n <!-- Upload button if user can upload -->\n <core-generic-button \n *ngIf=\"canUpload()\"\n [config]=\"uploadButtonConfig()\"\n (buttonClick)=\"onUploadClick($event.originalEvent)\">\n </core-generic-button>\n </div>\n</div>\n", styles: [".c-empty-state{--_color-main-hsl: var(--color-neutral-800-hsl);--_color-text-hsl: var(--color-neutral-800-hsl);--_py: 4em;--_px: 1.5em;--_br: var(--core-main-br);--_fz: var(--fz-200);display:flex;justify-content:center;align-items:center;text-align:center;padding:var(--_py) var(--_px);background-color:hsl(var(--_color-main-hsl)/4%);border-radius:var(--_br);font-size:var(--_fz);font-weight:600;max-width:100rem}.c-empty-state__content{max-width:25em}.c-empty-state__icon{display:block;font-size:2.4em;margin-bottom:.6em;opacity:.7}.c-empty-state__icon.icon-loading{animation:spin 1s linear infinite}.c-empty-state__message{color:#6b7280;line-height:1.5}.c-empty-state core-generic-button{display:block;margin-top:1.8em}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
15289
+ args: [{ selector: 'core-generic-documentation', standalone: true, imports: [CommonModule, TranslateModule, GenericButtonComponent], hostDirectives: [CoreHostDirective], template: "<div\n *ngIf=\"!loading() && hasDocuments() && isGridMode()\"\n class=\"c-components-grid\"\n>\n <div\n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\"\n class=\"c-doc\"\n >\n <div\n class=\"c-bulleted-text\"\n *ngIf=\"config().showUploadDate || config().showUploadedBy\"\n >\n <time\n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\"\n >\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p\n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\"\n >\n {{ document.description }}\n </p>\n </div>\n <!-- DEV: Ajustar botones -->\n <div class=\"c-doc__group-btns\">\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DOWNLOAD,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(DocumentAction.DELETE, document, $event.originalEvent)\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(DocumentAction.HELP, document, $event.originalEvent)\n \"\n >\n </core-generic-button>\n </div>\n </div>\n </div>\n</div>\n\n<div\n *ngIf=\"!loading() && hasDocuments() && isListMode()\"\n class=\"c-components-grid\"\n>\n <ul class=\"c-doc-list\">\n <li\n *ngFor=\"let document of documents(); trackBy: trackByDocumentId\"\n class=\"c-doc-list__item\"\n >\n <div class=\"c-doc\">\n <div\n class=\"c-bulleted-text\"\n *ngIf=\"config().showUploadDate || config().showUploadedBy\"\n >\n <time\n *ngIf=\"config().showUploadDate\"\n [attr.datetime]=\"document.uploadedDate\"\n >\n <span [class]=\"getFileIcon(document)\"></span>\n {{ formatDate(document.uploadedDate) }}\n </time>\n <span *ngIf=\"config().showUploadedBy\">\n {{ document.uploadedBy }}\n </span>\n </div>\n\n <div class=\"c-doc__file c-doc-file\">\n <div>\n <p class=\"c-doc__name\">{{ document.name }}</p>\n <p\n *ngIf=\"config().showDescription && document.description\"\n class=\"c-doc__description\"\n >\n {{ document.description }}\n </p>\n </div>\n\n <div class=\"c-doc__group-btns\">\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DOWNLOAD, document)\"\n [config]=\"getDownloadButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DOWNLOAD,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.DELETE, document)\"\n [config]=\"getDeleteButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.DELETE,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n\n <core-generic-button\n *ngIf=\"canPerformAction(DocumentAction.HELP, document)\"\n [config]=\"getHelpButtonConfig(document)\"\n [data]=\"document\"\n (buttonClick)=\"\n onButtonClick(\n DocumentAction.HELP,\n document,\n $event.originalEvent\n )\n \"\n >\n </core-generic-button>\n </div>\n </div>\n </div>\n </li>\n </ul>\n</div>\n\n<!-- Loading state -->\n<div *ngIf=\"loading()\" class=\"c-empty-state\">\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon icon-loading\"></span>\n <p class=\"c-empty-state__message\">{{ \"commons.loading\" | translate }}</p>\n </div>\n</div>\n\n<!-- Empty state - No documents -->\n<div\n *ngIf=\"!loading() && !hasDocuments() && config().showUploadButton\"\n class=\"c-empty-state\"\n>\n <div class=\"c-empty-state__content\">\n <span class=\"c-empty-state__icon\" [class]=\"getEmptyStateIcon()\"></span>\n <p class=\"c-empty-state__message\">\n {{ getEmptyStateMessage() | translate }}\n </p>\n\n <!-- Upload button if user can upload -->\n <core-generic-button\n *ngIf=\"canUpload()\"\n [config]=\"uploadButtonConfig()\"\n (buttonClick)=\"onUploadClick($event.originalEvent)\"\n >\n </core-generic-button>\n </div>\n</div>\n", styles: [".c-empty-state{--_color-main-hsl: var(--color-neutral-800-hsl);--_color-text-hsl: var(--color-neutral-800-hsl);--_py: 4em;--_px: 1.5em;--_br: var(--core-main-br);--_fz: var(--fz-200);display:flex;justify-content:center;align-items:center;text-align:center;padding:var(--_py) var(--_px);background-color:hsl(var(--_color-main-hsl)/4%);border-radius:var(--_br);font-size:var(--_fz);font-weight:600;max-width:100rem}.c-empty-state__content{max-width:25em}.c-empty-state__icon{display:block;font-size:2.4em;margin-bottom:.6em;opacity:.7}.c-empty-state__icon.icon-loading{animation:spin 1s linear infinite}.c-empty-state__message{color:#6b7280;line-height:1.5}.c-empty-state core-generic-button{display:block;margin-top:1.8em}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
15198
15290
  }], ctorParameters: () => [] });
15199
15291
 
15200
15292
  class LayoutService {
@@ -16556,12 +16648,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
16556
16648
  // Este archivo es generado automáticamente por scripts/update-version.js
16557
16649
  // No edites manualmente este archivo
16558
16650
  const VERSION = {
16559
- full: '2.17.0',
16651
+ full: '2.17.2',
16560
16652
  major: 2,
16561
16653
  minor: 17,
16562
- patch: 0,
16563
- timestamp: '2025-12-11T18:35:18.659Z',
16564
- buildDate: '11/12/2025'
16654
+ patch: 2,
16655
+ timestamp: '2025-12-16T15:13:31.821Z',
16656
+ buildDate: '16/12/2025'
16565
16657
  };
16566
16658
 
16567
16659
  class MainNavComponent {
@@ -21156,7 +21248,8 @@ const DEFAULT_SCHEDULER_CONFIG = {
21156
21248
  slotDuration: 30,
21157
21249
  rowHeightRem: 4,
21158
21250
  showCurrentTimeLine: true,
21159
- locale: 'es-ES'
21251
+ locale: 'es-ES',
21252
+ viewMode: 'day'
21160
21253
  };
21161
21254
 
21162
21255
  class GenericSchedulerComponent {
@@ -21171,6 +21264,10 @@ class GenericSchedulerComponent {
21171
21264
  disabledSlotLabel = input('No disponible');
21172
21265
  todayLabel = input('Hoy');
21173
21266
  locale = input('es-ES');
21267
+ weekLabel = input('Semana');
21268
+ dayLabel = input('Día');
21269
+ monthLabel = input('Mes');
21270
+ disabledDates = input([]);
21174
21271
  slotClick = output();
21175
21272
  eventClick = output();
21176
21273
  eventHover = output();
@@ -21178,10 +21275,70 @@ class GenericSchedulerComponent {
21178
21275
  todayClick = output();
21179
21276
  previousDay = output();
21180
21277
  nextDay = output();
21278
+ previousWeek = output();
21279
+ nextWeek = output();
21280
+ previousMonth = output();
21281
+ nextMonth = output();
21282
+ viewModeChange = output();
21181
21283
  timeSlots = signal([]);
21182
21284
  currentTime = signal(new Date());
21285
+ expandedDay = signal(null);
21183
21286
  timeUpdateInterval = null;
21184
21287
  mergedConfig = computed(() => ({ ...DEFAULT_SCHEDULER_CONFIG, ...this.config() }));
21288
+ viewMode = computed(() => this.mergedConfig().viewMode || 'day');
21289
+ weekDays = computed(() => {
21290
+ if (this.viewMode() !== 'week')
21291
+ return [];
21292
+ const selected = this.selectedDate();
21293
+ const localeValue = this.locale();
21294
+ const today = new Date();
21295
+ const dayOfWeek = selected.getUTCDay();
21296
+ const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
21297
+ const monday = new Date(Date.UTC(selected.getUTCFullYear(), selected.getUTCMonth(), selected.getUTCDate() + mondayOffset));
21298
+ const days = [];
21299
+ for (let i = 0; i < 7; i++) {
21300
+ const date = new Date(Date.UTC(monday.getUTCFullYear(), monday.getUTCMonth(), monday.getUTCDate() + i));
21301
+ const isToday = date.getUTCFullYear() === today.getUTCFullYear() &&
21302
+ date.getUTCMonth() === today.getUTCMonth() &&
21303
+ date.getUTCDate() === today.getUTCDate();
21304
+ days.push({
21305
+ date,
21306
+ dayNumber: date.getUTCDate(),
21307
+ dayName: date.toLocaleDateString(localeValue, { weekday: 'short', timeZone: 'UTC' }),
21308
+ isToday,
21309
+ isWeekend: i >= 5
21310
+ });
21311
+ }
21312
+ return days;
21313
+ });
21314
+ monthDays = computed(() => {
21315
+ if (this.viewMode() !== 'month')
21316
+ return [];
21317
+ const selected = this.selectedDate();
21318
+ const localeValue = this.locale();
21319
+ const today = new Date();
21320
+ const year = selected.getUTCFullYear();
21321
+ const month = selected.getUTCMonth();
21322
+ const firstDayOfMonth = new Date(Date.UTC(year, month, 1));
21323
+ const dayOfWeek = firstDayOfMonth.getUTCDay();
21324
+ const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
21325
+ const startDate = new Date(Date.UTC(year, month, 1 + mondayOffset));
21326
+ const days = [];
21327
+ for (let i = 0; i < 42; i++) {
21328
+ const date = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth(), startDate.getUTCDate() + i));
21329
+ const isToday = date.getUTCFullYear() === today.getUTCFullYear() &&
21330
+ date.getUTCMonth() === today.getUTCMonth() &&
21331
+ date.getUTCDate() === today.getUTCDate();
21332
+ days.push({
21333
+ date,
21334
+ dayNumber: date.getUTCDate(),
21335
+ dayName: date.toLocaleDateString(localeValue, { weekday: 'short', timeZone: 'UTC' }),
21336
+ isToday,
21337
+ isWeekend: [0, 6].includes(date.getUTCDay())
21338
+ });
21339
+ }
21340
+ return days;
21341
+ });
21185
21342
  isToday = computed(() => {
21186
21343
  const selected = this.selectedDate();
21187
21344
  const today = new Date();
@@ -21192,6 +21349,32 @@ class GenericSchedulerComponent {
21192
21349
  formattedDate = computed(() => {
21193
21350
  const date = this.selectedDate();
21194
21351
  const localeValue = this.locale();
21352
+ if (this.viewMode() === 'week') {
21353
+ const days = this.weekDays();
21354
+ if (days.length > 0) {
21355
+ const firstDay = days[0].date;
21356
+ const lastDay = days[6].date;
21357
+ const firstFormatted = firstDay.toLocaleDateString(localeValue, {
21358
+ day: 'numeric',
21359
+ month: 'short',
21360
+ timeZone: 'UTC'
21361
+ });
21362
+ const lastFormatted = lastDay.toLocaleDateString(localeValue, {
21363
+ day: 'numeric',
21364
+ month: 'short',
21365
+ year: 'numeric',
21366
+ timeZone: 'UTC'
21367
+ });
21368
+ return `${firstFormatted} - ${lastFormatted}`;
21369
+ }
21370
+ }
21371
+ if (this.viewMode() === 'month') {
21372
+ return date.toLocaleDateString(localeValue, {
21373
+ month: 'long',
21374
+ year: 'numeric',
21375
+ timeZone: 'UTC'
21376
+ });
21377
+ }
21195
21378
  return date.toLocaleDateString(localeValue, {
21196
21379
  weekday: 'long',
21197
21380
  year: 'numeric',
@@ -21201,8 +21384,17 @@ class GenericSchedulerComponent {
21201
21384
  });
21202
21385
  });
21203
21386
  currentTimePosition = computed(() => {
21204
- if (!this.isToday() || !this.mergedConfig().showCurrentTimeLine)
21387
+ if (!this.mergedConfig().showCurrentTimeLine)
21205
21388
  return null;
21389
+ if (this.viewMode() === 'week') {
21390
+ const days = this.weekDays();
21391
+ const todayIndex = days.findIndex(d => d.isToday);
21392
+ if (todayIndex === -1)
21393
+ return null;
21394
+ }
21395
+ else if (!this.isToday()) {
21396
+ return null;
21397
+ }
21206
21398
  const now = this.currentTime();
21207
21399
  const hours = now.getUTCHours();
21208
21400
  const minutes = now.getUTCMinutes();
@@ -21215,6 +21407,12 @@ class GenericSchedulerComponent {
21215
21407
  const positionInRem = slotsFromStart * cfg.rowHeightRem;
21216
21408
  return positionInRem;
21217
21409
  });
21410
+ currentTimeDayIndex = computed(() => {
21411
+ if (this.viewMode() !== 'week')
21412
+ return -1;
21413
+ const days = this.weekDays();
21414
+ return days.findIndex(d => d.isToday);
21415
+ });
21218
21416
  eventMap = computed(() => {
21219
21417
  const map = new Map();
21220
21418
  const evts = this.events();
@@ -21295,6 +21493,10 @@ class GenericSchedulerComponent {
21295
21493
  isSlotDisabled(columnId, slot) {
21296
21494
  const now = new Date();
21297
21495
  const selected = this.selectedDate();
21496
+ const dateStr = selected.toISOString().split('T')[0];
21497
+ if (this.disabledDates().includes(dateStr)) {
21498
+ return true;
21499
+ }
21298
21500
  const todayUTC = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
21299
21501
  const selectedUTC = Date.UTC(selected.getUTCFullYear(), selected.getUTCMonth(), selected.getUTCDate());
21300
21502
  if (selectedUTC < todayUTC) {
@@ -21350,15 +21552,170 @@ class GenericSchedulerComponent {
21350
21552
  const nextDayDate = new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth(), current.getUTCDate() + 1));
21351
21553
  this.nextDay.emit(nextDayDate);
21352
21554
  }
21555
+ onPreviousWeek() {
21556
+ const current = this.selectedDate();
21557
+ const prevWeek = new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth(), current.getUTCDate() - 7));
21558
+ this.previousWeek.emit(prevWeek);
21559
+ }
21560
+ onNextWeek() {
21561
+ const current = this.selectedDate();
21562
+ const nextWeekDate = new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth(), current.getUTCDate() + 7));
21563
+ this.nextWeek.emit(nextWeekDate);
21564
+ }
21565
+ onPreviousMonth() {
21566
+ const current = this.selectedDate();
21567
+ const prevMonth = new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth() - 1, 1));
21568
+ this.previousMonth.emit(prevMonth);
21569
+ }
21570
+ onNextMonth() {
21571
+ const current = this.selectedDate();
21572
+ const nextMonth = new Date(Date.UTC(current.getUTCFullYear(), current.getUTCMonth() + 1, 1));
21573
+ this.nextMonth.emit(nextMonth);
21574
+ }
21575
+ onPrevious() {
21576
+ if (this.viewMode() === 'week') {
21577
+ this.onPreviousWeek();
21578
+ }
21579
+ else if (this.viewMode() === 'month') {
21580
+ this.onPreviousMonth();
21581
+ }
21582
+ else {
21583
+ this.onPreviousDay();
21584
+ }
21585
+ }
21586
+ onNext() {
21587
+ if (this.viewMode() === 'week') {
21588
+ this.onNextWeek();
21589
+ }
21590
+ else if (this.viewMode() === 'month') {
21591
+ this.onNextMonth();
21592
+ }
21593
+ else {
21594
+ this.onNextDay();
21595
+ }
21596
+ }
21597
+ toggleViewMode() {
21598
+ const newMode = this.viewMode() === 'day' ? 'week' : 'day';
21599
+ this.viewModeChange.emit(newMode);
21600
+ }
21601
+ setViewMode(mode) {
21602
+ this.viewModeChange.emit(mode);
21603
+ }
21604
+ getEventsForDay(dayDate) {
21605
+ const evts = this.events();
21606
+ return evts.filter(event => {
21607
+ if (!event.date)
21608
+ return false;
21609
+ const eventDate = new Date(event.date);
21610
+ return eventDate.getUTCFullYear() === dayDate.getUTCFullYear() &&
21611
+ eventDate.getUTCMonth() === dayDate.getUTCMonth() &&
21612
+ eventDate.getUTCDate() === dayDate.getUTCDate();
21613
+ });
21614
+ }
21615
+ isSlotOccupiedForDay(dayDate, slot) {
21616
+ const evts = this.getEventsForDay(dayDate);
21617
+ return evts.some(event => this.isTimeInEvent(slot.time, event));
21618
+ }
21619
+ shouldShowEventForDay(dayDate, slot) {
21620
+ const evts = this.getEventsForDay(dayDate);
21621
+ return evts.some(event => event.startTime === slot.time);
21622
+ }
21623
+ getEventForDaySlot(dayDate, slot) {
21624
+ const evts = this.getEventsForDay(dayDate);
21625
+ return evts.find(event => event.startTime === slot.time);
21626
+ }
21627
+ isDayDisabled(dayDate) {
21628
+ const dateStr = dayDate.toISOString().split('T')[0];
21629
+ return this.disabledDates().includes(dateStr);
21630
+ }
21631
+ isSlotDisabledForDay(dayDate, slot) {
21632
+ if (this.isDayDisabled(dayDate)) {
21633
+ return true;
21634
+ }
21635
+ const now = new Date();
21636
+ const todayUTC = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
21637
+ const dayUTC = Date.UTC(dayDate.getUTCFullYear(), dayDate.getUTCMonth(), dayDate.getUTCDate());
21638
+ if (dayUTC < todayUTC) {
21639
+ return true;
21640
+ }
21641
+ if (dayUTC === todayUTC) {
21642
+ const [slotHour, slotMin] = slot.time.split(':').map(Number);
21643
+ const slotMinutes = slotHour * 60 + slotMin;
21644
+ const currentMinutes = now.getUTCHours() * 60 + now.getUTCMinutes();
21645
+ return slotMinutes < currentMinutes;
21646
+ }
21647
+ return false;
21648
+ }
21649
+ onWeekSlotClick(dayDate, slot) {
21650
+ if (this.isSlotOccupiedForDay(dayDate, slot) || this.isSlotDisabledForDay(dayDate, slot)) {
21651
+ return;
21652
+ }
21653
+ this.slotClick.emit({
21654
+ columnId: dayDate.toISOString(),
21655
+ slot,
21656
+ date: dayDate
21657
+ });
21658
+ }
21659
+ onWeekEventClick(event, dayDate) {
21660
+ const pseudoColumn = {
21661
+ id: dayDate.toISOString(),
21662
+ name: dayDate.toLocaleDateString(this.locale(), { weekday: 'long', timeZone: 'UTC' })
21663
+ };
21664
+ this.eventClick.emit({ event, column: pseudoColumn });
21665
+ }
21666
+ onMonthDayClick(dayDate) {
21667
+ const dummySlot = {
21668
+ time: '00:00',
21669
+ hour: 0,
21670
+ minutes: 0,
21671
+ isHalfHour: false,
21672
+ displayTime: false
21673
+ };
21674
+ this.slotClick.emit({
21675
+ columnId: dayDate.toISOString(),
21676
+ slot: dummySlot,
21677
+ date: dayDate
21678
+ });
21679
+ }
21680
+ onMonthEventClick(event, dayDate) {
21681
+ const pseudoColumn = {
21682
+ id: dayDate.toISOString(),
21683
+ name: dayDate.toLocaleDateString(this.locale(), { weekday: 'long', timeZone: 'UTC' })
21684
+ };
21685
+ this.eventClick.emit({ event, column: pseudoColumn });
21686
+ }
21687
+ openDayPopover(dayDate, event) {
21688
+ event.stopPropagation();
21689
+ this.expandedDay.set(dayDate);
21690
+ }
21691
+ closeDayPopover() {
21692
+ this.expandedDay.set(null);
21693
+ }
21694
+ getExpandedDayEvents() {
21695
+ const day = this.expandedDay();
21696
+ if (!day)
21697
+ return [];
21698
+ return this.getEventsForDay(day);
21699
+ }
21700
+ getExpandedDayLabel() {
21701
+ const day = this.expandedDay();
21702
+ if (!day)
21703
+ return '';
21704
+ const localeValue = this.locale();
21705
+ const weekday = day.toLocaleDateString(localeValue, { weekday: 'short', timeZone: 'UTC' }).toUpperCase();
21706
+ const dayNum = day.getUTCDate();
21707
+ return `${weekday}\n${dayNum}`;
21708
+ }
21353
21709
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericSchedulerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
21354
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericSchedulerComponent, isStandalone: true, selector: "core-generic-scheduler", inputs: { selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showTimeColumn: { classPropertyName: "showTimeColumn", publicName: "showTimeColumn", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, emptySlotLabel: { classPropertyName: "emptySlotLabel", publicName: "emptySlotLabel", isSignal: true, isRequired: false, transformFunction: null }, disabledSlotLabel: { classPropertyName: "disabledSlotLabel", publicName: "disabledSlotLabel", isSignal: true, isRequired: false, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { slotClick: "slotClick", eventClick: "eventClick", eventHover: "eventHover", eventLeave: "eventLeave", todayClick: "todayClick", previousDay: "previousDay", nextDay: "nextDay" }, host: { properties: { "style.--cols": "columns().length" }, classAttribute: "c-bookings-grid c-bookings-card" }, ngImport: i0, template: "@if (showHeader()) {\n<div class=\"c-bookings-header\">\n <button class=\"c-bookings-header__today\" (click)=\"onTodayClick()\">\n {{ todayLabel() }}\n </button>\n\n <div class=\"c-bookings-header__date\">\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-left\"\n title=\"D\u00EDa anterior\"\n (click)=\"onPreviousDay()\"\n ></button>\n <span>{{ formattedDate() }}</span>\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-right\"\n title=\"D\u00EDa siguiente\"\n (click)=\"onNextDay()\"\n ></button>\n </div>\n</div>\n}\n\n<div\n class=\"c-bookings-grid__wrapper\"\n [style.--cols]=\"columns().length\"\n style=\"position: relative\"\n>\n @if (isToday() && currentTimePosition() !== null) {\n <div\n class=\"c-bookings-grid__current-time-line\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (column of columns(); track column.id) {\n <div class=\"c-bookings-grid__col\">\n <div class=\"c-bookings-grid__top\">\n <p class=\"c-bookings-grid__title\">{{ column.name }}</p>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupied(column.id, slot)) { @if (isSlotDisabled(column.id,\n slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n >\n {{ disabledSlotLabel() }}\n </button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onSlotClick(column.id, slot)\"\n >\n {{ emptySlotLabel() }}\n </button>\n } } @if (shouldShowEvent(column.id, slot)) { @let event =\n getEventForSlot(column.id, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onEventClick(event, column)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n\n @if (event.canCancel) {\n <button\n class=\"c-bookings-grid__link c-link--underlined\"\n (click)=\"$event.stopPropagation()\"\n >\n <span class=\"icon-cross-thin\"></span>\n Cancelar\n </button>\n } @if ((event.canApprove || event.canReject) && event.duration >= 91) {\n <div class=\"c-bookings-grid__quick-actions\">\n @if (event.canApprove) {\n <button\n class=\"c-icon-btn--fill context:success icon-check\"\n title=\"Aprobar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n } @if (event.canReject) {\n <button\n class=\"c-icon-btn--fill context:error icon-cross\"\n title=\"Rechazar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n }\n </div>\n }\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;overflow:visible}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
21710
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: GenericSchedulerComponent, isStandalone: true, selector: "core-generic-scheduler", inputs: { selectedDate: { classPropertyName: "selectedDate", publicName: "selectedDate", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showTimeColumn: { classPropertyName: "showTimeColumn", publicName: "showTimeColumn", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, emptySlotLabel: { classPropertyName: "emptySlotLabel", publicName: "emptySlotLabel", isSignal: true, isRequired: false, transformFunction: null }, disabledSlotLabel: { classPropertyName: "disabledSlotLabel", publicName: "disabledSlotLabel", isSignal: true, isRequired: false, transformFunction: null }, todayLabel: { classPropertyName: "todayLabel", publicName: "todayLabel", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, weekLabel: { classPropertyName: "weekLabel", publicName: "weekLabel", isSignal: true, isRequired: false, transformFunction: null }, dayLabel: { classPropertyName: "dayLabel", publicName: "dayLabel", isSignal: true, isRequired: false, transformFunction: null }, monthLabel: { classPropertyName: "monthLabel", publicName: "monthLabel", isSignal: true, isRequired: false, transformFunction: null }, disabledDates: { classPropertyName: "disabledDates", publicName: "disabledDates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { slotClick: "slotClick", eventClick: "eventClick", eventHover: "eventHover", eventLeave: "eventLeave", todayClick: "todayClick", previousDay: "previousDay", nextDay: "nextDay", previousWeek: "previousWeek", nextWeek: "nextWeek", previousMonth: "previousMonth", nextMonth: "nextMonth", viewModeChange: "viewModeChange" }, host: { properties: { "class.c-bookings-grid--weekly": "viewMode() === \"week\"", "style.--cols": "columns().length" }, classAttribute: "c-bookings-grid c-bookings-card" }, ngImport: i0, template: "@if (showHeader()) {\n<div class=\"c-bookings-header\">\n <button class=\"c-bookings-header__today\" (click)=\"onTodayClick()\">\n {{ todayLabel() }}\n </button>\n\n <div class=\"c-bookings-header__date\">\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-left\"\n [title]=\"viewMode() === 'week' ? 'Semana anterior' : 'D\u00EDa anterior'\"\n (click)=\"onPrevious()\"\n ></button>\n <span>{{ formattedDate() }}</span>\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-right\"\n [title]=\"viewMode() === 'week' ? 'Semana siguiente' : 'D\u00EDa siguiente'\"\n (click)=\"onNext()\"\n ></button>\n </div>\n\n <div class=\"c-bookings-header__view-toggle\">\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'day'\"\n (click)=\"setViewMode('day')\"\n >\n {{ dayLabel() }}\n </button>\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'week'\"\n (click)=\"setViewMode('week')\"\n >\n {{ weekLabel() }}\n </button>\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'month'\"\n (click)=\"setViewMode('month')\"\n >\n {{ monthLabel() }}\n </button>\n </div>\n</div>\n} @if (viewMode() === 'day') {\n<!-- DAILY VIEW -->\n<div\n class=\"c-bookings-grid__wrapper\"\n [style.--cols]=\"columns().length\"\n style=\"position: relative\"\n>\n @if (isToday() && currentTimePosition() !== null) {\n <div\n class=\"c-bookings-grid__current-time-line\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (column of columns(); track column.id) {\n <div class=\"c-bookings-grid__col\">\n <div class=\"c-bookings-grid__top\">\n <p class=\"c-bookings-grid__title\">{{ column.name }}</p>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupied(column.id, slot)) { @if (isSlotDisabled(column.id,\n slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n >\n {{ disabledSlotLabel() }}\n </button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onSlotClick(column.id, slot)\"\n >\n {{ emptySlotLabel() }}\n </button>\n } } @if (shouldShowEvent(column.id, slot)) { @let event =\n getEventForSlot(column.id, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onEventClick(event, column)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n\n @if (event.canCancel) {\n <button\n class=\"c-bookings-grid__link c-link--underlined\"\n (click)=\"$event.stopPropagation()\"\n >\n <span class=\"icon-cross-thin\"></span>\n Cancelar\n </button>\n } @if ((event.canApprove || event.canReject) && event.duration >= 91) {\n <div class=\"c-bookings-grid__quick-actions\">\n @if (event.canApprove) {\n <button\n class=\"c-icon-btn--fill context:success icon-check\"\n title=\"Aprobar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n } @if (event.canReject) {\n <button\n class=\"c-icon-btn--fill context:error icon-cross\"\n title=\"Rechazar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n }\n </div>\n }\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n} @else if (viewMode() === 'week') {\n<!-- WEEKLY VIEW -->\n<div\n class=\"c-bookings-grid__wrapper c-bookings-grid__wrapper--weekly\"\n [style.--cols]=\"7\"\n style=\"position: relative\"\n>\n @if (currentTimePosition() !== null && currentTimeDayIndex() >= 0) {\n <div\n class=\"c-bookings-grid__current-time-line c-bookings-grid__current-time-line--weekly\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n [style.--day-index]=\"currentTimeDayIndex()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top c-bookings-grid__top--weekly\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (day of weekDays(); track day.date.getTime()) {\n <div\n class=\"c-bookings-grid__col\"\n [class.c-bookings-grid__col--weekend]=\"day.isWeekend\"\n >\n <div class=\"c-bookings-grid__top c-bookings-grid__top--weekly\">\n <div class=\"c-bookings-grid__day-header\" [class.is-today]=\"day.isToday\">\n <span class=\"c-bookings-grid__day-name\">{{ day.dayName }}</span>\n <span\n class=\"c-bookings-grid__day-number\"\n [class.is-today]=\"day.isToday\"\n >{{ day.dayNumber }}</span\n >\n </div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupiedForDay(day.date, slot)) { @if\n (isSlotDisabledForDay(day.date, slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n ></button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onWeekSlotClick(day.date, slot)\"\n ></button>\n } } @if (shouldShowEventForDay(day.date, slot)) { @let event =\n getEventForDaySlot(day.date, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onWeekEventClick(event, day.date)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n} @else if (viewMode() === 'month') {\n<!-- MONTHLY VIEW -->\n<div class=\"c-bookings-grid__wrapper c-bookings-grid__wrapper--monthly\">\n <!-- Header Row -->\n <div class=\"c-bookings-grid__header-row\">\n @for (day of monthDays().slice(0, 7); track day.dayName) {\n <div class=\"c-bookings-grid__header-cell\">\n {{ day.dayName }}\n </div>\n }\n </div>\n\n <!-- Days Grid -->\n <div class=\"c-bookings-grid__month-grid\">\n @for (day of monthDays(); track day.date.getTime()) {\n <div\n class=\"c-bookings-grid__month-cell\"\n [class.is-today]=\"day.isToday\"\n [class.is-weekend]=\"day.isWeekend\"\n [class.is-other-month]=\"\n day.date.getUTCMonth() !== selectedDate().getUTCMonth()\n \"\n [class.is-disabled]=\"isDayDisabled(day.date)\"\n (click)=\"!isDayDisabled(day.date) && onMonthDayClick(day.date)\"\n >\n <div class=\"c-bookings-grid__month-day-number\">\n {{ day.dayNumber }}\n </div>\n\n <div class=\"c-bookings-grid__month-events\">\n @let dayEvents = getEventsForDay(day.date); @for (event of\n dayEvents.slice(0, 3); track event.id) {\n <div\n class=\"c-bookings-grid__month-event\"\n [attr.data-type]=\"event.type\"\n [style.background-color]=\"event.metadata?.['color']\"\n [style.border-left]=\"event.metadata?.['color'] ? '3px solid ' + event.metadata?.['color'] : ''\"\n (click)=\"$event.stopPropagation(); onMonthEventClick(event, day.date)\"\n >\n <span class=\"c-bookings-grid__month-event-title\">{{\n event.title\n }}</span>\n </div>\n } @if (dayEvents.length > 3) {\n <div\n class=\"c-bookings-grid__more-events\"\n (click)=\"openDayPopover(day.date, $event)\"\n >\n {{ dayEvents.length - 3 }} m\u00E1s\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n @if (expandedDay()) {\n <div class=\"c-bookings-grid__popover-overlay\" (click)=\"closeDayPopover()\">\n <div class=\"c-bookings-grid__popover\" (click)=\"$event.stopPropagation()\">\n <div class=\"c-bookings-grid__popover-header\">\n <div class=\"c-bookings-grid__popover-date\">\n <span class=\"c-bookings-grid__popover-weekday\">{{\n expandedDay() | date : \"EEE\" : \"UTC\" : locale() | uppercase\n }}</span>\n <span class=\"c-bookings-grid__popover-daynum\">{{\n expandedDay() | date : \"d\" : \"UTC\"\n }}</span>\n </div>\n <button\n class=\"c-bookings-grid__popover-close\"\n (click)=\"closeDayPopover()\"\n >\n <span class=\"icon-cross\"></span>\n </button>\n </div>\n <div class=\"c-bookings-grid__popover-content\">\n @for (event of getExpandedDayEvents(); track event.id) {\n <div\n class=\"c-bookings-grid__month-event c-bookings-grid__month-event--popover\"\n [attr.data-type]=\"event.type\"\n [style.background-color]=\"event.metadata?.['color']\"\n [style.border-left]=\"event.metadata?.['color'] ? '3px solid ' + event.metadata?.['color'] : ''\"\n (click)=\"onMonthEventClick(event, expandedDay()!)\"\n >\n <span class=\"c-bookings-grid__month-event-title\">{{\n event.title\n }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n}\n", styles: [":host{display:block;width:100%;overflow:visible}.c-bookings-grid__month-cell.is-disabled{background-color:#f3f4f6;cursor:not-allowed;opacity:.7}.c-bookings-grid__month-cell.is-disabled:hover{background-color:#f3f4f6}.c-bookings-grid__month-cell.is-disabled .c-bookings-grid__month-day-number{color:#9ca3af}.c-bookings-grid__slot--disabled{background-color:#f3f4f6;cursor:not-allowed}.c-bookings-grid__slot--disabled:hover{background-color:#f3f4f6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i2.DatePipe, name: "date" }] });
21355
21711
  }
21356
21712
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: GenericSchedulerComponent, decorators: [{
21357
21713
  type: Component,
21358
21714
  args: [{ selector: 'core-generic-scheduler', standalone: true, imports: [CommonModule], host: {
21359
21715
  'class': 'c-bookings-grid c-bookings-card',
21716
+ '[class.c-bookings-grid--weekly]': 'viewMode() === "week"',
21360
21717
  '[style.--cols]': 'columns().length'
21361
- }, template: "@if (showHeader()) {\n<div class=\"c-bookings-header\">\n <button class=\"c-bookings-header__today\" (click)=\"onTodayClick()\">\n {{ todayLabel() }}\n </button>\n\n <div class=\"c-bookings-header__date\">\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-left\"\n title=\"D\u00EDa anterior\"\n (click)=\"onPreviousDay()\"\n ></button>\n <span>{{ formattedDate() }}</span>\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-right\"\n title=\"D\u00EDa siguiente\"\n (click)=\"onNextDay()\"\n ></button>\n </div>\n</div>\n}\n\n<div\n class=\"c-bookings-grid__wrapper\"\n [style.--cols]=\"columns().length\"\n style=\"position: relative\"\n>\n @if (isToday() && currentTimePosition() !== null) {\n <div\n class=\"c-bookings-grid__current-time-line\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (column of columns(); track column.id) {\n <div class=\"c-bookings-grid__col\">\n <div class=\"c-bookings-grid__top\">\n <p class=\"c-bookings-grid__title\">{{ column.name }}</p>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupied(column.id, slot)) { @if (isSlotDisabled(column.id,\n slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n >\n {{ disabledSlotLabel() }}\n </button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onSlotClick(column.id, slot)\"\n >\n {{ emptySlotLabel() }}\n </button>\n } } @if (shouldShowEvent(column.id, slot)) { @let event =\n getEventForSlot(column.id, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onEventClick(event, column)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n\n @if (event.canCancel) {\n <button\n class=\"c-bookings-grid__link c-link--underlined\"\n (click)=\"$event.stopPropagation()\"\n >\n <span class=\"icon-cross-thin\"></span>\n Cancelar\n </button>\n } @if ((event.canApprove || event.canReject) && event.duration >= 91) {\n <div class=\"c-bookings-grid__quick-actions\">\n @if (event.canApprove) {\n <button\n class=\"c-icon-btn--fill context:success icon-check\"\n title=\"Aprobar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n } @if (event.canReject) {\n <button\n class=\"c-icon-btn--fill context:error icon-cross\"\n title=\"Rechazar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n }\n </div>\n }\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{display:block;width:100%;overflow:visible}\n"] }]
21718
+ }, template: "@if (showHeader()) {\n<div class=\"c-bookings-header\">\n <button class=\"c-bookings-header__today\" (click)=\"onTodayClick()\">\n {{ todayLabel() }}\n </button>\n\n <div class=\"c-bookings-header__date\">\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-left\"\n [title]=\"viewMode() === 'week' ? 'Semana anterior' : 'D\u00EDa anterior'\"\n (click)=\"onPrevious()\"\n ></button>\n <span>{{ formattedDate() }}</span>\n <button\n class=\"c-bookings-header__date-arrow icon-arrow-right\"\n [title]=\"viewMode() === 'week' ? 'Semana siguiente' : 'D\u00EDa siguiente'\"\n (click)=\"onNext()\"\n ></button>\n </div>\n\n <div class=\"c-bookings-header__view-toggle\">\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'day'\"\n (click)=\"setViewMode('day')\"\n >\n {{ dayLabel() }}\n </button>\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'week'\"\n (click)=\"setViewMode('week')\"\n >\n {{ weekLabel() }}\n </button>\n <button\n class=\"c-bookings-header__view-btn\"\n [class.is-active]=\"viewMode() === 'month'\"\n (click)=\"setViewMode('month')\"\n >\n {{ monthLabel() }}\n </button>\n </div>\n</div>\n} @if (viewMode() === 'day') {\n<!-- DAILY VIEW -->\n<div\n class=\"c-bookings-grid__wrapper\"\n [style.--cols]=\"columns().length\"\n style=\"position: relative\"\n>\n @if (isToday() && currentTimePosition() !== null) {\n <div\n class=\"c-bookings-grid__current-time-line\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (column of columns(); track column.id) {\n <div class=\"c-bookings-grid__col\">\n <div class=\"c-bookings-grid__top\">\n <p class=\"c-bookings-grid__title\">{{ column.name }}</p>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupied(column.id, slot)) { @if (isSlotDisabled(column.id,\n slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n >\n {{ disabledSlotLabel() }}\n </button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onSlotClick(column.id, slot)\"\n >\n {{ emptySlotLabel() }}\n </button>\n } } @if (shouldShowEvent(column.id, slot)) { @let event =\n getEventForSlot(column.id, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onEventClick(event, column)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n\n @if (event.canCancel) {\n <button\n class=\"c-bookings-grid__link c-link--underlined\"\n (click)=\"$event.stopPropagation()\"\n >\n <span class=\"icon-cross-thin\"></span>\n Cancelar\n </button>\n } @if ((event.canApprove || event.canReject) && event.duration >= 91) {\n <div class=\"c-bookings-grid__quick-actions\">\n @if (event.canApprove) {\n <button\n class=\"c-icon-btn--fill context:success icon-check\"\n title=\"Aprobar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n } @if (event.canReject) {\n <button\n class=\"c-icon-btn--fill context:error icon-cross\"\n title=\"Rechazar\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n }\n </div>\n }\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n} @else if (viewMode() === 'week') {\n<!-- WEEKLY VIEW -->\n<div\n class=\"c-bookings-grid__wrapper c-bookings-grid__wrapper--weekly\"\n [style.--cols]=\"7\"\n style=\"position: relative\"\n>\n @if (currentTimePosition() !== null && currentTimeDayIndex() >= 0) {\n <div\n class=\"c-bookings-grid__current-time-line c-bookings-grid__current-time-line--weekly\"\n [style.--time-position-rem]=\"currentTimePosition()\"\n [style.--day-index]=\"currentTimeDayIndex()\"\n ></div>\n } @if (showTimeColumn()) {\n <div class=\"c-bookings-grid__times\">\n <div class=\"c-bookings-grid__top c-bookings-grid__top--weekly\">\n <div class=\"c-bookings-grid__title\">{{ timeColumnLabel() }}</div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (slot.displayTime) {\n <span class=\"c-bookings-grid__time\">{{ slot.time }}</span>\n }\n </div>\n }\n </div>\n } @for (day of weekDays(); track day.date.getTime()) {\n <div\n class=\"c-bookings-grid__col\"\n [class.c-bookings-grid__col--weekend]=\"day.isWeekend\"\n >\n <div class=\"c-bookings-grid__top c-bookings-grid__top--weekly\">\n <div class=\"c-bookings-grid__day-header\" [class.is-today]=\"day.isToday\">\n <span class=\"c-bookings-grid__day-name\">{{ day.dayName }}</span>\n <span\n class=\"c-bookings-grid__day-number\"\n [class.is-today]=\"day.isToday\"\n >{{ day.dayNumber }}</span\n >\n </div>\n </div>\n\n @for (slot of timeSlots(); track slot.time) {\n <div class=\"c-bookings-grid__row\">\n @if (!isSlotOccupiedForDay(day.date, slot)) { @if\n (isSlotDisabledForDay(day.date, slot)) {\n <button\n class=\"c-bookings-grid__slot c-bookings-grid__slot--disabled\"\n disabled\n [title]=\"disabledSlotLabel()\"\n ></button>\n } @else {\n <button\n class=\"c-bookings-grid__slot\"\n [title]=\"emptySlotLabel()\"\n (click)=\"onWeekSlotClick(day.date, slot)\"\n ></button>\n } } @if (shouldShowEventForDay(day.date, slot)) { @let event =\n getEventForDaySlot(day.date, slot); @if (event) {\n <div\n [class]=\"getEventClasses(event)\"\n [attr.data-type]=\"event.type\"\n [attr.data-status]=\"event.status\"\n [style.--rows]=\"getEventRowSpan(event)\"\n (mouseenter)=\"onEventHover($event, event)\"\n (mouseleave)=\"onEventLeave()\"\n (click)=\"onWeekEventClick(event, day.date)\"\n >\n <p class=\"c-bookings-grid__title\">\n {{ event.subtitle || event.title }}\n </p>\n <p class=\"c-bookings-grid__text\">\n {{ event.startTime }} - {{ event.endTime }}\n </p>\n </div>\n } }\n </div>\n }\n </div>\n }\n</div>\n} @else if (viewMode() === 'month') {\n<!-- MONTHLY VIEW -->\n<div class=\"c-bookings-grid__wrapper c-bookings-grid__wrapper--monthly\">\n <!-- Header Row -->\n <div class=\"c-bookings-grid__header-row\">\n @for (day of monthDays().slice(0, 7); track day.dayName) {\n <div class=\"c-bookings-grid__header-cell\">\n {{ day.dayName }}\n </div>\n }\n </div>\n\n <!-- Days Grid -->\n <div class=\"c-bookings-grid__month-grid\">\n @for (day of monthDays(); track day.date.getTime()) {\n <div\n class=\"c-bookings-grid__month-cell\"\n [class.is-today]=\"day.isToday\"\n [class.is-weekend]=\"day.isWeekend\"\n [class.is-other-month]=\"\n day.date.getUTCMonth() !== selectedDate().getUTCMonth()\n \"\n [class.is-disabled]=\"isDayDisabled(day.date)\"\n (click)=\"!isDayDisabled(day.date) && onMonthDayClick(day.date)\"\n >\n <div class=\"c-bookings-grid__month-day-number\">\n {{ day.dayNumber }}\n </div>\n\n <div class=\"c-bookings-grid__month-events\">\n @let dayEvents = getEventsForDay(day.date); @for (event of\n dayEvents.slice(0, 3); track event.id) {\n <div\n class=\"c-bookings-grid__month-event\"\n [attr.data-type]=\"event.type\"\n [style.background-color]=\"event.metadata?.['color']\"\n [style.border-left]=\"event.metadata?.['color'] ? '3px solid ' + event.metadata?.['color'] : ''\"\n (click)=\"$event.stopPropagation(); onMonthEventClick(event, day.date)\"\n >\n <span class=\"c-bookings-grid__month-event-title\">{{\n event.title\n }}</span>\n </div>\n } @if (dayEvents.length > 3) {\n <div\n class=\"c-bookings-grid__more-events\"\n (click)=\"openDayPopover(day.date, $event)\"\n >\n {{ dayEvents.length - 3 }} m\u00E1s\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n @if (expandedDay()) {\n <div class=\"c-bookings-grid__popover-overlay\" (click)=\"closeDayPopover()\">\n <div class=\"c-bookings-grid__popover\" (click)=\"$event.stopPropagation()\">\n <div class=\"c-bookings-grid__popover-header\">\n <div class=\"c-bookings-grid__popover-date\">\n <span class=\"c-bookings-grid__popover-weekday\">{{\n expandedDay() | date : \"EEE\" : \"UTC\" : locale() | uppercase\n }}</span>\n <span class=\"c-bookings-grid__popover-daynum\">{{\n expandedDay() | date : \"d\" : \"UTC\"\n }}</span>\n </div>\n <button\n class=\"c-bookings-grid__popover-close\"\n (click)=\"closeDayPopover()\"\n >\n <span class=\"icon-cross\"></span>\n </button>\n </div>\n <div class=\"c-bookings-grid__popover-content\">\n @for (event of getExpandedDayEvents(); track event.id) {\n <div\n class=\"c-bookings-grid__month-event c-bookings-grid__month-event--popover\"\n [attr.data-type]=\"event.type\"\n [style.background-color]=\"event.metadata?.['color']\"\n [style.border-left]=\"event.metadata?.['color'] ? '3px solid ' + event.metadata?.['color'] : ''\"\n (click)=\"onMonthEventClick(event, expandedDay()!)\"\n >\n <span class=\"c-bookings-grid__month-event-title\">{{\n event.title\n }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n}\n", styles: [":host{display:block;width:100%;overflow:visible}.c-bookings-grid__month-cell.is-disabled{background-color:#f3f4f6;cursor:not-allowed;opacity:.7}.c-bookings-grid__month-cell.is-disabled:hover{background-color:#f3f4f6}.c-bookings-grid__month-cell.is-disabled .c-bookings-grid__month-day-number{color:#9ca3af}.c-bookings-grid__slot--disabled{background-color:#f3f4f6;cursor:not-allowed}.c-bookings-grid__slot--disabled:hover{background-color:#f3f4f6}\n"] }]
21362
21719
  }] });
21363
21720
 
21364
21721
  class CacheBustingInterceptor {
@@ -21642,5 +21999,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImpor
21642
21999
  * Generated bundle index. Do not edit.
21643
22000
  */
21644
22001
 
21645
- export { AD_AUTH_CONFIG, AD_AUTH_INTERCEPTOR_CONFIG, ALL_COUNTRY_CODES, ActiveFiltersComponent, AdAuthService, AdInteractionType, AdLoginButtonComponent, AgeValidationHelper, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, COMMON_COUNTRIES, CacheBustingInterceptor, CalendarEventType, CardComponent, CarouselComponent, ChatMessagePosition, ChatMessageType, CheckboxFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreManualRefreshComponent, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, CountryCode, CustomClassService, DEFAULT_AD_AUTH_INTERCEPTOR_CONFIG, DEFAULT_COUNTRIES, DEFAULT_SCHEDULER_CONFIG, DataListComponent, DataListItemComponent, DataStoreService, DateFieldComponent, DateUtility, DatetimeFieldComponent, DayState, DayType, DialogActions, DocumentAction, DocumentDisplayMode, DocumentFieldComponent, DocumentFieldValidators, DocumentPayloadMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FilePreviewActionType, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, FixedActionPosition, FixedActionsMobileModalComponent, FixedActionsMobileModalService, GalleryAnimationType, GalleryLayoutType, GalleryModalComponent, GalleryModalGlobalService, GenericButtonComponent, GenericCalendarComponent, GenericChatComponent, GenericChatService, GenericDocumentationComponent, GenericFixedActionsComponent, GenericGalleryComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSchedulerComponent, GenericSidebarComponent, GenericSkeletonComponent, GenericStepsComponent, GenericSwitchComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LATIN_AMERICA_COUNTRIES, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MODEL_REFERENCE_SORT_KEY, MainNavComponent, MainNavService, ManualRefreshService, MobileHeaderComponent, MobileResolutionService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsCustomActions, PermissionsInterceptor, PermissionsResources, PhoneFieldComponent, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, RedirectUrlService, ResetPasswordModel, RoleModel, SOUTH_AMERICA_COUNTRIES, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SkeletonAnimation, SkeletonService, SkeletonSize, SkeletonType, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableFixedActionsService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UruguayanDocumentValidationHelper, UsersModel, VERSION, WeekDay, adAuthGuard, adAuthInterceptor, adGuestGuard, adRoleGuard, ageValidator, calculateAge, equalToValidator, generateRandomUruguayanDocument, getCountryCodeStrings, getLatestBirthDateForAge, getRandomCi, getUruguayanDocumentValidationDigit, getValidationDigit, isSameDate, isValidCountryCode, provideAdAuth, provideAdAuthInterceptor, provideAdAuthWithInterceptor, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader, random, transform, transformUruguayanDocument, uruguayanDocumentValidator, validate, validateAge, validateCi, validateUruguayanDocument, validationDigit };
22002
+ export { AD_AUTH_CONFIG, AD_AUTH_INTERCEPTOR_CONFIG, ALL_COUNTRY_CODES, ActiveFiltersComponent, AdAuthService, AdInteractionType, AdLoginButtonComponent, AgeValidationHelper, AlertComponent, AlertContainerComponent, AlertService, AlertType, ApiConfigurationProvider, BaseFieldComponent, ButtonContext, ButtonSize, ButtonType, COMMON_COUNTRIES, CacheBustingInterceptor, CalendarEventType, CardComponent, CarouselComponent, ChatMessagePosition, ChatMessageType, CheckboxFieldComponent, ColorPickerFieldComponent, ConfigurationModel, ConfirmationDialogComponent, ConfirmationDialogService, CoreHostDirective, CoreManualRefreshComponent, CoreUiHttpLoaderFactory, CoreUiTranslateLoader, CoreUiTranslateService, CountryCode, CustomClassService, DEFAULT_AD_AUTH_INTERCEPTOR_CONFIG, DEFAULT_COUNTRIES, DEFAULT_SCHEDULER_CONFIG, DataListComponent, DataListItemComponent, DataStoreService, DateFieldComponent, DateUtility, DatetimeFieldComponent, DayState, DayType, DialogActions, DocumentAction, DocumentDisplayMode, DocumentFieldComponent, DocumentFieldValidators, DocumentPayloadMode, DropdownComponent, DropdownDirection, DropdownService, DynamicFieldDirective, DynamicFieldsHelper, FieldErrorsComponent, FieldType, FileFieldComponent, FileModel, FilePreviewActionType, FileTemplateModel, FileTemplateType, FileType, FileTypeModel, FileUploadService, FilterModalComponent, FilterService, FilterType, FixedActionPosition, FixedActionsMobileModalComponent, FixedActionsMobileModalService, GalleryAnimationType, GalleryLayoutType, GalleryModalComponent, GalleryModalGlobalService, GenericButtonComponent, GenericCalendarComponent, GenericChatComponent, GenericChatService, GenericDocumentationComponent, GenericFixedActionsComponent, GenericGalleryComponent, GenericModalComponent, GenericPaginationComponent, GenericRatingComponent, GenericSchedulerComponent, GenericSidebarComponent, GenericSkeletonComponent, GenericStepsComponent, GenericSwitchComponent, GenericTableComponent, GenericTabsComponent, GenericTimelineComponent, GlobalApiConfigService, HeaderComponent, HeaderConfigurationService, HeaderElementType, HeaderService, HttpLoaderFactory, ImageModalComponent, ImageModalService, ImagePreviewComponent, LATIN_AMERICA_COUNTRIES, LayoutAuth, LayoutBreakpoint, LayoutComponent, LayoutService, LayoutStateService, LayoutType, LoaderComponent, LoaderService, MODEL_REFERENCE_SORT_KEY, MainNavComponent, MainNavService, ManualRefreshService, MobileHeaderComponent, MobileResolutionService, ModalMode, ModelApiService, MultiEntryFieldComponent, MultiEntryOutputFormat, NumberFieldComponent, NumberFieldConfigType, NumberFieldType, NumberRange, PERMISSION_ACTIONS_PROVIDER, PERMISSION_PROVIDER, PERMISSION_RESOURCES_PROVIDER, PaginationService, PasswordFieldComponent, PermissionEnumsService, PermissionModel, PermissionService, PermissionWrapperService, PermissionsActions, PermissionsCustomActions, PermissionsInterceptor, PermissionsResources, PhoneFieldComponent, ProgressBarComponent, ProgressBarSize, RatingService, RatingSize, RatingType, RedirectUrlService, ResetPasswordModel, RoleModel, SOUTH_AMERICA_COUNTRIES, SelectFieldComponent, ServerSelectFieldComponent, ServerSelectService, SidebarCustomModalComponent, SidebarCustomModalService, SidebarHeight, SidebarMobileModalService, SidebarMobileType, SidebarPosition, SidebarService, SidebarState, SidebarTemplateRegistryService, SidebarVisibility, SidebarWidth, SkeletonAnimation, SkeletonService, SkeletonSize, SkeletonType, SmartFieldComponent, SortDirection, SortMode, StepSize, StepStatus, StepType, StepsService, SwitchFieldComponent, TableAction, TableActionService, TableDataService, TableFixedActionsService, TableSortService, TextAreaFieldComponent, TextFieldComponent, TimeFieldComponent, TimeInterval, TimelineService, TimelineStatus, TimelineType, TranslationMergeService, UruguayanDocumentValidationHelper, UsersModel, VERSION, WeekDay, adAuthGuard, adAuthInterceptor, adGuestGuard, adRoleGuard, ageValidator, calculateAge, equalToValidator, generateRandomUruguayanDocument, getCountryCodeStrings, getLatestBirthDateForAge, getRandomCi, getUruguayanDocumentValidationDigit, getValidationDigit, isSameDate, isValidCountryCode, provideAdAuth, provideAdAuthInterceptor, provideAdAuthWithInterceptor, provideCoreUiTranslateLoader, providePermissionActions, providePermissionEnums, providePermissionResources, providePermissionService, providePermissionServiceFactory, provideTranslateLoader, random, transform, transformUruguayanDocument, uruguayanDocumentValidator, validate, validateAge, validateCi, validateUruguayanDocument, validationDigit };
21646
22003
  //# sourceMappingURL=solcre-org-core-ui.mjs.map