@corp-products/ui-components 4.2.9 → 4.3.1

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.
@@ -10,7 +10,7 @@ import * as i1$2 from '@ngx-translate/core';
10
10
  import { TranslateModule, TranslateService, TranslatePipe } from '@ngx-translate/core';
11
11
  import * as i1$7 from '@angular/router';
12
12
  import { Router, ActivatedRoute, NavigationEnd, RouterLink, RouterOutlet, NavigationStart, RouterModule } from '@angular/router';
13
- import { filter, Subject, Subscription, BehaviorSubject, of } from 'rxjs';
13
+ import { filter, Subject, Subscription, finalize, BehaviorSubject, of } from 'rxjs';
14
14
  import * as i3 from 'primeng/badge';
15
15
  import { BadgeModule } from 'primeng/badge';
16
16
  import { Popover } from 'primeng/popover';
@@ -20,11 +20,11 @@ import * as i1$9 from 'primeng/drawer';
20
20
  import { Drawer, DrawerModule } from 'primeng/drawer';
21
21
  import * as i1$3 from 'primeng/tooltip';
22
22
  import { TooltipModule } from 'primeng/tooltip';
23
+ import * as i1$4 from '@angular/forms';
24
+ import { Validators, FormControl, ReactiveFormsModule, FormsModule, FormGroup } from '@angular/forms';
23
25
  import { AvatarModule } from 'primeng/avatar';
24
26
  import * as i1$8 from 'primeng/dynamicdialog';
25
27
  import { DynamicDialogRef, DialogService, DynamicDialogConfig, DynamicDialogModule, DynamicDialogStyle } from 'primeng/dynamicdialog';
26
- import * as i1$4 from '@angular/forms';
27
- import { Validators, FormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
28
28
  import * as i4 from 'primeng/checkbox';
29
29
  import { CheckboxModule } from 'primeng/checkbox';
30
30
  import { AutoComplete } from 'primeng/autocomplete';
@@ -344,6 +344,14 @@ const FileExtentions = [
344
344
  'ppt',
345
345
  'rar',
346
346
  ];
347
+ /** Comma-separated bare extensions (e.g. "pdf,doc") for validation */
348
+ function fileExtensionsToString(extensions = FileExtentions) {
349
+ return extensions.join(',');
350
+ }
351
+ /** Dot-prefixed extensions for HTML accept attribute (e.g. ".pdf,.doc") */
352
+ function formatFileExtensionsForAccept(extensions = FileExtentions) {
353
+ return extensions.map((ext) => (ext.startsWith('.') ? ext : `.${ext}`)).join(',');
354
+ }
347
355
 
348
356
  /**
349
357
  * Transforms file size from bytes to readable format (B, KB, MB, GB, TB).
@@ -458,46 +466,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
458
466
  }] } });
459
467
 
460
468
  class FileManagementComponent extends BaseInputComponent {
461
- // Inputs
462
469
  existingFiles = input([], ...(ngDevMode ? [{ debugName: "existingFiles" }] : []));
463
470
  acceptedTypes = input('*', ...(ngDevMode ? [{ debugName: "acceptedTypes" }] : []));
464
- maxFileSize = input(10485760, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : [])); //250 MB
471
+ maxFileSize = input(10485760, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : []));
465
472
  maxConcurrentUploads = input(3, ...(ngDevMode ? [{ debugName: "maxConcurrentUploads" }] : []));
466
473
  showTable = input(true, ...(ngDevMode ? [{ debugName: "showTable" }] : []));
467
474
  showDropZone = input(true, ...(ngDevMode ? [{ debugName: "showDropZone" }] : []));
468
475
  allowPreview = input(true, ...(ngDevMode ? [{ debugName: "allowPreview" }] : []));
469
476
  permissonKey = input('', ...(ngDevMode ? [{ debugName: "permissonKey" }] : []));
470
477
  allowedActions = input([], ...(ngDevMode ? [{ debugName: "allowedActions" }] : []));
471
- uploadedFile = signal([], ...(ngDevMode ? [{ debugName: "uploadedFile" }] : []));
472
- // Outputs
478
+ uploadFn = input(undefined, ...(ngDevMode ? [{ debugName: "uploadFn" }] : []));
473
479
  filesUploaded = new EventEmitter();
474
480
  fileDeleted = new EventEmitter();
475
481
  filePreview = new EventEmitter();
476
482
  fileDownload = new EventEmitter();
477
483
  uploadError = new EventEmitter();
478
484
  newFilesChange = new EventEmitter();
485
+ uploadStateChange = new EventEmitter();
479
486
  fileInput;
480
- // State - separate new uploads from existing files
487
+ uploadedFile = signal([], ...(ngDevMode ? [{ debugName: "uploadedFile" }] : []));
481
488
  isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
482
- newFiles = signal([], ...(ngDevMode ? [{ debugName: "newFiles" }] : [])); // Files being uploaded or newly uploaded
489
+ newFiles = signal([], ...(ngDevMode ? [{ debugName: "newFiles" }] : []));
490
+ documentId = null;
491
+ uploadErrorMessage = null;
483
492
  uploadedResponses = [];
484
- // Combined files list for the table (existing + new)
493
+ UploadStatus = UploadStatus;
494
+ _subscription = new Subscription();
495
+ progressIntervals = new Map();
485
496
  allFiles = computed(() => {
486
497
  const existing = this.existingFiles().map((f) => ({
487
498
  ...f,
488
- status: undefined, // Don't show status for existing files
499
+ status: undefined,
489
500
  isNew: false,
490
501
  }));
491
- const newOnes = this.newFiles();
492
- return [...newOnes, ...existing];
502
+ return [...this.newFiles(), ...existing];
493
503
  }, ...(ngDevMode ? [{ debugName: "allFiles" }] : []));
494
- // Get only successfully uploaded new file IDs
495
504
  uploadedNewFileIds = computed(() => {
496
505
  return this.newFiles()
497
506
  .filter((f) => f.status === UploadStatus.SUCCESS && f.id && !f.id.startsWith('temp-'))
498
507
  .map((f) => f.id);
499
508
  }, ...(ngDevMode ? [{ debugName: "uploadedNewFileIds" }] : []));
500
- // Formatted accepted file types for display
501
509
  formattedAcceptedTypes = computed(() => {
502
510
  const accepted = this.acceptedTypes();
503
511
  if (accepted === '*' || accepted === '*/*')
@@ -507,8 +515,12 @@ class FileManagementComponent extends BaseInputComponent {
507
515
  .map((type) => type.trim().replace('.', '').toUpperCase())
508
516
  .join(', ');
509
517
  }, ...(ngDevMode ? [{ debugName: "formattedAcceptedTypes" }] : []));
510
- // Table configuration
511
- // Drag & Drop handlers
518
+ ngOnDestroy() {
519
+ this._subscription.unsubscribe();
520
+ this.progressIntervals.forEach((interval) => clearInterval(interval));
521
+ this.progressIntervals.clear();
522
+ super.ngOnDestroy();
523
+ }
512
524
  onDragOver(event) {
513
525
  event.preventDefault();
514
526
  event.stopPropagation();
@@ -528,7 +540,6 @@ class FileManagementComponent extends BaseInputComponent {
528
540
  this.handleFiles(Array.from(droppedFiles));
529
541
  }
530
542
  }
531
- // Browse button handler
532
543
  onBrowseClick() {
533
544
  this.fileInput.nativeElement.click();
534
545
  }
@@ -536,97 +547,163 @@ class FileManagementComponent extends BaseInputComponent {
536
547
  const input = event.target;
537
548
  if (input.files) {
538
549
  this.handleFiles(Array.from(input.files));
539
- // Reset input to allow selecting the same file again
540
550
  input.value = '';
541
551
  }
542
552
  }
543
- // Public method to trigger file selection from parent
544
553
  triggerFileInput() {
545
554
  this.fileInput?.nativeElement?.click();
546
555
  }
547
- // Public method to append file selection from parent
548
556
  appendFileFromParent(file) {
549
557
  this.handleFiles([file]);
550
558
  }
551
- // Public method to upload files programmatically from parent
552
559
  uploadFilesFromParent(files) {
553
560
  this.handleFiles(files);
554
561
  }
555
- // Public method to get new uploaded file IDs
556
562
  getUploadedFileIds() {
557
563
  return this.uploadedNewFileIds();
558
564
  }
559
- // Public method to clear new files (after save)
560
565
  clearNewFiles() {
561
566
  this.newFiles.set([]);
562
567
  this.uploadedResponses = [];
568
+ this.uploadedFile.set([]);
569
+ this.documentId = null;
570
+ this.emitUploadState();
563
571
  }
564
- // Public method to remove a new file by ID
565
572
  removeNewFile(fileId) {
566
573
  this.newFiles.update((files) => files.filter((f) => f.id !== fileId));
567
574
  }
568
- // Check if there are pending/uploading files
569
- // File handling
575
+ deleteFile() {
576
+ this.uploadedFile.set([]);
577
+ this.newFiles.set([]);
578
+ this.documentId = null;
579
+ this.uploadErrorMessage = null;
580
+ this.control?.reset();
581
+ this.filesUploaded.emit([]);
582
+ this.fileDeleted.emit({ fileId: this.documentId || '', isNew: true });
583
+ this.emitUploadState();
584
+ }
585
+ onDeleteFile(file) {
586
+ const isNewFile = file.isNew;
587
+ this.fileDeleted.emit({ fileId: file.id, isNew: !!isNewFile });
588
+ if (isNewFile) {
589
+ this.newFiles.update((files) => files.filter((f) => f.id !== file.id));
590
+ if (!this.newFiles().length) {
591
+ this.documentId = null;
592
+ this.control?.reset();
593
+ this.emitUploadState();
594
+ }
595
+ }
596
+ }
597
+ onPreviewFile(file) {
598
+ this.filePreview.emit(file);
599
+ }
570
600
  handleFiles(filesToProcess) {
571
601
  const validFiles = [];
572
602
  for (const file of filesToProcess) {
573
- // Validate file size
574
603
  if (file.size > this.maxFileSize()) {
575
- this.uploadError.emit({
576
- file,
577
- error: `File ${file.name} exceeds maximum size of ${this.formatFileSize(this.maxFileSize())}`,
578
- });
604
+ const error = `File ${file.name} exceeds maximum size of ${this.formatFileSize(this.maxFileSize())}`;
605
+ this.uploadErrorMessage = error;
606
+ this.uploadError.emit({ file, error });
607
+ continue;
608
+ }
609
+ if (!this.isValidFileType(file)) {
610
+ const error = `File type not allowed: ${file.type}`;
611
+ this.uploadErrorMessage = error;
612
+ this.uploadError.emit({ file, error });
579
613
  continue;
580
614
  }
581
- // Validate file type
582
- // if (!this.isValidFileType(file)) {
583
- // this.uploadError.emit({
584
- // file,
585
- // error: `File type not allowed: ${file.type}`,
586
- // });
587
- // continue;
588
- // }
589
615
  validFiles.push(file);
590
616
  }
591
- if (validFiles.length > 0) {
592
- // this.uploadFiles(validFiles);
593
- this.uploadedFile.set(validFiles);
594
- this.filesUploaded.emit(validFiles);
595
- console.log('uploadedFile', this.uploadedFile());
617
+ if (!validFiles.length)
618
+ return;
619
+ if (this.uploadFn()) {
620
+ this.uploadFileImmediately(validFiles[0]);
621
+ return;
596
622
  }
623
+ this.uploadedFile.set(validFiles);
624
+ this.filesUploaded.emit(validFiles);
597
625
  }
598
- deleteFile() {
599
- this.uploadedFile.set([]);
600
- this.filesUploaded.emit([]);
601
- }
602
- isValidFileType(file) {
603
- const accepted = this.acceptedTypes();
604
- if (accepted === '*' || accepted === '*/*')
605
- return true;
606
- const acceptedTypes = accepted.split(',').map((t) => t.trim().toLowerCase());
607
- const fileType = file.type.toLowerCase();
608
- const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();
609
- return acceptedTypes.some((type) => {
610
- if (type.startsWith('.')) {
611
- return fileExt === type;
612
- }
613
- if (type.endsWith('/*')) {
614
- return fileType.startsWith(type.replace('/*', '/'));
626
+ uploadFileImmediately(file) {
627
+ const uploadFn = this.uploadFn();
628
+ if (!uploadFn)
629
+ return;
630
+ const tempId = this.generateTempId(file);
631
+ const fileItem = {
632
+ id: tempId,
633
+ fileName: file.name,
634
+ size: file.size,
635
+ mimeType: file.type,
636
+ progress: 0,
637
+ status: UploadStatus.UPLOADING,
638
+ file,
639
+ isNew: true,
640
+ };
641
+ this.uploadErrorMessage = null;
642
+ this.documentId = null;
643
+ this.newFiles.set([fileItem]);
644
+ this.uploadedFile.set([file]);
645
+ this.emitUploadState();
646
+ const progressInterval = setInterval(() => {
647
+ this.newFiles.update((files) => files.map((f) => f.id === tempId && (f.progress ?? 0) < 90
648
+ ? { ...f, progress: (f.progress ?? 0) + 10 }
649
+ : f));
650
+ }, 200);
651
+ this.progressIntervals.set(tempId, progressInterval);
652
+ this._subscription.add(uploadFn(file)
653
+ .pipe(finalize(() => {
654
+ const interval = this.progressIntervals.get(tempId);
655
+ if (interval) {
656
+ clearInterval(interval);
657
+ this.progressIntervals.delete(tempId);
615
658
  }
616
- return fileType === type;
659
+ }))
660
+ .subscribe({
661
+ next: (response) => {
662
+ this.documentId = response.documentId;
663
+ this.newFiles.set([
664
+ {
665
+ ...fileItem,
666
+ id: response.documentId,
667
+ progress: 100,
668
+ status: UploadStatus.SUCCESS,
669
+ },
670
+ ]);
671
+ this.control?.setValue(response.documentId);
672
+ this.filesUploaded.emit(response);
673
+ this.emitUploadState();
674
+ },
675
+ error: (error) => {
676
+ this.uploadErrorMessage = error?.message || 'Upload failed. Please try again.';
677
+ this.newFiles.set([
678
+ {
679
+ ...fileItem,
680
+ progress: 0,
681
+ status: UploadStatus.FAILED,
682
+ error: this.uploadErrorMessage ?? undefined,
683
+ },
684
+ ]);
685
+ this.uploadedFile.set([]);
686
+ this.emitUploadState();
687
+ },
688
+ }));
689
+ }
690
+ emitUploadState() {
691
+ const isUploading = this.newFiles().some((f) => f.status === UploadStatus.UPLOADING);
692
+ this.uploadStateChange.emit({
693
+ isUploading,
694
+ documentId: this.documentId,
695
+ hasFile: !!this.documentId || this.uploadedFile().length > 0,
617
696
  });
618
697
  }
619
698
  updateFileFromAttachment(attachment) {
620
699
  this.newFiles.update((currentFiles) => {
621
700
  return currentFiles.map((file) => {
622
- // Match by file name and size
623
701
  if (file.fileName === attachment.nameFile && file.size === attachment.size) {
624
702
  const updatedFile = {
625
703
  ...file,
626
704
  progress: attachment.status?.percentage ?? 0,
627
705
  error: attachment.errorMessage,
628
706
  };
629
- // If upload succeeded, update with response data from serverResponse
630
707
  if (attachment.uploadStatus === UploadStatus.SUCCESS && attachment.serverResponse) {
631
708
  const serverData = attachment.serverResponse;
632
709
  const responseFile = {
@@ -647,20 +724,26 @@ class FileManagementComponent extends BaseInputComponent {
647
724
  });
648
725
  });
649
726
  }
650
- // Actions
651
- onDeleteFile(file) {
652
- const isNewFile = file.isNew;
653
- this.fileDeleted.emit({ fileId: file.id, isNew: !!isNewFile });
654
- if (isNewFile) {
655
- // Remove from newFiles list immediately for new uploads
656
- this.newFiles.update((files) => files.filter((f) => f.id !== file.id));
657
- }
658
- }
659
- onPreviewFile(file) {
660
- this.filePreview.emit(file);
661
- }
662
- removeFileFromList(fileId) {
663
- this.newFiles.update((current) => current.filter((f) => f.id !== fileId));
727
+ isValidFileType(file) {
728
+ const accepted = this.acceptedTypes();
729
+ if (accepted === '*' || accepted === '*/*')
730
+ return true;
731
+ const acceptedTypes = accepted.split(',').map((t) => t.trim().toLowerCase());
732
+ const fileType = file.type.toLowerCase();
733
+ const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();
734
+ return acceptedTypes.some((type) => {
735
+ if (type.startsWith('.')) {
736
+ return fileExt === type;
737
+ }
738
+ if (type.endsWith('/*')) {
739
+ return fileType.startsWith(type.replace('/*', '/'));
740
+ }
741
+ // bare extension without dot (e.g. "pdf" from FileExtentions.join)
742
+ if (!type.includes('/')) {
743
+ return fileExt === `.${type}`;
744
+ }
745
+ return fileType === type;
746
+ });
664
747
  }
665
748
  generateTempId(file) {
666
749
  return `temp-${file.name}-${file.size}-${Date.now()}`;
@@ -674,12 +757,12 @@ class FileManagementComponent extends BaseInputComponent {
674
757
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
675
758
  }
676
759
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileManagementComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
677
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FileManagementComponent, isStandalone: true, selector: "app-file-management", inputs: { existingFiles: { classPropertyName: "existingFiles", publicName: "existingFiles", isSignal: true, isRequired: false, transformFunction: null }, acceptedTypes: { classPropertyName: "acceptedTypes", publicName: "acceptedTypes", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxConcurrentUploads: { classPropertyName: "maxConcurrentUploads", publicName: "maxConcurrentUploads", isSignal: true, isRequired: false, transformFunction: null }, showTable: { classPropertyName: "showTable", publicName: "showTable", isSignal: true, isRequired: false, transformFunction: null }, showDropZone: { classPropertyName: "showDropZone", publicName: "showDropZone", isSignal: true, isRequired: false, transformFunction: null }, allowPreview: { classPropertyName: "allowPreview", publicName: "allowPreview", isSignal: true, isRequired: false, transformFunction: null }, permissonKey: { classPropertyName: "permissonKey", publicName: "permissonKey", isSignal: true, isRequired: false, transformFunction: null }, allowedActions: { classPropertyName: "allowedActions", publicName: "allowedActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesUploaded: "filesUploaded", fileDeleted: "fileDeleted", filePreview: "filePreview", fileDownload: "fileDownload", uploadError: "uploadError", newFilesChange: "newFilesChange" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"file-management\">\r\n <!-- Drop Zone -->\r\n @if (showDropZone()) {\r\n <div\r\n class=\"drop-zone upload-container\"\r\n [class.drag-over]=\"isDragOver()\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n >\r\n <div class=\"drop-zone-content\">\r\n <p class=\"drop-text\">{{ 'file.drag_drop_files' | translate }}</p>\r\n <p-button\r\n [label]=\"'file.browse' | translate\"\r\n severity=\"danger\"\r\n [outlined]=\"true\"\r\n (onClick)=\"onBrowseClick()\"\r\n />\r\n <p class=\"drop-hint text-xs text-gray-500 mt-2\">\r\n {{ 'file.max_size_hint' | translate }}: {{ maxFileSize() | fileSize: 2 : 'MB' }}\r\n </p>\r\n @if (formattedAcceptedTypes()) {\r\n <p class=\"accepted-types text-xs text-gray-400\">\r\n {{ 'file.accepted_types' | translate }}: {{ formattedAcceptedTypes() }}\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Hidden file input (always present for programmatic access) -->\r\n <input\r\n #fileInput\r\n type=\"file\"\r\n [accept]=\"acceptedTypes()\"\r\n multiple\r\n hidden\r\n (change)=\"onFileInputChange($event)\"\r\n />\r\n\r\n @if(uploadedFile().length) {\r\n @for(file of uploadedFile() ; track file) {\r\n <div class=\"uploaded-files \" >\r\n <p>{{file.name}}</p>\r\n <i class=\"pi pi-trash\" style=\"font-size: 1.5rem; color: #f00\" (click)=\"deleteFile()\"></i>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Files Table -->\r\n\r\n</div>\r\n", styles: [".file-management{width:100%}.drop-zone{@apply cursor-pointer rounded-l border-2 border-dashed border-gray-300 p-8 bg-purple-light3 text-center transition-all duration-200 ease-in-out;}.drop-zone.drag-over{@apply border-purple-200 bg-purple-light;}.drop-zone-content{@apply flex flex-col items-center gap-2;}.drop-icon{font-size:3rem;color:var(--gray-400, #9ca3af);margin-bottom:.5rem}.drop-text{font-size:1rem;color:var(--gray-700, #374151);margin:0}.drop-or{font-size:.875rem;color:var(--gray-500, #6b7280);margin:.25rem 0}.drop-hint{margin-top:.75rem}.files-table{border:1px solid var(--gray-200, #e5e7eb);border-radius:8px;overflow:hidden}:host-context([dir=rtl]) .drop-zone-content{direction:rtl}.uploaded-files{background-color:#f3f3f7;border:1px solid #DFE0E6;display:flex;justify-content:space-between;align-items:center;padding:15px;margin-bottom:10px}.uploaded-files .pi-trash{cursor:pointer}.uploaded-files p{margin-block-start:0;margin-block-end:0}.upload-container{background-color:#f3f3f7;padding:15px;border:1px dashed #DFE0E6;margin-bottom:15px;display:flex;justify-content:center;align-items:center;border-radius:2px}.upload-container .drop-zone-content{display:flex;align-items:center;flex-direction:column}.upload-container .drop-zone-content .drop-text{margin-bottom:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FileSizePipe, name: "fileSize" }] });
760
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FileManagementComponent, isStandalone: true, selector: "app-file-management", inputs: { existingFiles: { classPropertyName: "existingFiles", publicName: "existingFiles", isSignal: true, isRequired: false, transformFunction: null }, acceptedTypes: { classPropertyName: "acceptedTypes", publicName: "acceptedTypes", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxConcurrentUploads: { classPropertyName: "maxConcurrentUploads", publicName: "maxConcurrentUploads", isSignal: true, isRequired: false, transformFunction: null }, showTable: { classPropertyName: "showTable", publicName: "showTable", isSignal: true, isRequired: false, transformFunction: null }, showDropZone: { classPropertyName: "showDropZone", publicName: "showDropZone", isSignal: true, isRequired: false, transformFunction: null }, allowPreview: { classPropertyName: "allowPreview", publicName: "allowPreview", isSignal: true, isRequired: false, transformFunction: null }, permissonKey: { classPropertyName: "permissonKey", publicName: "permissonKey", isSignal: true, isRequired: false, transformFunction: null }, allowedActions: { classPropertyName: "allowedActions", publicName: "allowedActions", isSignal: true, isRequired: false, transformFunction: null }, uploadFn: { classPropertyName: "uploadFn", publicName: "uploadFn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesUploaded: "filesUploaded", fileDeleted: "fileDeleted", filePreview: "filePreview", fileDownload: "fileDownload", uploadError: "uploadError", newFilesChange: "newFilesChange", uploadStateChange: "uploadStateChange" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"file-management\">\r\n @if (showDropZone()) {\r\n <div\r\n class=\"drop-zone upload-container\"\r\n [class.drag-over]=\"isDragOver()\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n >\r\n <div class=\"drop-zone-content\">\r\n <p class=\"drop-text\">{{ 'file.drag_drop_files' | translate }}</p>\r\n <p-button\r\n [label]=\"'file.browse' | translate\"\r\n severity=\"danger\"\r\n [outlined]=\"true\"\r\n (onClick)=\"onBrowseClick()\"\r\n />\r\n <p class=\"drop-hint text-xs text-gray-500 mt-2\">\r\n {{ 'file.max_size_hint' | translate }}: {{ maxFileSize() | fileSize: 2 : 'MB' }}\r\n </p>\r\n @if (formattedAcceptedTypes()) {\r\n <p class=\"accepted-types text-xs text-gray-400\">\r\n {{ 'file.accepted_types' | translate }}: {{ formattedAcceptedTypes() }}\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <input\r\n #fileInput\r\n type=\"file\"\r\n [accept]=\"acceptedTypes()\"\r\n [multiple]=\"!uploadFn()\"\r\n hidden\r\n (change)=\"onFileInputChange($event)\"\r\n />\r\n\r\n @for (file of newFiles(); track file.id) {\r\n <div class=\"uploaded-files\">\r\n <div class=\"file-details\">\r\n <p class=\"file-name\">{{ file.fileName }}</p>\r\n @if (file.status === UploadStatus.UPLOADING) {\r\n <span class=\"upload-percentage\">{{ file.progress ?? 0 }}%</span>\r\n } @else if (file.status === UploadStatus.SUCCESS) {\r\n <i class=\"pi pi-check-circle success-icon\"></i>\r\n } @else if (file.status === UploadStatus.FAILED) {\r\n <span class=\"upload-error-text\">{{ file.error }}</span>\r\n }\r\n </div>\r\n <i\r\n class=\"pi pi-trash delete-icon\"\r\n [class.disabled]=\"file.status === UploadStatus.UPLOADING\"\r\n (click)=\"file.status !== UploadStatus.UPLOADING && onDeleteFile(file)\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n @if (!uploadFn() && uploadedFile().length) {\r\n @for (file of uploadedFile(); track file.name) {\r\n <div class=\"uploaded-files\">\r\n <p>{{ file.name }}</p>\r\n <i class=\"pi pi-trash delete-icon\" (click)=\"deleteFile()\"></i>\r\n </div>\r\n }\r\n }\r\n\r\n @if (uploadErrorMessage) {\r\n <div class=\"upload-error\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n <span>{{ uploadErrorMessage }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".file-management{width:100%}.drop-zone{@apply cursor-pointer rounded-l border-2 border-dashed border-gray-300 p-8 bg-purple-light3 text-center transition-all duration-200 ease-in-out;}.drop-zone.drag-over{@apply border-purple-200 bg-purple-light;}.drop-zone-content{@apply flex flex-col items-center gap-2;}.drop-icon{font-size:3rem;color:var(--gray-400, #9ca3af);margin-bottom:.5rem}.drop-text{font-size:1rem;color:var(--gray-700, #374151);margin:0}.drop-or{font-size:.875rem;color:var(--gray-500, #6b7280);margin:.25rem 0}.drop-hint{margin-top:.75rem}.files-table{border:1px solid var(--gray-200, #e5e7eb);border-radius:8px;overflow:hidden}:host-context([dir=rtl]) .drop-zone-content{direction:rtl}.upload-container{background-color:#f3f3f7;padding:15px;border:1px dashed #DFE0E6;margin-bottom:15px;display:flex;justify-content:center;align-items:center;border-radius:2px}.upload-container .drop-zone-content{display:flex;align-items:center;flex-direction:column}.upload-container .drop-zone-content .drop-text{margin-bottom:10px}.uploaded-files{background-color:#f3f3f7;border:1px solid #DFE0E6;display:flex;justify-content:space-between;align-items:center;padding:15px;margin-bottom:10px}.uploaded-files .file-details{display:flex;flex-direction:column;gap:.25rem;flex:1;min-width:0}.uploaded-files .file-name{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uploaded-files .upload-percentage{font-size:.875rem;font-weight:500;color:var(--primary-color, #3b82f6)}.uploaded-files .success-icon{color:#22c55e;font-size:1.25rem}.uploaded-files .upload-error-text{color:#ef4444;font-size:.875rem}.uploaded-files .delete-icon{cursor:pointer;font-size:1.5rem;color:red;flex-shrink:0}.uploaded-files .delete-icon.disabled{opacity:.5;cursor:not-allowed}.upload-error{display:flex;align-items:center;gap:.5rem;color:#ef4444;font-size:.875rem;margin-top:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FileSizePipe, name: "fileSize" }] });
678
761
  }
679
762
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileManagementComponent, decorators: [{
680
763
  type: Component,
681
- args: [{ selector: 'app-file-management', imports: [CommonModule, TranslatePipe, ButtonModule, TooltipModule, FileSizePipe], template: "<div class=\"file-management\">\r\n <!-- Drop Zone -->\r\n @if (showDropZone()) {\r\n <div\r\n class=\"drop-zone upload-container\"\r\n [class.drag-over]=\"isDragOver()\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n >\r\n <div class=\"drop-zone-content\">\r\n <p class=\"drop-text\">{{ 'file.drag_drop_files' | translate }}</p>\r\n <p-button\r\n [label]=\"'file.browse' | translate\"\r\n severity=\"danger\"\r\n [outlined]=\"true\"\r\n (onClick)=\"onBrowseClick()\"\r\n />\r\n <p class=\"drop-hint text-xs text-gray-500 mt-2\">\r\n {{ 'file.max_size_hint' | translate }}: {{ maxFileSize() | fileSize: 2 : 'MB' }}\r\n </p>\r\n @if (formattedAcceptedTypes()) {\r\n <p class=\"accepted-types text-xs text-gray-400\">\r\n {{ 'file.accepted_types' | translate }}: {{ formattedAcceptedTypes() }}\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Hidden file input (always present for programmatic access) -->\r\n <input\r\n #fileInput\r\n type=\"file\"\r\n [accept]=\"acceptedTypes()\"\r\n multiple\r\n hidden\r\n (change)=\"onFileInputChange($event)\"\r\n />\r\n\r\n @if(uploadedFile().length) {\r\n @for(file of uploadedFile() ; track file) {\r\n <div class=\"uploaded-files \" >\r\n <p>{{file.name}}</p>\r\n <i class=\"pi pi-trash\" style=\"font-size: 1.5rem; color: #f00\" (click)=\"deleteFile()\"></i>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Files Table -->\r\n\r\n</div>\r\n", styles: [".file-management{width:100%}.drop-zone{@apply cursor-pointer rounded-l border-2 border-dashed border-gray-300 p-8 bg-purple-light3 text-center transition-all duration-200 ease-in-out;}.drop-zone.drag-over{@apply border-purple-200 bg-purple-light;}.drop-zone-content{@apply flex flex-col items-center gap-2;}.drop-icon{font-size:3rem;color:var(--gray-400, #9ca3af);margin-bottom:.5rem}.drop-text{font-size:1rem;color:var(--gray-700, #374151);margin:0}.drop-or{font-size:.875rem;color:var(--gray-500, #6b7280);margin:.25rem 0}.drop-hint{margin-top:.75rem}.files-table{border:1px solid var(--gray-200, #e5e7eb);border-radius:8px;overflow:hidden}:host-context([dir=rtl]) .drop-zone-content{direction:rtl}.uploaded-files{background-color:#f3f3f7;border:1px solid #DFE0E6;display:flex;justify-content:space-between;align-items:center;padding:15px;margin-bottom:10px}.uploaded-files .pi-trash{cursor:pointer}.uploaded-files p{margin-block-start:0;margin-block-end:0}.upload-container{background-color:#f3f3f7;padding:15px;border:1px dashed #DFE0E6;margin-bottom:15px;display:flex;justify-content:center;align-items:center;border-radius:2px}.upload-container .drop-zone-content{display:flex;align-items:center;flex-direction:column}.upload-container .drop-zone-content .drop-text{margin-bottom:10px}\n"] }]
682
- }], propDecorators: { existingFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFiles", required: false }] }], acceptedTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptedTypes", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxConcurrentUploads: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxConcurrentUploads", required: false }] }], showTable: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTable", required: false }] }], showDropZone: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropZone", required: false }] }], allowPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowPreview", required: false }] }], permissonKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissonKey", required: false }] }], allowedActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedActions", required: false }] }], filesUploaded: [{
764
+ args: [{ selector: 'app-file-management', imports: [CommonModule, TranslatePipe, ButtonModule, TooltipModule, FileSizePipe], template: "<div class=\"file-management\">\r\n @if (showDropZone()) {\r\n <div\r\n class=\"drop-zone upload-container\"\r\n [class.drag-over]=\"isDragOver()\"\r\n (dragover)=\"onDragOver($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n (drop)=\"onDrop($event)\"\r\n >\r\n <div class=\"drop-zone-content\">\r\n <p class=\"drop-text\">{{ 'file.drag_drop_files' | translate }}</p>\r\n <p-button\r\n [label]=\"'file.browse' | translate\"\r\n severity=\"danger\"\r\n [outlined]=\"true\"\r\n (onClick)=\"onBrowseClick()\"\r\n />\r\n <p class=\"drop-hint text-xs text-gray-500 mt-2\">\r\n {{ 'file.max_size_hint' | translate }}: {{ maxFileSize() | fileSize: 2 : 'MB' }}\r\n </p>\r\n @if (formattedAcceptedTypes()) {\r\n <p class=\"accepted-types text-xs text-gray-400\">\r\n {{ 'file.accepted_types' | translate }}: {{ formattedAcceptedTypes() }}\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <input\r\n #fileInput\r\n type=\"file\"\r\n [accept]=\"acceptedTypes()\"\r\n [multiple]=\"!uploadFn()\"\r\n hidden\r\n (change)=\"onFileInputChange($event)\"\r\n />\r\n\r\n @for (file of newFiles(); track file.id) {\r\n <div class=\"uploaded-files\">\r\n <div class=\"file-details\">\r\n <p class=\"file-name\">{{ file.fileName }}</p>\r\n @if (file.status === UploadStatus.UPLOADING) {\r\n <span class=\"upload-percentage\">{{ file.progress ?? 0 }}%</span>\r\n } @else if (file.status === UploadStatus.SUCCESS) {\r\n <i class=\"pi pi-check-circle success-icon\"></i>\r\n } @else if (file.status === UploadStatus.FAILED) {\r\n <span class=\"upload-error-text\">{{ file.error }}</span>\r\n }\r\n </div>\r\n <i\r\n class=\"pi pi-trash delete-icon\"\r\n [class.disabled]=\"file.status === UploadStatus.UPLOADING\"\r\n (click)=\"file.status !== UploadStatus.UPLOADING && onDeleteFile(file)\"\r\n ></i>\r\n </div>\r\n }\r\n\r\n @if (!uploadFn() && uploadedFile().length) {\r\n @for (file of uploadedFile(); track file.name) {\r\n <div class=\"uploaded-files\">\r\n <p>{{ file.name }}</p>\r\n <i class=\"pi pi-trash delete-icon\" (click)=\"deleteFile()\"></i>\r\n </div>\r\n }\r\n }\r\n\r\n @if (uploadErrorMessage) {\r\n <div class=\"upload-error\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n <span>{{ uploadErrorMessage }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".file-management{width:100%}.drop-zone{@apply cursor-pointer rounded-l border-2 border-dashed border-gray-300 p-8 bg-purple-light3 text-center transition-all duration-200 ease-in-out;}.drop-zone.drag-over{@apply border-purple-200 bg-purple-light;}.drop-zone-content{@apply flex flex-col items-center gap-2;}.drop-icon{font-size:3rem;color:var(--gray-400, #9ca3af);margin-bottom:.5rem}.drop-text{font-size:1rem;color:var(--gray-700, #374151);margin:0}.drop-or{font-size:.875rem;color:var(--gray-500, #6b7280);margin:.25rem 0}.drop-hint{margin-top:.75rem}.files-table{border:1px solid var(--gray-200, #e5e7eb);border-radius:8px;overflow:hidden}:host-context([dir=rtl]) .drop-zone-content{direction:rtl}.upload-container{background-color:#f3f3f7;padding:15px;border:1px dashed #DFE0E6;margin-bottom:15px;display:flex;justify-content:center;align-items:center;border-radius:2px}.upload-container .drop-zone-content{display:flex;align-items:center;flex-direction:column}.upload-container .drop-zone-content .drop-text{margin-bottom:10px}.uploaded-files{background-color:#f3f3f7;border:1px solid #DFE0E6;display:flex;justify-content:space-between;align-items:center;padding:15px;margin-bottom:10px}.uploaded-files .file-details{display:flex;flex-direction:column;gap:.25rem;flex:1;min-width:0}.uploaded-files .file-name{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uploaded-files .upload-percentage{font-size:.875rem;font-weight:500;color:var(--primary-color, #3b82f6)}.uploaded-files .success-icon{color:#22c55e;font-size:1.25rem}.uploaded-files .upload-error-text{color:#ef4444;font-size:.875rem}.uploaded-files .delete-icon{cursor:pointer;font-size:1.5rem;color:red;flex-shrink:0}.uploaded-files .delete-icon.disabled{opacity:.5;cursor:not-allowed}.upload-error{display:flex;align-items:center;gap:.5rem;color:#ef4444;font-size:.875rem;margin-top:.5rem}\n"] }]
765
+ }], propDecorators: { existingFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFiles", required: false }] }], acceptedTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptedTypes", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxConcurrentUploads: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxConcurrentUploads", required: false }] }], showTable: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTable", required: false }] }], showDropZone: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDropZone", required: false }] }], allowPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowPreview", required: false }] }], permissonKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissonKey", required: false }] }], allowedActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedActions", required: false }] }], uploadFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadFn", required: false }] }], filesUploaded: [{
683
766
  type: Output
684
767
  }], fileDeleted: [{
685
768
  type: Output
@@ -691,6 +774,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
691
774
  type: Output
692
775
  }], newFilesChange: [{
693
776
  type: Output
777
+ }], uploadStateChange: [{
778
+ type: Output
694
779
  }], fileInput: [{
695
780
  type: ViewChild,
696
781
  args: ['fileInput']
@@ -1625,6 +1710,7 @@ class HijriCalendarComponent {
1625
1710
  cdr;
1626
1711
  model;
1627
1712
  disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
1713
+ disabledDates = [];
1628
1714
  dateSelected = new EventEmitter();
1629
1715
  language = 'en';
1630
1716
  renderer = inject(Renderer2);
@@ -1661,14 +1747,20 @@ class HijriCalendarComponent {
1661
1747
  date.day === today.day;
1662
1748
  }
1663
1749
  isDisabled = (date) => {
1664
- if (!this.disabledDays || this.disabledDays.length === 0)
1665
- return false;
1666
1750
  const ngbDate = new NgbDate(date.year, date.month, date.day);
1667
1751
  const gregDate = this.calendar.toGregorian(ngbDate);
1668
- return this.disabledDays.includes(gregDate.getDay());
1752
+ if (this.disabledDays?.length && this.disabledDays.includes(gregDate.getDay())) {
1753
+ return true;
1754
+ }
1755
+ if (this.disabledDates?.length) {
1756
+ return this.disabledDates.some((d) => d.getFullYear() === gregDate.getFullYear() &&
1757
+ d.getMonth() === gregDate.getMonth() &&
1758
+ d.getDate() === gregDate.getDate());
1759
+ }
1760
+ return false;
1669
1761
  };
1670
1762
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriCalendarComponent, deps: [{ token: i1$6.NgbDatepickerI18n }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1671
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: HijriCalendarComponent, isStandalone: true, selector: "app-hijri-calendar", inputs: { model: "model", disabledDays: "disabledDays", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1763
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: HijriCalendarComponent, isStandalone: true, selector: "app-hijri-calendar", inputs: { model: "model", disabledDays: "disabledDays", disabledDates: "disabledDates", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1672
1764
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura },
1673
1765
  { provide: NgbDatepickerI18n, useClass: DynamicHijriI18n }
1674
1766
  ], usesOnChanges: true, ngImport: i0, template: "<ngb-datepicker #dp [class.rtl]=\"language === 'ar'\" [class.ltr]=\"language === 'en'\" [ngModel]=\"model\"\r\n [startDate]=\"startDate\" (ngModelChange)=\"onDateChange($event)\" (dateSelect)=\"dateSelected.emit($event)\"\r\n [dayTemplate]=\"dayTemplate\" [markDisabled]=\"isDisabled\">\r\n</ngb-datepicker>\r\n<ng-template #dayTemplate let-date let-currentMonth=\"currentMonth\" let-selected=\"selected\" let-disabled=\"disabled\">\r\n <span class=\"custom-day\" [class.today]=\"isToday(date)\" [class.selected]=\"selected\"\r\n [class.outside]=\"date.month !== currentMonth\" [class.disabled]=\"disabled\">\r\n {{ date.day }}\r\n </span>\r\n</ng-template>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: NgbDatepickerModule }, { kind: "component", type: i1$6.NgbDatepicker, selector: "ngb-datepicker", inputs: ["contentTemplate", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "maxDate", "minDate", "navigation", "outsideDays", "showWeekNumbers", "startDate", "weekdays"], outputs: ["navigate", "dateSelect"], exportAs: ["ngbDatepicker"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
@@ -1683,6 +1775,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1683
1775
  type: Input
1684
1776
  }], disabledDays: [{
1685
1777
  type: Input
1778
+ }], disabledDates: [{
1779
+ type: Input
1686
1780
  }], dateSelected: [{
1687
1781
  type: Output
1688
1782
  }], language: [{
@@ -1796,6 +1890,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1796
1890
  class GregorianCalendarComponent {
1797
1891
  model;
1798
1892
  disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
1893
+ disabledDates = [];
1799
1894
  dateSelected = new EventEmitter();
1800
1895
  renderer = inject(Renderer2);
1801
1896
  language = 'en';
@@ -1830,13 +1925,21 @@ class GregorianCalendarComponent {
1830
1925
  date.day === today.day;
1831
1926
  }
1832
1927
  isDisabled = (date) => {
1833
- if (!this.disabledDays || this.disabledDays.length === 0)
1834
- return false;
1835
- const jsDate = new Date(date.year, date.month - 1, date.day);
1836
- return this.disabledDays.includes(jsDate.getDay());
1928
+ if (this.disabledDays?.length) {
1929
+ const jsDate = new Date(date.year, date.month - 1, date.day);
1930
+ if (this.disabledDays.includes(jsDate.getDay())) {
1931
+ return true;
1932
+ }
1933
+ }
1934
+ if (this.disabledDates?.length) {
1935
+ return this.disabledDates.some((d) => d.getFullYear() === date.year &&
1936
+ d.getMonth() + 1 === date.month &&
1937
+ d.getDate() === date.day);
1938
+ }
1939
+ return false;
1837
1940
  };
1838
1941
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GregorianCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1839
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: GregorianCalendarComponent, isStandalone: true, selector: "app-gregorian-calendar", inputs: { model: "model", disabledDays: "disabledDays", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1942
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: GregorianCalendarComponent, isStandalone: true, selector: "app-gregorian-calendar", inputs: { model: "model", disabledDays: "disabledDays", disabledDates: "disabledDates", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1840
1943
  { provide: NgbCalendar, useClass: NgbCalendarGregorian },
1841
1944
  { provide: NgbDatepickerI18n, useClass: DynamicGregorianI18n }
1842
1945
  ], usesOnChanges: true, ngImport: i0, template: "@for(item of [calendarKey]; track item) {\r\n <ngb-datepicker #dp\r\n [class.rtl]=\"language === 'ar'\"\r\n [class.ltr]=\"language === 'en'\"\r\n [ngModel]=\"model\"\r\n [startDate]=\"startDate\"\r\n (ngModelChange)=\"onDateChange($event)\"\r\n (dateSelect)=\"dateSelected.emit($event)\"\r\n [dayTemplate]=\"dayTemplate\"\r\n [markDisabled]=\"isDisabled\">\r\n </ngb-datepicker>\r\n <ng-template #dayTemplate let-date let-currentMonth=\"currentMonth\" let-selected=\"selected\" let-disabled=\"disabled\">\r\n <span class=\"custom-day\"\r\n [class.today]=\"isToday(date)\"\r\n [class.selected]=\"selected\"\r\n [class.outside]=\"date.month !== currentMonth\"\r\n [class.disabled]=\"disabled\">\r\n {{ date.day }}\r\n </span>\r\n </ng-template>\r\n}\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: NgbDatepickerModule }, { kind: "component", type: i1$6.NgbDatepicker, selector: "ngb-datepicker", inputs: ["contentTemplate", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "maxDate", "minDate", "navigation", "outsideDays", "showWeekNumbers", "startDate", "weekdays"], outputs: ["navigate", "dateSelect"], exportAs: ["ngbDatepicker"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], encapsulation: i0.ViewEncapsulation.None });
@@ -1851,6 +1954,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1851
1954
  type: Input
1852
1955
  }], disabledDays: [{
1853
1956
  type: Input
1957
+ }], disabledDates: [{
1958
+ type: Input
1854
1959
  }], dateSelected: [{
1855
1960
  type: Output
1856
1961
  }], language: [{
@@ -1953,6 +2058,7 @@ class DualCalendarComponent {
1953
2058
  hijriModel;
1954
2059
  currentLang = signal('ar', ...(ngDevMode ? [{ debugName: "currentLang" }] : []));
1955
2060
  disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
2061
+ disabledDates = [];
1956
2062
  gregorianUTC = new EventEmitter();
1957
2063
  onClose = new EventEmitter();
1958
2064
  gregorianUTCValue = '';
@@ -2125,9 +2231,9 @@ class DualCalendarComponent {
2125
2231
  }
2126
2232
  }
2127
2233
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DualCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2128
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DualCalendarComponent, isStandalone: true, selector: "app-dual-calendar", inputs: { control: "control", label: "label", name: "name", withTime: "withTime", isDatePickerShow: "isDatePickerShow", currentLang: "currentLang", disabledDays: "disabledDays", isShown: "isShown", appedToBody: "appedToBody" }, outputs: { gregorianUTC: "gregorianUTC", onClose: "onClose" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
2234
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DualCalendarComponent, isStandalone: true, selector: "app-dual-calendar", inputs: { control: "control", label: "label", name: "name", withTime: "withTime", isDatePickerShow: "isDatePickerShow", currentLang: "currentLang", disabledDays: "disabledDays", disabledDates: "disabledDates", isShown: "isShown", appedToBody: "appedToBody" }, outputs: { gregorianUTC: "gregorianUTC", onClose: "onClose" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
2129
2235
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura }
2130
- ], viewQueries: [{ propertyName: "calendarWrapper", first: true, predicate: ["calendarWrapper"], descendants: true }, { propertyName: "calendarContainer", first: true, predicate: ["calendarContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"calender-content\" #calendarContainer>\r\n @if(isDatePickerShow) {\r\n <stc-date-picker-switcher [variant]=\"'in'\" [label]=\"label\" id=\"dateId\" (openCalender)=\"showCalender($event)\"\r\n [control]=\"control\" [formattedDate]='selectedDate' >\r\n </stc-date-picker-switcher>\r\n }\r\n\r\n <!-- calender.html -->\r\n <div (click)=\"$event.stopPropagation()\" [dir]=\"currentLang() === 'ar' ? 'rtl' : 'ltr'\" class=\"p-2 calendar-wrapper \" [@slideDown]=\"isShown ? 'open' : 'closed'\" #calendarWrapper>\r\n <div class=\"header-tabs\">\r\n <div class=\"header-label\">{{'calender.calender_type' | translate}}</div>\r\n <div class=\"tabs\">\r\n <button class=\"tab-button\" [class.active]=\"mode === 'gregorian'\" type=\"button\" (click)=\" mode='gregorian'\">\r\n {{'calender.gregorian' | translate}}\r\n </button>\r\n <button class=\"tab-button\" [class.active]=\"mode === 'hijri'\" type=\"button\" (click)=\" mode='hijri'\">\r\n {{'calender.hijri' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n @if(mode === 'gregorian') {\r\n <app-gregorian-calendar [model]=\"gregorianModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" (dateSelected)=\"onSelectGregorian($event)\">\r\n </app-gregorian-calendar>\r\n }\r\n\r\n @if(mode === 'hijri') {\r\n <app-hijri-calendar [model]=\"hijriModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" (dateSelected)=\"onSelectHijri($event)\">\r\n </app-hijri-calendar>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".calendar-wrapper{max-width:375px;padding:15px;position:fixed;z-index:9999;box-shadow:0 2px 8px #00000026;background-color:#fff;border-radius:4px;overflow:hidden}.calendar-wrapper .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-6px;transform:rotate(180deg);margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:22px;transform:rotate(180deg)}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-4px}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:11px}.header-tabs{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}.tabs{background:#f0f0f5;padding:3px;border-radius:2px}.tab-button{flex:1;padding:6px 10px;font-size:14px;background:#f0f0f5;border:none;border-radius:6px;cursor:pointer;transition:.3s}.tab-button.active{background:#dcd6f8;color:#4a3fb4;font-weight:600}.custom-datepicker{width:100%;background:#fff;border:1px solid #e5e5e5;border-radius:8px;padding:12px}.custom-datepicker .ngb-dp-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;max-width:375px}.custom-datepicker .ngb-dp-arrow-btn{background:none;border:none;cursor:pointer;padding:4px}.custom-datepicker .ngb-dp-weekdays{margin-bottom:6px}.custom-datepicker .ngb-dp-weekday{color:#9b9b9b;font-weight:600;text-align:center}.custom-day.today{border:1px solid #6a41d8;width:100%;height:100%;border-radius:4px;margin:0}.custom-day.outside{opacity:.3}.custom-day.disabled{opacity:.2;pointer-events:none}.calender-content{position:relative}.ngb-datepicker{width:100%}.custom-day{display:inline-flex;justify-content:center;align-items:center;margin:2px;border-radius:50%;cursor:pointer;font-weight:500}.custom-day.today{color:#4f008d}.ngb-dp-day:has(.selected){background-color:#ede6f4!important;border:0!important;color:#4f008d!important;border-radius:2px}.custom-day.outside{color:#ccc!important}.custom-day.disabled{color:#aaa!important;pointer-events:none!important}.ngb-dp-day,.ngb-dp-weekday,.ngb-dp-week-number{width:32px!important;height:32px!important;display:flex;margin:5px;justify-content:center;align-items:center}.ngb-dp-month:first-child .ngb-dp-week{padding:0!important}.ngb-dp-month:last-child .ngb-dp-week{padding:0!important}.ngb-dp-arrow-btn{margin-inline-end:0!important;outline:0!important;padding:0!important;margin:0!important}.ngb-dp-header{position:relative}.ngb-dp-header .ngb-dp-arrow{position:absolute}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:0}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:15px}.ngb-dp-header .ngb-dp-arrow:focus-visible,.ngb-dp-header .ngb-dp-arrow .btn:focus-visible{outline:0!important}.ngb-dp-header .visually-hidden{display:none}.ngb-dp-navigation-select{max-width:140px}.ngb-dp-navigation-select select{border:0}.ngb-dp-navigation-select select:focus-visible{outline:0}.ngb-datepicker-navigation-select>.form-select{font-size:14px;font-weight:700}.ngb-dp-navigation-select,.form-select:first-child{appearance:none!important;-webkit-appearance:none;-moz-appearance:none}.ngb-dp-navigation-chevron{font-size:18px;border-width:.1em .1em 0 0!important;border-color:#000}\n"], dependencies: [{ kind: "ngmodule", type: NgbDatepickerModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: DatePickerModule }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: HijriCalendarComponent, selector: "app-hijri-calendar", inputs: ["model", "disabledDays", "language"], outputs: ["dateSelected"] }, { kind: "component", type: DatePickerSwitcherComponent, selector: "stc-date-picker-switcher", inputs: ["type", "contentType", "size", "prefix", "rows", "cols", "autoResize", "basicInput", "noStyle", "hideOptionalLabel", "inputDirection", "variant", "defaultColor", "formattedDate"], outputs: ["openCalender"] }, { kind: "component", type: GregorianCalendarComponent, selector: "app-gregorian-calendar", inputs: ["model", "disabledDays", "language"], outputs: ["dateSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
2236
+ ], viewQueries: [{ propertyName: "calendarWrapper", first: true, predicate: ["calendarWrapper"], descendants: true }, { propertyName: "calendarContainer", first: true, predicate: ["calendarContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"calender-content\" #calendarContainer>\r\n @if(isDatePickerShow) {\r\n <stc-date-picker-switcher [variant]=\"'in'\" [label]=\"label\" id=\"dateId\" (openCalender)=\"showCalender($event)\"\r\n [control]=\"control\" [formattedDate]='selectedDate' >\r\n </stc-date-picker-switcher>\r\n }\r\n\r\n <!-- calender.html -->\r\n <div (click)=\"$event.stopPropagation()\" [dir]=\"currentLang() === 'ar' ? 'rtl' : 'ltr'\" class=\"p-2 calendar-wrapper \" [@slideDown]=\"isShown ? 'open' : 'closed'\" #calendarWrapper>\r\n <div class=\"header-tabs\">\r\n <div class=\"header-label\">{{'calender.calender_type' | translate}}</div>\r\n <div class=\"tabs\">\r\n <button class=\"tab-button\" [class.active]=\"mode === 'gregorian'\" type=\"button\" (click)=\" mode='gregorian'\">\r\n {{'calender.gregorian' | translate}}\r\n </button>\r\n <button class=\"tab-button\" [class.active]=\"mode === 'hijri'\" type=\"button\" (click)=\" mode='hijri'\">\r\n {{'calender.hijri' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n @if(mode === 'gregorian') {\r\n <app-gregorian-calendar [model]=\"gregorianModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" [disabledDates]=\"disabledDates\" (dateSelected)=\"onSelectGregorian($event)\">\r\n </app-gregorian-calendar>\r\n }\r\n\r\n @if(mode === 'hijri') {\r\n <app-hijri-calendar [model]=\"hijriModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" [disabledDates]=\"disabledDates\" (dateSelected)=\"onSelectHijri($event)\">\r\n </app-hijri-calendar>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".calendar-wrapper{max-width:375px;padding:15px;position:fixed;z-index:9999;box-shadow:0 2px 8px #00000026;background-color:#fff;border-radius:4px;overflow:hidden}.calendar-wrapper .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-6px;transform:rotate(180deg);margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:22px;transform:rotate(180deg)}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-4px}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:11px}.header-tabs{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}.tabs{background:#f0f0f5;padding:3px;border-radius:2px}.tab-button{flex:1;padding:6px 10px;font-size:14px;background:#f0f0f5;border:none;border-radius:6px;cursor:pointer;transition:.3s}.tab-button.active{background:#dcd6f8;color:#4a3fb4;font-weight:600}.custom-datepicker{width:100%;background:#fff;border:1px solid #e5e5e5;border-radius:8px;padding:12px}.custom-datepicker .ngb-dp-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;max-width:375px}.custom-datepicker .ngb-dp-arrow-btn{background:none;border:none;cursor:pointer;padding:4px}.custom-datepicker .ngb-dp-weekdays{margin-bottom:6px}.custom-datepicker .ngb-dp-weekday{color:#9b9b9b;font-weight:600;text-align:center}.custom-day.today{border:1px solid #6a41d8;width:100%;height:100%;border-radius:4px;margin:0}.custom-day.outside{opacity:.3}.custom-day.disabled{opacity:.2;pointer-events:none}.calender-content{position:relative}.ngb-datepicker{width:100%}.custom-day{display:inline-flex;justify-content:center;align-items:center;margin:2px;border-radius:50%;cursor:pointer;font-weight:500}.custom-day.today{color:#4f008d}.ngb-dp-day:has(.selected){background-color:#ede6f4!important;border:0!important;color:#4f008d!important;border-radius:2px}.custom-day.outside{color:#ccc!important}.custom-day.disabled{color:#aaa!important;pointer-events:none!important}.ngb-dp-day,.ngb-dp-weekday,.ngb-dp-week-number{width:32px!important;height:32px!important;display:flex;margin:5px;justify-content:center;align-items:center}.ngb-dp-month:first-child .ngb-dp-week{padding:0!important}.ngb-dp-month:last-child .ngb-dp-week{padding:0!important}.ngb-dp-arrow-btn{margin-inline-end:0!important;outline:0!important;padding:0!important;margin:0!important}.ngb-dp-header{position:relative}.ngb-dp-header .ngb-dp-arrow{position:absolute}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:0}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:15px}.ngb-dp-header .ngb-dp-arrow:focus-visible,.ngb-dp-header .ngb-dp-arrow .btn:focus-visible{outline:0!important}.ngb-dp-header .visually-hidden{display:none}.ngb-dp-navigation-select{max-width:140px}.ngb-dp-navigation-select select{border:0}.ngb-dp-navigation-select select:focus-visible{outline:0}.ngb-datepicker-navigation-select>.form-select{font-size:14px;font-weight:700}.ngb-dp-navigation-select,.form-select:first-child{appearance:none!important;-webkit-appearance:none;-moz-appearance:none}.ngb-dp-navigation-chevron{font-size:18px;border-width:.1em .1em 0 0!important;border-color:#000}\n"], dependencies: [{ kind: "ngmodule", type: NgbDatepickerModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: DatePickerModule }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: HijriCalendarComponent, selector: "app-hijri-calendar", inputs: ["model", "disabledDays", "disabledDates", "language"], outputs: ["dateSelected"] }, { kind: "component", type: DatePickerSwitcherComponent, selector: "stc-date-picker-switcher", inputs: ["type", "contentType", "size", "prefix", "rows", "cols", "autoResize", "basicInput", "noStyle", "hideOptionalLabel", "inputDirection", "variant", "defaultColor", "formattedDate"], outputs: ["openCalender"] }, { kind: "component", type: GregorianCalendarComponent, selector: "app-gregorian-calendar", inputs: ["model", "disabledDays", "disabledDates", "language"], outputs: ["dateSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
2131
2237
  trigger('slideDown', [
2132
2238
  state('closed', style({
2133
2239
  height: '0px',
@@ -2179,7 +2285,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2179
2285
  GregorianCalendarComponent
2180
2286
  ], providers: [
2181
2287
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura }
2182
- ], encapsulation: ViewEncapsulation.None, template: "<div class=\"calender-content\" #calendarContainer>\r\n @if(isDatePickerShow) {\r\n <stc-date-picker-switcher [variant]=\"'in'\" [label]=\"label\" id=\"dateId\" (openCalender)=\"showCalender($event)\"\r\n [control]=\"control\" [formattedDate]='selectedDate' >\r\n </stc-date-picker-switcher>\r\n }\r\n\r\n <!-- calender.html -->\r\n <div (click)=\"$event.stopPropagation()\" [dir]=\"currentLang() === 'ar' ? 'rtl' : 'ltr'\" class=\"p-2 calendar-wrapper \" [@slideDown]=\"isShown ? 'open' : 'closed'\" #calendarWrapper>\r\n <div class=\"header-tabs\">\r\n <div class=\"header-label\">{{'calender.calender_type' | translate}}</div>\r\n <div class=\"tabs\">\r\n <button class=\"tab-button\" [class.active]=\"mode === 'gregorian'\" type=\"button\" (click)=\" mode='gregorian'\">\r\n {{'calender.gregorian' | translate}}\r\n </button>\r\n <button class=\"tab-button\" [class.active]=\"mode === 'hijri'\" type=\"button\" (click)=\" mode='hijri'\">\r\n {{'calender.hijri' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n @if(mode === 'gregorian') {\r\n <app-gregorian-calendar [model]=\"gregorianModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" (dateSelected)=\"onSelectGregorian($event)\">\r\n </app-gregorian-calendar>\r\n }\r\n\r\n @if(mode === 'hijri') {\r\n <app-hijri-calendar [model]=\"hijriModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" (dateSelected)=\"onSelectHijri($event)\">\r\n </app-hijri-calendar>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".calendar-wrapper{max-width:375px;padding:15px;position:fixed;z-index:9999;box-shadow:0 2px 8px #00000026;background-color:#fff;border-radius:4px;overflow:hidden}.calendar-wrapper .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-6px;transform:rotate(180deg);margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:22px;transform:rotate(180deg)}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-4px}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:11px}.header-tabs{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}.tabs{background:#f0f0f5;padding:3px;border-radius:2px}.tab-button{flex:1;padding:6px 10px;font-size:14px;background:#f0f0f5;border:none;border-radius:6px;cursor:pointer;transition:.3s}.tab-button.active{background:#dcd6f8;color:#4a3fb4;font-weight:600}.custom-datepicker{width:100%;background:#fff;border:1px solid #e5e5e5;border-radius:8px;padding:12px}.custom-datepicker .ngb-dp-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;max-width:375px}.custom-datepicker .ngb-dp-arrow-btn{background:none;border:none;cursor:pointer;padding:4px}.custom-datepicker .ngb-dp-weekdays{margin-bottom:6px}.custom-datepicker .ngb-dp-weekday{color:#9b9b9b;font-weight:600;text-align:center}.custom-day.today{border:1px solid #6a41d8;width:100%;height:100%;border-radius:4px;margin:0}.custom-day.outside{opacity:.3}.custom-day.disabled{opacity:.2;pointer-events:none}.calender-content{position:relative}.ngb-datepicker{width:100%}.custom-day{display:inline-flex;justify-content:center;align-items:center;margin:2px;border-radius:50%;cursor:pointer;font-weight:500}.custom-day.today{color:#4f008d}.ngb-dp-day:has(.selected){background-color:#ede6f4!important;border:0!important;color:#4f008d!important;border-radius:2px}.custom-day.outside{color:#ccc!important}.custom-day.disabled{color:#aaa!important;pointer-events:none!important}.ngb-dp-day,.ngb-dp-weekday,.ngb-dp-week-number{width:32px!important;height:32px!important;display:flex;margin:5px;justify-content:center;align-items:center}.ngb-dp-month:first-child .ngb-dp-week{padding:0!important}.ngb-dp-month:last-child .ngb-dp-week{padding:0!important}.ngb-dp-arrow-btn{margin-inline-end:0!important;outline:0!important;padding:0!important;margin:0!important}.ngb-dp-header{position:relative}.ngb-dp-header .ngb-dp-arrow{position:absolute}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:0}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:15px}.ngb-dp-header .ngb-dp-arrow:focus-visible,.ngb-dp-header .ngb-dp-arrow .btn:focus-visible{outline:0!important}.ngb-dp-header .visually-hidden{display:none}.ngb-dp-navigation-select{max-width:140px}.ngb-dp-navigation-select select{border:0}.ngb-dp-navigation-select select:focus-visible{outline:0}.ngb-datepicker-navigation-select>.form-select{font-size:14px;font-weight:700}.ngb-dp-navigation-select,.form-select:first-child{appearance:none!important;-webkit-appearance:none;-moz-appearance:none}.ngb-dp-navigation-chevron{font-size:18px;border-width:.1em .1em 0 0!important;border-color:#000}\n"] }]
2288
+ ], encapsulation: ViewEncapsulation.None, template: "<div class=\"calender-content\" #calendarContainer>\r\n @if(isDatePickerShow) {\r\n <stc-date-picker-switcher [variant]=\"'in'\" [label]=\"label\" id=\"dateId\" (openCalender)=\"showCalender($event)\"\r\n [control]=\"control\" [formattedDate]='selectedDate' >\r\n </stc-date-picker-switcher>\r\n }\r\n\r\n <!-- calender.html -->\r\n <div (click)=\"$event.stopPropagation()\" [dir]=\"currentLang() === 'ar' ? 'rtl' : 'ltr'\" class=\"p-2 calendar-wrapper \" [@slideDown]=\"isShown ? 'open' : 'closed'\" #calendarWrapper>\r\n <div class=\"header-tabs\">\r\n <div class=\"header-label\">{{'calender.calender_type' | translate}}</div>\r\n <div class=\"tabs\">\r\n <button class=\"tab-button\" [class.active]=\"mode === 'gregorian'\" type=\"button\" (click)=\" mode='gregorian'\">\r\n {{'calender.gregorian' | translate}}\r\n </button>\r\n <button class=\"tab-button\" [class.active]=\"mode === 'hijri'\" type=\"button\" (click)=\" mode='hijri'\">\r\n {{'calender.hijri' | translate}}\r\n </button>\r\n </div>\r\n </div>\r\n @if(mode === 'gregorian') {\r\n <app-gregorian-calendar [model]=\"gregorianModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" [disabledDates]=\"disabledDates\" (dateSelected)=\"onSelectGregorian($event)\">\r\n </app-gregorian-calendar>\r\n }\r\n\r\n @if(mode === 'hijri') {\r\n <app-hijri-calendar [model]=\"hijriModel\" [language]=\"currentLang()\"\r\n [disabledDays]=\"disabledDays\" [disabledDates]=\"disabledDates\" (dateSelected)=\"onSelectHijri($event)\">\r\n </app-hijri-calendar>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".calendar-wrapper{max-width:375px;padding:15px;position:fixed;z-index:9999;box-shadow:0 2px 8px #00000026;background-color:#fff;border-radius:4px;overflow:hidden}.calendar-wrapper .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-6px;transform:rotate(180deg);margin:0 10px;max-width:20px}.calendar-wrapper .rtl .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:22px;transform:rotate(180deg)}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:-4px}.calendar-wrapper .ltr .ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:11px}.header-tabs{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}.tabs{background:#f0f0f5;padding:3px;border-radius:2px}.tab-button{flex:1;padding:6px 10px;font-size:14px;background:#f0f0f5;border:none;border-radius:6px;cursor:pointer;transition:.3s}.tab-button.active{background:#dcd6f8;color:#4a3fb4;font-weight:600}.custom-datepicker{width:100%;background:#fff;border:1px solid #e5e5e5;border-radius:8px;padding:12px}.custom-datepicker .ngb-dp-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;max-width:375px}.custom-datepicker .ngb-dp-arrow-btn{background:none;border:none;cursor:pointer;padding:4px}.custom-datepicker .ngb-dp-weekdays{margin-bottom:6px}.custom-datepicker .ngb-dp-weekday{color:#9b9b9b;font-weight:600;text-align:center}.custom-day.today{border:1px solid #6a41d8;width:100%;height:100%;border-radius:4px;margin:0}.custom-day.outside{opacity:.3}.custom-day.disabled{opacity:.2;pointer-events:none}.calender-content{position:relative}.ngb-datepicker{width:100%}.custom-day{display:inline-flex;justify-content:center;align-items:center;margin:2px;border-radius:50%;cursor:pointer;font-weight:500}.custom-day.today{color:#4f008d}.ngb-dp-day:has(.selected){background-color:#ede6f4!important;border:0!important;color:#4f008d!important;border-radius:2px}.custom-day.outside{color:#ccc!important}.custom-day.disabled{color:#aaa!important;pointer-events:none!important}.ngb-dp-day,.ngb-dp-weekday,.ngb-dp-week-number{width:32px!important;height:32px!important;display:flex;margin:5px;justify-content:center;align-items:center}.ngb-dp-month:first-child .ngb-dp-week{padding:0!important}.ngb-dp-month:last-child .ngb-dp-week{padding:0!important}.ngb-dp-arrow-btn{margin-inline-end:0!important;outline:0!important;padding:0!important;margin:0!important}.ngb-dp-header{position:relative}.ngb-dp-header .ngb-dp-arrow{position:absolute}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-prev{inset-inline-end:0}.ngb-dp-header .ngb-dp-arrow.ngb-dp-arrow-next{inset-inline-end:15px}.ngb-dp-header .ngb-dp-arrow:focus-visible,.ngb-dp-header .ngb-dp-arrow .btn:focus-visible{outline:0!important}.ngb-dp-header .visually-hidden{display:none}.ngb-dp-navigation-select{max-width:140px}.ngb-dp-navigation-select select{border:0}.ngb-dp-navigation-select select:focus-visible{outline:0}.ngb-datepicker-navigation-select>.form-select{font-size:14px;font-weight:700}.ngb-dp-navigation-select,.form-select:first-child{appearance:none!important;-webkit-appearance:none;-moz-appearance:none}.ngb-dp-navigation-chevron{font-size:18px;border-width:.1em .1em 0 0!important;border-color:#000}\n"] }]
2183
2289
  }], ctorParameters: () => [], propDecorators: { calendarWrapper: [{
2184
2290
  type: ViewChild,
2185
2291
  args: ['calendarWrapper']
@@ -2197,6 +2303,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2197
2303
  type: Input
2198
2304
  }], disabledDays: [{
2199
2305
  type: Input
2306
+ }], disabledDates: [{
2307
+ type: Input
2200
2308
  }], gregorianUTC: [{
2201
2309
  type: Output
2202
2310
  }], onClose: [{
@@ -2228,7 +2336,6 @@ var FormFieldTypeEnum;
2228
2336
 
2229
2337
  class DynamicFormComponent {
2230
2338
  dynamicFormData;
2231
- // Generic field change outputs (optional for consumers)
2232
2339
  selectButtonChange = new EventEmitter();
2233
2340
  selectChange = new EventEmitter();
2234
2341
  selectClicked = new EventEmitter();
@@ -2237,11 +2344,16 @@ class DynamicFormComponent {
2237
2344
  autoCompleteSelect = new EventEmitter();
2238
2345
  popUpFilesUploaded = new EventEmitter();
2239
2346
  fileDeleted = new EventEmitter();
2347
+ uploadStateChange = new EventEmitter();
2240
2348
  inputsNames = [];
2241
2349
  formGroup;
2242
2350
  inputsMap;
2351
+ standaloneFileControl = new FormControl(null);
2243
2352
  fieldType = FormFieldTypeEnum;
2244
2353
  getFormControl = FormUtils.getFormControl;
2354
+ get fileUploadConfig() {
2355
+ return this.dynamicFormData?.fileUpload;
2356
+ }
2245
2357
  ngOnInit() {
2246
2358
  this.updateFormState();
2247
2359
  }
@@ -2255,8 +2367,20 @@ class DynamicFormComponent {
2255
2367
  this.inputsMap = this.dynamicFormData?.inputsMap;
2256
2368
  this.inputsNames = Object.keys(this.inputsMap || {});
2257
2369
  }
2258
- getAcceptedTypes() {
2259
- return FileExtentions.toString();
2370
+ getAcceptedTypes(fileUpload) {
2371
+ if (fileUpload?.acceptedTypes) {
2372
+ return fileUpload.acceptedTypes;
2373
+ }
2374
+ return formatFileExtensionsForAccept(FileExtentions);
2375
+ }
2376
+ getMaxFileSize(fileUpload) {
2377
+ return fileUpload?.maxFileSize ?? 262144000;
2378
+ }
2379
+ getFileUploadConfig(inputName) {
2380
+ return this.inputsMap[inputName]?.fileUpload ?? this.dynamicFormData?.fileUpload;
2381
+ }
2382
+ hasUploadFileField() {
2383
+ return this.inputsNames.some((name) => this.inputsMap[name].fieldType === FormFieldTypeEnum.UPLOAD_FILE);
2260
2384
  }
2261
2385
  onFilesUploaded(file) {
2262
2386
  this.popUpFilesUploaded.emit(file);
@@ -2264,13 +2388,16 @@ class DynamicFormComponent {
2264
2388
  onFileDeleted(file) {
2265
2389
  this.fileDeleted.emit(file);
2266
2390
  }
2391
+ onUploadStateChange(state) {
2392
+ this.uploadStateChange.emit(state);
2393
+ }
2267
2394
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2268
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DynamicFormComponent, isStandalone: true, selector: "app-dynamic-form", inputs: { dynamicFormData: "dynamicFormData" }, outputs: { selectButtonChange: "selectButtonChange", selectChange: "selectChange", selectClicked: "selectClicked", switchChange: "switchChange", autoCompleteSearch: "autoCompleteSearch", autoCompleteSelect: "autoCompleteSelect", popUpFilesUploaded: "popUpFilesUploaded", fileDeleted: "fileDeleted" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"dynamic-form__content\">\r\n @for (inputName of inputsNames; track $index) {\r\n <div [ngClass]=\"inputsMap[inputName].rowSize\">\r\n @switch (inputsMap[inputName].fieldType) {\r\n @case (fieldType.HIJRI_DATE_PICKER) {\r\n <app-dual-calendar [control]=\"getFormControl(inputName, formGroup)\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"></app-dual-calendar>\r\n }\r\n\r\n @case (fieldType.DATE_PICKER) {\r\n <stc-date-picker [minDate]=\"inputsMap[inputName]?.dateRange?.min\" [maxDate]=\"inputsMap[inputName]?.dateRange?.max\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"\r\n [id]=\"inputsMap[inputName].inputId\" [control]=\"getFormControl(inputName, formGroup)\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [showIcon]=\"inputsMap[inputName].showIcon !== false\" [isTimeOnly]=\"inputsMap[inputName].isTimeOnly || false\"\r\n [withoutTime]=\"inputsMap[inputName].withoutTime || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || true\" />\r\n }\r\n @case (fieldType.SELECT_BUTTON) {\r\n <stc-select-button [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\"\r\n [options]=\"inputsMap[inputName].selectButtonOptions || []\"\r\n (onChange)=\"selectButtonChange.emit({ name: inputName, value: $event })\" />\r\n }\r\n @case (fieldType.INPUT) {\r\n <stc-input [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [type]=\"inputsMap[inputName].inputType || 'text'\"\r\n [contentType]=\"inputsMap[inputName].contentType || 'text'\" [rows]=\"inputsMap[inputName].rows || 2\"\r\n [cols]=\"inputsMap[inputName].cols || 20\" [autoResize]=\"inputsMap[inputName].autoResize ?? false\"\r\n [prefix]=\"inputsMap[inputName].prefix || ''\" [size]=\"inputsMap[inputName].size || 'small'\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [maxLength]=\"inputsMap[inputName].maxLength || null\">\r\n @if(inputsMap[inputName].maxLength){\r\n <span class=\"text-xs text-gray-700\">\r\n {{ (getFormControl(inputName, formGroup).value?.length || 0) }}\r\n <span> / {{ inputsMap[inputName].maxLength}}</span>\r\n </span>\r\n }\r\n </stc-input>\r\n }\r\n @case (fieldType.SELECT) {\r\n <ng-template #optionTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-3\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-8 h-8 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <div class=\"flex flex-col min-w-0\">\r\n <span class=\"font-medium truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n @if (inputsMap[inputName].optionTemplate!.subTextKey &&\r\n item[inputsMap[inputName].optionTemplate!.subTextKey!]) {\r\n <span class=\"text-sm text-gray-500 truncate\">{{ item[inputsMap[inputName].optionTemplate!.subTextKey!]\r\n }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n <ng-template #selectedTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-2\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-6 h-6 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <span class=\"truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n </div>\r\n }\r\n </ng-template>\r\n <stc-select [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [options]=\"inputsMap[inputName].selectOptions || []\"\r\n [optionLabel]=\"inputsMap[inputName]?.translatable\r\n ? ((inputsMap[inputName]?.optionLabel || 'label') | localizedLabel)\r\n : (inputsMap[inputName]?.optionLabel || 'label')\" [optionValue]=\"inputsMap[inputName]?.optionValue || ''\"\r\n [filter]=\"inputsMap[inputName].filter || false\" [multiple]=\"inputsMap[inputName].multiple || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || false\" [checkmark]=\"inputsMap[inputName].checkmark ?? true\"\r\n [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [optionTemplate]=\"inputsMap[inputName].optionTemplate ? optionTpl : null\"\r\n [selectedItemTemplate]=\"inputsMap[inputName].optionTemplate ? selectedTpl : null\"\r\n (change)=\"selectChange.emit({ name: inputName, event: $event })\"\r\n (click)=\"selectClicked.emit({ name: inputName, event: $event })\" />\r\n }\r\n @case (fieldType.SWITCH) {\r\n <stc-switch [label]=\"inputsMap[inputName].label\" [key]=\"inputName\"\r\n [checked]=\"getFormControl(inputName, formGroup).value\"\r\n (onChange)=\"getFormControl(inputName, formGroup).setValue(typeof $event === 'string' ? ($event === 'true') : $event); switchChange.emit({ name: inputName, value: (typeof $event === 'string' ? ($event === 'true') : $event) })\" />\r\n }\r\n @case (fieldType.CHECKBOX) {\r\n <div class=\"flex items-center gap-2 my-3\">\r\n <p-checkbox [inputId]=\"inputsMap[inputName].inputId || inputName\" [binary]=\"true\"\r\n [formControl]=\"getFormControl(inputName, formGroup)\" [disabled]=\"inputsMap[inputName].disabled || false\" />\r\n <label [for]=\"inputsMap[inputName].inputId || inputName\">{{ inputsMap[inputName].label }}</label>\r\n </div>\r\n }\r\n @case (fieldType.AUTO_COMPLETE) {\r\n <stc-auto-complete [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [items]=\"inputsMap[inputName].autoCompleteItems || []\"\r\n [minLengthToSearch]=\"inputsMap[inputName].minLengthToSearch || 2\" [delay]=\"inputsMap[inputName].delay || 300\"\r\n (onSearch)=\"autoCompleteSearch.emit({ name: inputName, query: $event })\"\r\n (selectOption)=\"autoCompleteSelect.emit({ name: inputName, event: $event })\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [allowedDomains]=\"inputsMap[inputName]?.allowedDomains\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager [maxFileSize]=\"262144000\" [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\" [acceptedTypes]=\"getAcceptedTypes()\" (filesUploaded)=\"onFilesUploaded($event)\"\r\n [control]=\"getFormControl(inputName, formGroup)\" (fileDeleted)=\"onFileDeleted($event)\" />\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n\r\n\r\n </div>\r\n <div class=\"col-span-12\">\r\n <small class=\"p-error text-red-700\">\r\n @for (error of formGroup.errors | validationErrors: dynamicFormData.formValidationErrorsKeys;\r\n track error) {\r\n {{ error }}\r\n }\r\n </small>\r\n </div>\r\n</form>", styles: [".dynamic-form__content>div{margin-bottom:15px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DatePickerComponent, selector: "stc-date-picker", inputs: ["showIcon", "showClear", "basicInput", "isTimeOnly", "minDate", "maxDate", "disabledDates", "disabledDays", "hourFormat", "appendTo", "selectionMode", "variant", "withoutTime"], outputs: ["onAfterClearDate"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: SelectButtonComponent, selector: "stc-select-button", inputs: ["options", "title"], outputs: ["onChange"] }, { kind: "component", type: DualCalendarComponent, selector: "app-dual-calendar", inputs: ["control", "label", "name", "withTime", "isDatePickerShow", "currentLang", "disabledDays", "isShown", "appedToBody"], outputs: ["gregorianUTC", "onClose"] }, { kind: "component", type: InputComponent, selector: "stc-input", inputs: ["type", "contentType", "size", "prefix", "rows", "cols", "maxLength", "autoResize", "basicInput", "noStyle", "canClear", "hideOptionalLabel", "inputDirection", "variant", "defaultColor", "iconClass", "iconPosition"] }, { kind: "component", type: FileManagementComponent, selector: "app-file-management", inputs: ["existingFiles", "acceptedTypes", "maxFileSize", "maxConcurrentUploads", "showTable", "showDropZone", "allowPreview", "permissonKey", "allowedActions"], outputs: ["filesUploaded", "fileDeleted", "filePreview", "fileDownload", "uploadError", "newFilesChange"] }, { kind: "component", type: SelectComponent, selector: "stc-select", inputs: ["selectedItemTemplate", "optionTemplate", "options", "optionLabel", "optionValue", "emptyMessage", "checkmark", "showClear", "editable", "filter", "multiple", "filterBy", "selectAllLabel", "dataKey", "size", "appendTo", "selectedItemsLabel", "basicInput", "variant", "defaultColor"], outputs: ["change", "clicked"] }, { kind: "component", type: AutoCompleteComponent, selector: "stc-auto-complete", inputs: ["selectedItemTemplate", "items", "minLengthToSearch", "delay", "basicInput", "typeAhead", "variant", "allowedDomains"], outputs: ["onSearch", "selectOption"] }, { kind: "component", type: SwitchComponent, selector: "stc-switch", inputs: ["label", "key", "checked"], outputs: ["onChange"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "pipe", type: ValidationErrorsPipe, name: "validationErrors" }, { kind: "pipe", type: LocalizedLabelPipe, name: "localizedLabel" }] });
2395
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DynamicFormComponent, isStandalone: true, selector: "app-dynamic-form", inputs: { dynamicFormData: "dynamicFormData" }, outputs: { selectButtonChange: "selectButtonChange", selectChange: "selectChange", selectClicked: "selectClicked", switchChange: "switchChange", autoCompleteSearch: "autoCompleteSearch", autoCompleteSelect: "autoCompleteSelect", popUpFilesUploaded: "popUpFilesUploaded", fileDeleted: "fileDeleted", uploadStateChange: "uploadStateChange" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"dynamic-form__content\">\r\n @for (inputName of inputsNames; track $index) {\r\n <div [ngClass]=\"inputsMap[inputName].rowSize\">\r\n @switch (inputsMap[inputName].fieldType) {\r\n @case (fieldType.HIJRI_DATE_PICKER) {\r\n <app-dual-calendar [control]=\"getFormControl(inputName, formGroup)\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"></app-dual-calendar>\r\n }\r\n\r\n @case (fieldType.DATE_PICKER) {\r\n <stc-date-picker [minDate]=\"inputsMap[inputName]?.dateRange?.min\" [maxDate]=\"inputsMap[inputName]?.dateRange?.max\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"\r\n [id]=\"inputsMap[inputName].inputId\" [control]=\"getFormControl(inputName, formGroup)\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [showIcon]=\"inputsMap[inputName].showIcon !== false\" [isTimeOnly]=\"inputsMap[inputName].isTimeOnly || false\"\r\n [withoutTime]=\"inputsMap[inputName].withoutTime || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || true\" />\r\n }\r\n @case (fieldType.SELECT_BUTTON) {\r\n <stc-select-button [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\"\r\n [options]=\"inputsMap[inputName].selectButtonOptions || []\"\r\n (onChange)=\"selectButtonChange.emit({ name: inputName, value: $event })\" />\r\n }\r\n @case (fieldType.INPUT) {\r\n <stc-input [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [type]=\"inputsMap[inputName].inputType || 'text'\"\r\n [contentType]=\"inputsMap[inputName].contentType || 'text'\" [rows]=\"inputsMap[inputName].rows || 2\"\r\n [cols]=\"inputsMap[inputName].cols || 20\" [autoResize]=\"inputsMap[inputName].autoResize ?? false\"\r\n [prefix]=\"inputsMap[inputName].prefix || ''\" [size]=\"inputsMap[inputName].size || 'small'\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [maxLength]=\"inputsMap[inputName].maxLength || null\">\r\n @if(inputsMap[inputName].maxLength){\r\n <span class=\"text-xs text-gray-700\">\r\n {{ (getFormControl(inputName, formGroup).value?.length || 0) }}\r\n <span> / {{ inputsMap[inputName].maxLength}}</span>\r\n </span>\r\n }\r\n </stc-input>\r\n }\r\n @case (fieldType.SELECT) {\r\n <ng-template #optionTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-3\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-8 h-8 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <div class=\"flex flex-col min-w-0\">\r\n <span class=\"font-medium truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n @if (inputsMap[inputName].optionTemplate!.subTextKey &&\r\n item[inputsMap[inputName].optionTemplate!.subTextKey!]) {\r\n <span class=\"text-sm text-gray-500 truncate\">{{ item[inputsMap[inputName].optionTemplate!.subTextKey!]\r\n }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n <ng-template #selectedTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-2\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-6 h-6 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <span class=\"truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n </div>\r\n }\r\n </ng-template>\r\n <stc-select [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [options]=\"inputsMap[inputName].selectOptions || []\"\r\n [optionLabel]=\"inputsMap[inputName]?.translatable\r\n ? ((inputsMap[inputName]?.optionLabel || 'label') | localizedLabel)\r\n : (inputsMap[inputName]?.optionLabel || 'label')\" [optionValue]=\"inputsMap[inputName]?.optionValue || ''\"\r\n [filter]=\"inputsMap[inputName].filter || false\" [multiple]=\"inputsMap[inputName].multiple || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || false\" [checkmark]=\"inputsMap[inputName].checkmark ?? true\"\r\n [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [optionTemplate]=\"inputsMap[inputName].optionTemplate ? optionTpl : null\"\r\n [selectedItemTemplate]=\"inputsMap[inputName].optionTemplate ? selectedTpl : null\"\r\n (change)=\"selectChange.emit({ name: inputName, event: $event })\"\r\n (click)=\"selectClicked.emit({ name: inputName, event: $event })\" />\r\n }\r\n @case (fieldType.SWITCH) {\r\n <stc-switch [label]=\"inputsMap[inputName].label\" [key]=\"inputName\"\r\n [checked]=\"getFormControl(inputName, formGroup).value\"\r\n (onChange)=\"getFormControl(inputName, formGroup).setValue(typeof $event === 'string' ? ($event === 'true') : $event); switchChange.emit({ name: inputName, value: (typeof $event === 'string' ? ($event === 'true') : $event) })\" />\r\n }\r\n @case (fieldType.CHECKBOX) {\r\n <div class=\"flex items-center gap-2 my-3\">\r\n <p-checkbox [inputId]=\"inputsMap[inputName].inputId || inputName\" [binary]=\"true\"\r\n [formControl]=\"getFormControl(inputName, formGroup)\" [disabled]=\"inputsMap[inputName].disabled || false\" />\r\n <label [for]=\"inputsMap[inputName].inputId || inputName\">{{ inputsMap[inputName].label }}</label>\r\n </div>\r\n }\r\n @case (fieldType.AUTO_COMPLETE) {\r\n <stc-auto-complete [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [items]=\"inputsMap[inputName].autoCompleteItems || []\"\r\n [minLengthToSearch]=\"inputsMap[inputName].minLengthToSearch || 2\" [delay]=\"inputsMap[inputName].delay || 300\"\r\n (onSearch)=\"autoCompleteSearch.emit({ name: inputName, query: $event })\"\r\n (selectOption)=\"autoCompleteSelect.emit({ name: inputName, event: $event })\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [allowedDomains]=\"inputsMap[inputName]?.allowedDomains\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager\r\n [maxFileSize]=\"getMaxFileSize(getFileUploadConfig(inputName))\"\r\n [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\"\r\n [acceptedTypes]=\"getAcceptedTypes(getFileUploadConfig(inputName))\"\r\n [uploadFn]=\"getFileUploadConfig(inputName)?.uploadFn\"\r\n (filesUploaded)=\"onFilesUploaded($event)\"\r\n (uploadStateChange)=\"onUploadStateChange($event)\"\r\n [control]=\"getFormControl(inputName, formGroup)\"\r\n (fileDeleted)=\"onFileDeleted($event)\" />\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n\r\n\r\n </div>\r\n <div class=\"col-span-12\">\r\n <small class=\"p-error text-red-700\">\r\n @for (error of formGroup.errors | validationErrors: dynamicFormData.formValidationErrorsKeys;\r\n track error) {\r\n {{ error }}\r\n }\r\n </small>\r\n </div>\r\n</form>", styles: [".dynamic-form__content>div{margin-bottom:15px}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DatePickerComponent, selector: "stc-date-picker", inputs: ["showIcon", "showClear", "basicInput", "isTimeOnly", "minDate", "maxDate", "disabledDates", "disabledDays", "hourFormat", "appendTo", "selectionMode", "variant", "withoutTime"], outputs: ["onAfterClearDate"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: SelectButtonComponent, selector: "stc-select-button", inputs: ["options", "title"], outputs: ["onChange"] }, { kind: "component", type: DualCalendarComponent, selector: "app-dual-calendar", inputs: ["control", "label", "name", "withTime", "isDatePickerShow", "currentLang", "disabledDays", "disabledDates", "isShown", "appedToBody"], outputs: ["gregorianUTC", "onClose"] }, { kind: "component", type: InputComponent, selector: "stc-input", inputs: ["type", "contentType", "size", "prefix", "rows", "cols", "maxLength", "autoResize", "basicInput", "noStyle", "canClear", "hideOptionalLabel", "inputDirection", "variant", "defaultColor", "iconClass", "iconPosition"] }, { kind: "component", type: FileManagementComponent, selector: "app-file-management", inputs: ["existingFiles", "acceptedTypes", "maxFileSize", "maxConcurrentUploads", "showTable", "showDropZone", "allowPreview", "permissonKey", "allowedActions", "uploadFn"], outputs: ["filesUploaded", "fileDeleted", "filePreview", "fileDownload", "uploadError", "newFilesChange", "uploadStateChange"] }, { kind: "component", type: SelectComponent, selector: "stc-select", inputs: ["selectedItemTemplate", "optionTemplate", "options", "optionLabel", "optionValue", "emptyMessage", "checkmark", "showClear", "editable", "filter", "multiple", "filterBy", "selectAllLabel", "dataKey", "size", "appendTo", "selectedItemsLabel", "basicInput", "variant", "defaultColor"], outputs: ["change", "clicked"] }, { kind: "component", type: AutoCompleteComponent, selector: "stc-auto-complete", inputs: ["selectedItemTemplate", "items", "minLengthToSearch", "delay", "basicInput", "typeAhead", "variant", "allowedDomains"], outputs: ["onSearch", "selectOption"] }, { kind: "component", type: SwitchComponent, selector: "stc-switch", inputs: ["label", "key", "checked"], outputs: ["onChange"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "pipe", type: ValidationErrorsPipe, name: "validationErrors" }, { kind: "pipe", type: LocalizedLabelPipe, name: "localizedLabel" }] });
2269
2396
  }
2270
2397
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, decorators: [{
2271
2398
  type: Component,
2272
2399
  args: [{ selector: 'app-dynamic-form', standalone: true, imports: [
2273
- CommonModule,
2400
+ NgClass,
2274
2401
  ReactiveFormsModule,
2275
2402
  DatePickerComponent,
2276
2403
  ValidationErrorsPipe,
@@ -2284,7 +2411,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2284
2411
  SwitchComponent,
2285
2412
  LocalizedLabelPipe,
2286
2413
  CheckboxModule,
2287
- ], template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"dynamic-form__content\">\r\n @for (inputName of inputsNames; track $index) {\r\n <div [ngClass]=\"inputsMap[inputName].rowSize\">\r\n @switch (inputsMap[inputName].fieldType) {\r\n @case (fieldType.HIJRI_DATE_PICKER) {\r\n <app-dual-calendar [control]=\"getFormControl(inputName, formGroup)\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"></app-dual-calendar>\r\n }\r\n\r\n @case (fieldType.DATE_PICKER) {\r\n <stc-date-picker [minDate]=\"inputsMap[inputName]?.dateRange?.min\" [maxDate]=\"inputsMap[inputName]?.dateRange?.max\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"\r\n [id]=\"inputsMap[inputName].inputId\" [control]=\"getFormControl(inputName, formGroup)\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [showIcon]=\"inputsMap[inputName].showIcon !== false\" [isTimeOnly]=\"inputsMap[inputName].isTimeOnly || false\"\r\n [withoutTime]=\"inputsMap[inputName].withoutTime || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || true\" />\r\n }\r\n @case (fieldType.SELECT_BUTTON) {\r\n <stc-select-button [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\"\r\n [options]=\"inputsMap[inputName].selectButtonOptions || []\"\r\n (onChange)=\"selectButtonChange.emit({ name: inputName, value: $event })\" />\r\n }\r\n @case (fieldType.INPUT) {\r\n <stc-input [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [type]=\"inputsMap[inputName].inputType || 'text'\"\r\n [contentType]=\"inputsMap[inputName].contentType || 'text'\" [rows]=\"inputsMap[inputName].rows || 2\"\r\n [cols]=\"inputsMap[inputName].cols || 20\" [autoResize]=\"inputsMap[inputName].autoResize ?? false\"\r\n [prefix]=\"inputsMap[inputName].prefix || ''\" [size]=\"inputsMap[inputName].size || 'small'\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [maxLength]=\"inputsMap[inputName].maxLength || null\">\r\n @if(inputsMap[inputName].maxLength){\r\n <span class=\"text-xs text-gray-700\">\r\n {{ (getFormControl(inputName, formGroup).value?.length || 0) }}\r\n <span> / {{ inputsMap[inputName].maxLength}}</span>\r\n </span>\r\n }\r\n </stc-input>\r\n }\r\n @case (fieldType.SELECT) {\r\n <ng-template #optionTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-3\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-8 h-8 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <div class=\"flex flex-col min-w-0\">\r\n <span class=\"font-medium truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n @if (inputsMap[inputName].optionTemplate!.subTextKey &&\r\n item[inputsMap[inputName].optionTemplate!.subTextKey!]) {\r\n <span class=\"text-sm text-gray-500 truncate\">{{ item[inputsMap[inputName].optionTemplate!.subTextKey!]\r\n }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n <ng-template #selectedTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-2\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-6 h-6 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <span class=\"truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n </div>\r\n }\r\n </ng-template>\r\n <stc-select [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [options]=\"inputsMap[inputName].selectOptions || []\"\r\n [optionLabel]=\"inputsMap[inputName]?.translatable\r\n ? ((inputsMap[inputName]?.optionLabel || 'label') | localizedLabel)\r\n : (inputsMap[inputName]?.optionLabel || 'label')\" [optionValue]=\"inputsMap[inputName]?.optionValue || ''\"\r\n [filter]=\"inputsMap[inputName].filter || false\" [multiple]=\"inputsMap[inputName].multiple || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || false\" [checkmark]=\"inputsMap[inputName].checkmark ?? true\"\r\n [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [optionTemplate]=\"inputsMap[inputName].optionTemplate ? optionTpl : null\"\r\n [selectedItemTemplate]=\"inputsMap[inputName].optionTemplate ? selectedTpl : null\"\r\n (change)=\"selectChange.emit({ name: inputName, event: $event })\"\r\n (click)=\"selectClicked.emit({ name: inputName, event: $event })\" />\r\n }\r\n @case (fieldType.SWITCH) {\r\n <stc-switch [label]=\"inputsMap[inputName].label\" [key]=\"inputName\"\r\n [checked]=\"getFormControl(inputName, formGroup).value\"\r\n (onChange)=\"getFormControl(inputName, formGroup).setValue(typeof $event === 'string' ? ($event === 'true') : $event); switchChange.emit({ name: inputName, value: (typeof $event === 'string' ? ($event === 'true') : $event) })\" />\r\n }\r\n @case (fieldType.CHECKBOX) {\r\n <div class=\"flex items-center gap-2 my-3\">\r\n <p-checkbox [inputId]=\"inputsMap[inputName].inputId || inputName\" [binary]=\"true\"\r\n [formControl]=\"getFormControl(inputName, formGroup)\" [disabled]=\"inputsMap[inputName].disabled || false\" />\r\n <label [for]=\"inputsMap[inputName].inputId || inputName\">{{ inputsMap[inputName].label }}</label>\r\n </div>\r\n }\r\n @case (fieldType.AUTO_COMPLETE) {\r\n <stc-auto-complete [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [items]=\"inputsMap[inputName].autoCompleteItems || []\"\r\n [minLengthToSearch]=\"inputsMap[inputName].minLengthToSearch || 2\" [delay]=\"inputsMap[inputName].delay || 300\"\r\n (onSearch)=\"autoCompleteSearch.emit({ name: inputName, query: $event })\"\r\n (selectOption)=\"autoCompleteSelect.emit({ name: inputName, event: $event })\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [allowedDomains]=\"inputsMap[inputName]?.allowedDomains\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager [maxFileSize]=\"262144000\" [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\" [acceptedTypes]=\"getAcceptedTypes()\" (filesUploaded)=\"onFilesUploaded($event)\"\r\n [control]=\"getFormControl(inputName, formGroup)\" (fileDeleted)=\"onFileDeleted($event)\" />\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n\r\n\r\n </div>\r\n <div class=\"col-span-12\">\r\n <small class=\"p-error text-red-700\">\r\n @for (error of formGroup.errors | validationErrors: dynamicFormData.formValidationErrorsKeys;\r\n track error) {\r\n {{ error }}\r\n }\r\n </small>\r\n </div>\r\n</form>", styles: [".dynamic-form__content>div{margin-bottom:15px}\n"] }]
2414
+ ], template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"dynamic-form__content\">\r\n @for (inputName of inputsNames; track $index) {\r\n <div [ngClass]=\"inputsMap[inputName].rowSize\">\r\n @switch (inputsMap[inputName].fieldType) {\r\n @case (fieldType.HIJRI_DATE_PICKER) {\r\n <app-dual-calendar [control]=\"getFormControl(inputName, formGroup)\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"></app-dual-calendar>\r\n }\r\n\r\n @case (fieldType.DATE_PICKER) {\r\n <stc-date-picker [minDate]=\"inputsMap[inputName]?.dateRange?.min\" [maxDate]=\"inputsMap[inputName]?.dateRange?.max\"\r\n [disabledDates]=\"inputsMap[inputName].disabledDates || []\"\r\n [disabledDays]=\"inputsMap[inputName].disabledDays || []\"\r\n [id]=\"inputsMap[inputName].inputId\" [control]=\"getFormControl(inputName, formGroup)\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [showIcon]=\"inputsMap[inputName].showIcon !== false\" [isTimeOnly]=\"inputsMap[inputName].isTimeOnly || false\"\r\n [withoutTime]=\"inputsMap[inputName].withoutTime || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || true\" />\r\n }\r\n @case (fieldType.SELECT_BUTTON) {\r\n <stc-select-button [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\"\r\n [options]=\"inputsMap[inputName].selectButtonOptions || []\"\r\n (onChange)=\"selectButtonChange.emit({ name: inputName, value: $event })\" />\r\n }\r\n @case (fieldType.INPUT) {\r\n <stc-input [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\" [name]=\"inputName\"\r\n [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [type]=\"inputsMap[inputName].inputType || 'text'\"\r\n [contentType]=\"inputsMap[inputName].contentType || 'text'\" [rows]=\"inputsMap[inputName].rows || 2\"\r\n [cols]=\"inputsMap[inputName].cols || 20\" [autoResize]=\"inputsMap[inputName].autoResize ?? false\"\r\n [prefix]=\"inputsMap[inputName].prefix || ''\" [size]=\"inputsMap[inputName].size || 'small'\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [maxLength]=\"inputsMap[inputName].maxLength || null\">\r\n @if(inputsMap[inputName].maxLength){\r\n <span class=\"text-xs text-gray-700\">\r\n {{ (getFormControl(inputName, formGroup).value?.length || 0) }}\r\n <span> / {{ inputsMap[inputName].maxLength}}</span>\r\n </span>\r\n }\r\n </stc-input>\r\n }\r\n @case (fieldType.SELECT) {\r\n <ng-template #optionTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-3\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-8 h-8 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <div class=\"flex flex-col min-w-0\">\r\n <span class=\"font-medium truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n @if (inputsMap[inputName].optionTemplate!.subTextKey &&\r\n item[inputsMap[inputName].optionTemplate!.subTextKey!]) {\r\n <span class=\"text-sm text-gray-500 truncate\">{{ item[inputsMap[inputName].optionTemplate!.subTextKey!]\r\n }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n <ng-template #selectedTpl let-item>\r\n @if (inputsMap[inputName].optionTemplate) {\r\n <div class=\"flex items-center gap-2\">\r\n @if (inputsMap[inputName].optionTemplate!.imageKey && item[inputsMap[inputName].optionTemplate!.imageKey!]) {\r\n <img [src]=\"item[inputsMap[inputName].optionTemplate!.imageKey!]\"\r\n [alt]=\"item[inputsMap[inputName].optionTemplate!.mainTextKey]\"\r\n class=\"w-6 h-6 rounded-full object-cover flex-shrink-0\" />\r\n }\r\n <span class=\"truncate\">{{ item[inputsMap[inputName].optionTemplate!.mainTextKey] }}</span>\r\n </div>\r\n }\r\n </ng-template>\r\n <stc-select [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [options]=\"inputsMap[inputName].selectOptions || []\"\r\n [optionLabel]=\"inputsMap[inputName]?.translatable\r\n ? ((inputsMap[inputName]?.optionLabel || 'label') | localizedLabel)\r\n : (inputsMap[inputName]?.optionLabel || 'label')\" [optionValue]=\"inputsMap[inputName]?.optionValue || ''\"\r\n [filter]=\"inputsMap[inputName].filter || false\" [multiple]=\"inputsMap[inputName].multiple || false\"\r\n [showClear]=\"inputsMap[inputName].showClear || false\" [checkmark]=\"inputsMap[inputName].checkmark ?? true\"\r\n [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n [optionTemplate]=\"inputsMap[inputName].optionTemplate ? optionTpl : null\"\r\n [selectedItemTemplate]=\"inputsMap[inputName].optionTemplate ? selectedTpl : null\"\r\n (change)=\"selectChange.emit({ name: inputName, event: $event })\"\r\n (click)=\"selectClicked.emit({ name: inputName, event: $event })\" />\r\n }\r\n @case (fieldType.SWITCH) {\r\n <stc-switch [label]=\"inputsMap[inputName].label\" [key]=\"inputName\"\r\n [checked]=\"getFormControl(inputName, formGroup).value\"\r\n (onChange)=\"getFormControl(inputName, formGroup).setValue(typeof $event === 'string' ? ($event === 'true') : $event); switchChange.emit({ name: inputName, value: (typeof $event === 'string' ? ($event === 'true') : $event) })\" />\r\n }\r\n @case (fieldType.CHECKBOX) {\r\n <div class=\"flex items-center gap-2 my-3\">\r\n <p-checkbox [inputId]=\"inputsMap[inputName].inputId || inputName\" [binary]=\"true\"\r\n [formControl]=\"getFormControl(inputName, formGroup)\" [disabled]=\"inputsMap[inputName].disabled || false\" />\r\n <label [for]=\"inputsMap[inputName].inputId || inputName\">{{ inputsMap[inputName].label }}</label>\r\n </div>\r\n }\r\n @case (fieldType.AUTO_COMPLETE) {\r\n <stc-auto-complete [control]=\"getFormControl(inputName, formGroup)\" [id]=\"inputsMap[inputName].inputId\"\r\n [name]=\"inputName\" [label]=\"inputsMap[inputName].label\" [placeholder]=\"inputsMap[inputName].placeholder || ''\"\r\n [hint]=\"inputsMap[inputName].hint\"\r\n [readonly]=\"inputsMap[inputName].readonly || dynamicFormData.isReadOnlyForm || false\"\r\n [disabled]=\"inputsMap[inputName].disabled || false\" [items]=\"inputsMap[inputName].autoCompleteItems || []\"\r\n [minLengthToSearch]=\"inputsMap[inputName].minLengthToSearch || 2\" [delay]=\"inputsMap[inputName].delay || 300\"\r\n (onSearch)=\"autoCompleteSearch.emit({ name: inputName, query: $event })\"\r\n (selectOption)=\"autoCompleteSelect.emit({ name: inputName, event: $event })\"\r\n [variant]=\"inputsMap[inputName].variant || 'over'\" [allowedDomains]=\"inputsMap[inputName]?.allowedDomains\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager\r\n [maxFileSize]=\"getMaxFileSize(getFileUploadConfig(inputName))\"\r\n [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\"\r\n [acceptedTypes]=\"getAcceptedTypes(getFileUploadConfig(inputName))\"\r\n [uploadFn]=\"getFileUploadConfig(inputName)?.uploadFn\"\r\n (filesUploaded)=\"onFilesUploaded($event)\"\r\n (uploadStateChange)=\"onUploadStateChange($event)\"\r\n [control]=\"getFormControl(inputName, formGroup)\"\r\n (fileDeleted)=\"onFileDeleted($event)\" />\r\n }\r\n }\r\n </div>\r\n }\r\n\r\n\r\n\r\n </div>\r\n <div class=\"col-span-12\">\r\n <small class=\"p-error text-red-700\">\r\n @for (error of formGroup.errors | validationErrors: dynamicFormData.formValidationErrorsKeys;\r\n track error) {\r\n {{ error }}\r\n }\r\n </small>\r\n </div>\r\n</form>", styles: [".dynamic-form__content>div{margin-bottom:15px}\n"] }]
2288
2415
  }], propDecorators: { dynamicFormData: [{
2289
2416
  type: Input,
2290
2417
  args: [{ required: true }]
@@ -2304,6 +2431,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2304
2431
  type: Output
2305
2432
  }], fileDeleted: [{
2306
2433
  type: Output
2434
+ }], uploadStateChange: [{
2435
+ type: Output
2307
2436
  }] } });
2308
2437
 
2309
2438
  class ConfirmationDialogComponent extends DynamicDialogRef {
@@ -2314,23 +2443,51 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
2314
2443
  _subscription = new Subscription();
2315
2444
  dialogFormData;
2316
2445
  uploadedFile;
2446
+ documentId = null;
2447
+ uploadState = { isUploading: false, documentId: null, hasFile: false };
2448
+ get hasFileUpload() {
2449
+ return !!this.dialogFormData?.fileUpload || this.hasFileUploadField();
2450
+ }
2451
+ hasFileUploadField() {
2452
+ const inputsMap = this.dialogFormData?.inputsMap ?? {};
2453
+ return Object.values(inputsMap).some((field) => field.fieldType === FormFieldTypeEnum.UPLOAD_FILE && !!field.fileUpload?.uploadFn);
2454
+ }
2455
+ get isConfirmDisabled() {
2456
+ if (this.dialogFormData?.formGroup?.invalid) {
2457
+ return true;
2458
+ }
2459
+ if (this.hasFileUpload && (this.uploadState.isUploading || !this.uploadState.documentId)) {
2460
+ return true;
2461
+ }
2462
+ return false;
2463
+ }
2317
2464
  ngOnDestroy() {
2318
2465
  this._subscription.unsubscribe();
2319
2466
  }
2320
2467
  ngOnInit() {
2321
- // closing when navigating back from the browser
2322
2468
  this._subscription.add(this.router.events.pipe(filter((event) => event instanceof NavigationStart)).subscribe(() => {
2323
2469
  if (this.dynamicDialogConfig) {
2324
2470
  this._ref.close(false);
2325
2471
  }
2326
2472
  }));
2327
- this.dialogFormData = this.dynamicDialogConfig.data?.inputForm;
2473
+ const inputForm = this.dynamicDialogConfig.data?.inputForm;
2474
+ const fileUpload = inputForm?.fileUpload ?? this.dynamicDialogConfig.data?.fileUpload;
2475
+ this.dialogFormData = {
2476
+ ...inputForm,
2477
+ formGroup: inputForm?.formGroup ?? new FormGroup({}),
2478
+ inputsMap: inputForm?.inputsMap ?? {},
2479
+ fileUpload,
2480
+ };
2328
2481
  }
2329
2482
  submit() {
2330
- // we should pass submitted data when using form dialog
2331
- // const submitData = { submitted: true, data: this.dialogFormData?.formGroup?.value };
2332
- // this._ref.close(this.dynamicDialogConfig.data.inputForm ? submitData : true);
2333
- if (this.uploadedFile) {
2483
+ if (this.documentId) {
2484
+ this._ref.close({
2485
+ isSubmitted: true,
2486
+ documentId: this.documentId,
2487
+ data: this.dialogFormData?.formGroup?.value,
2488
+ });
2489
+ }
2490
+ else if (this.uploadedFile) {
2334
2491
  this._ref.close({ isSubmitted: true, file: this.uploadedFile });
2335
2492
  }
2336
2493
  else {
@@ -2341,12 +2498,25 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
2341
2498
  this._ref.close(false);
2342
2499
  }
2343
2500
  onPopFilesUploaded(file) {
2344
- this.uploadedFile = file;
2501
+ if (file?.documentId) {
2502
+ this.documentId = file.documentId;
2503
+ }
2504
+ else {
2505
+ this.uploadedFile = file;
2506
+ }
2345
2507
  }
2346
- onFileDeleted(file) {
2508
+ onFileDeleted() {
2509
+ this.documentId = null;
2510
+ this.uploadedFile = null;
2511
+ }
2512
+ onUploadStateChange(state) {
2513
+ this.uploadState = state;
2514
+ if (state.documentId) {
2515
+ this.documentId = state.documentId;
2516
+ }
2347
2517
  }
2348
2518
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2349
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfirmationDialogComponent, isStandalone: true, selector: "app-confirm-dialog", providers: [DialogService, DynamicDialogStyle], usesInheritance: true, ngImport: i0, template: "@if (dynamicDialogConfig.data) {\r\n<div class=\"confirmation-dialog\">\r\n <div class=\"dialog-wrapper\">\r\n @if (dynamicDialogConfig.data) {\r\n <div class=\"confirmation-dialog__content my-4\">\r\n @if (dynamicDialogConfig.data.dialogIcon) {\r\n <em [class]=\"dynamicDialogConfig.data.dialogIcon\"></em>\r\n }\r\n <p class=\"confirmation-dialog__message text-xl mb-2\">\r\n {{ dynamicDialogConfig.data.message }}\r\n </p>\r\n @if (dynamicDialogConfig.data.hint) {\r\n <p class=\"confirmation-dialog__hint font-normal text-base\">\r\n {{ dynamicDialogConfig.data.hint }}\r\n </p>\r\n }\r\n @if (dynamicDialogConfig.data.inputForm) {\r\n <app-dynamic-form [dynamicFormData]=\"dialogFormData\" (popUpFilesUploaded)=\"onPopFilesUploaded($event)\" (fileDeleted)=\"onFileDeleted($event)\" ></app-dynamic-form>\r\n }\r\n </div>\r\n }\r\n <div class=\"confirmation-dialog__actions flex gap-2 mt-4\">\r\n <app-button [title]=\"dynamicDialogConfig.data?.confirmLabel || ('actions.confirm' | translate)\"\r\n [disabled]=\"!!(dialogFormData && dialogFormData.formGroup?.invalid)\" [severity]=\"'primary'\"\r\n [id]=\"dynamicDialogConfig.data.confirmBtnId\" [icon]=\"dynamicDialogConfig.data.confirmBtnIcon || ''\"\r\n [label]=\"dynamicDialogConfig.data.confirmBtnLabel\"\r\n [iconPos]=\"dynamicDialogConfig.data.confirmBtnPosition || 'left'\" [styleClass]=\"'confirmation-btn'\"\r\n (click)=\"submit()\" />\r\n <app-button [title]=\"dynamicDialogConfig.data?.closeLabel || ('actions.cancel' | translate)\"\r\n [severity]=\"'primary'\" variant=\"outlined\" [label]=\"dynamicDialogConfig.data.cancelBtnLabel\"\r\n [id]=\"dynamicDialogConfig.data.cancelBtnId\" [styleClass]=\"'cancel-btn confirmation-btn cancel-btn'\"\r\n (click)=\"close()\" />\r\n </div>\r\n </div>\r\n\r\n</div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: AppButtonComponent, selector: "app-button" }, { kind: "ngmodule", type: AvatarModule }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "component", type: DynamicFormComponent, selector: "app-dynamic-form", inputs: ["dynamicFormData"], outputs: ["selectButtonChange", "selectChange", "selectClicked", "switchChange", "autoCompleteSearch", "autoCompleteSelect", "popUpFilesUploaded", "fileDeleted"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
2519
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfirmationDialogComponent, isStandalone: true, selector: "app-confirm-dialog", providers: [DialogService, DynamicDialogStyle], usesInheritance: true, ngImport: i0, template: "@if (dynamicDialogConfig.data) {\r\n<div class=\"confirmation-dialog\">\r\n <div class=\"dialog-wrapper\">\r\n @if (dynamicDialogConfig.data) {\r\n <div class=\"confirmation-dialog__content my-4\">\r\n @if (dynamicDialogConfig.data.dialogIcon) {\r\n <em [class]=\"dynamicDialogConfig.data.dialogIcon\"></em>\r\n }\r\n <p class=\"confirmation-dialog__message text-xl mb-2\">\r\n {{ dynamicDialogConfig.data.message }}\r\n </p>\r\n @if (dynamicDialogConfig.data.hint) {\r\n <p class=\"confirmation-dialog__hint font-normal text-base\">\r\n {{ dynamicDialogConfig.data.hint }}\r\n </p>\r\n }\r\n @if (dynamicDialogConfig.data.inputForm || hasFileUpload) {\r\n <app-dynamic-form [dynamicFormData]=\"dialogFormData\" (popUpFilesUploaded)=\"onPopFilesUploaded($event)\"\r\n (fileDeleted)=\"onFileDeleted()\" (uploadStateChange)=\"onUploadStateChange($event)\"></app-dynamic-form>\r\n }\r\n </div>\r\n }\r\n <div class=\"confirmation-dialog__actions flex gap-2 mt-4\">\r\n <app-button [title]=\"dynamicDialogConfig.data?.confirmLabel || ('actions.confirm' | translate)\"\r\n [disabled]=\"isConfirmDisabled\" [severity]=\"'primary'\"\r\n [id]=\"dynamicDialogConfig.data.confirmBtnId\" [icon]=\"dynamicDialogConfig.data.confirmBtnIcon || ''\"\r\n [label]=\"dynamicDialogConfig.data.confirmBtnLabel\"\r\n [iconPos]=\"dynamicDialogConfig.data.confirmBtnPosition || 'left'\" [styleClass]=\"'confirmation-btn'\"\r\n (click)=\"submit()\" />\r\n <app-button [title]=\"dynamicDialogConfig.data?.closeLabel || ('actions.cancel' | translate)\"\r\n [severity]=\"'primary'\" variant=\"outlined\" [label]=\"dynamicDialogConfig.data.cancelBtnLabel\"\r\n [id]=\"dynamicDialogConfig.data.cancelBtnId\" [styleClass]=\"'cancel-btn confirmation-btn cancel-btn'\"\r\n (click)=\"close()\" />\r\n </div>\r\n </div>\r\n\r\n</div>\r\n}\r\n", styles: [".confirmation-dialog .dialog-wrapper{padding:.5rem}.confirmation-dialog__content{text-align:center}.confirmation-dialog__message{font-weight:600}.confirmation-dialog__hint{color:#6b7280}.confirmation-dialog__actions{display:flex;justify-content:center;gap:.5rem}\n"], dependencies: [{ kind: "component", type: AppButtonComponent, selector: "app-button" }, { kind: "ngmodule", type: AvatarModule }, { kind: "ngmodule", type: DynamicDialogModule }, { kind: "component", type: DynamicFormComponent, selector: "app-dynamic-form", inputs: ["dynamicFormData"], outputs: ["selectButtonChange", "selectChange", "selectClicked", "switchChange", "autoCompleteSearch", "autoCompleteSelect", "popUpFilesUploaded", "fileDeleted", "uploadStateChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
2350
2520
  }
2351
2521
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
2352
2522
  type: Component,
@@ -2356,7 +2526,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2356
2526
  DynamicDialogModule,
2357
2527
  DynamicFormComponent,
2358
2528
  TranslatePipe,
2359
- ], providers: [DialogService, DynamicDialogStyle], template: "@if (dynamicDialogConfig.data) {\r\n<div class=\"confirmation-dialog\">\r\n <div class=\"dialog-wrapper\">\r\n @if (dynamicDialogConfig.data) {\r\n <div class=\"confirmation-dialog__content my-4\">\r\n @if (dynamicDialogConfig.data.dialogIcon) {\r\n <em [class]=\"dynamicDialogConfig.data.dialogIcon\"></em>\r\n }\r\n <p class=\"confirmation-dialog__message text-xl mb-2\">\r\n {{ dynamicDialogConfig.data.message }}\r\n </p>\r\n @if (dynamicDialogConfig.data.hint) {\r\n <p class=\"confirmation-dialog__hint font-normal text-base\">\r\n {{ dynamicDialogConfig.data.hint }}\r\n </p>\r\n }\r\n @if (dynamicDialogConfig.data.inputForm) {\r\n <app-dynamic-form [dynamicFormData]=\"dialogFormData\" (popUpFilesUploaded)=\"onPopFilesUploaded($event)\" (fileDeleted)=\"onFileDeleted($event)\" ></app-dynamic-form>\r\n }\r\n </div>\r\n }\r\n <div class=\"confirmation-dialog__actions flex gap-2 mt-4\">\r\n <app-button [title]=\"dynamicDialogConfig.data?.confirmLabel || ('actions.confirm' | translate)\"\r\n [disabled]=\"!!(dialogFormData && dialogFormData.formGroup?.invalid)\" [severity]=\"'primary'\"\r\n [id]=\"dynamicDialogConfig.data.confirmBtnId\" [icon]=\"dynamicDialogConfig.data.confirmBtnIcon || ''\"\r\n [label]=\"dynamicDialogConfig.data.confirmBtnLabel\"\r\n [iconPos]=\"dynamicDialogConfig.data.confirmBtnPosition || 'left'\" [styleClass]=\"'confirmation-btn'\"\r\n (click)=\"submit()\" />\r\n <app-button [title]=\"dynamicDialogConfig.data?.closeLabel || ('actions.cancel' | translate)\"\r\n [severity]=\"'primary'\" variant=\"outlined\" [label]=\"dynamicDialogConfig.data.cancelBtnLabel\"\r\n [id]=\"dynamicDialogConfig.data.cancelBtnId\" [styleClass]=\"'cancel-btn confirmation-btn cancel-btn'\"\r\n (click)=\"close()\" />\r\n </div>\r\n </div>\r\n\r\n</div>\r\n}\r\n" }]
2529
+ ], providers: [DialogService, DynamicDialogStyle], template: "@if (dynamicDialogConfig.data) {\r\n<div class=\"confirmation-dialog\">\r\n <div class=\"dialog-wrapper\">\r\n @if (dynamicDialogConfig.data) {\r\n <div class=\"confirmation-dialog__content my-4\">\r\n @if (dynamicDialogConfig.data.dialogIcon) {\r\n <em [class]=\"dynamicDialogConfig.data.dialogIcon\"></em>\r\n }\r\n <p class=\"confirmation-dialog__message text-xl mb-2\">\r\n {{ dynamicDialogConfig.data.message }}\r\n </p>\r\n @if (dynamicDialogConfig.data.hint) {\r\n <p class=\"confirmation-dialog__hint font-normal text-base\">\r\n {{ dynamicDialogConfig.data.hint }}\r\n </p>\r\n }\r\n @if (dynamicDialogConfig.data.inputForm || hasFileUpload) {\r\n <app-dynamic-form [dynamicFormData]=\"dialogFormData\" (popUpFilesUploaded)=\"onPopFilesUploaded($event)\"\r\n (fileDeleted)=\"onFileDeleted()\" (uploadStateChange)=\"onUploadStateChange($event)\"></app-dynamic-form>\r\n }\r\n </div>\r\n }\r\n <div class=\"confirmation-dialog__actions flex gap-2 mt-4\">\r\n <app-button [title]=\"dynamicDialogConfig.data?.confirmLabel || ('actions.confirm' | translate)\"\r\n [disabled]=\"isConfirmDisabled\" [severity]=\"'primary'\"\r\n [id]=\"dynamicDialogConfig.data.confirmBtnId\" [icon]=\"dynamicDialogConfig.data.confirmBtnIcon || ''\"\r\n [label]=\"dynamicDialogConfig.data.confirmBtnLabel\"\r\n [iconPos]=\"dynamicDialogConfig.data.confirmBtnPosition || 'left'\" [styleClass]=\"'confirmation-btn'\"\r\n (click)=\"submit()\" />\r\n <app-button [title]=\"dynamicDialogConfig.data?.closeLabel || ('actions.cancel' | translate)\"\r\n [severity]=\"'primary'\" variant=\"outlined\" [label]=\"dynamicDialogConfig.data.cancelBtnLabel\"\r\n [id]=\"dynamicDialogConfig.data.cancelBtnId\" [styleClass]=\"'cancel-btn confirmation-btn cancel-btn'\"\r\n (click)=\"close()\" />\r\n </div>\r\n </div>\r\n\r\n</div>\r\n}\r\n", styles: [".confirmation-dialog .dialog-wrapper{padding:.5rem}.confirmation-dialog__content{text-align:center}.confirmation-dialog__message{font-weight:600}.confirmation-dialog__hint{color:#6b7280}.confirmation-dialog__actions{display:flex;justify-content:center;gap:.5rem}\n"] }]
2360
2530
  }] });
2361
2531
 
2362
2532
  class ReadMoreComponent {