@corp-products/ui-components 4.2.8 → 4.3.0

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,13 +20,14 @@ 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
+ import { ProgressBar } from 'primeng/progressbar';
30
31
  import { AutoComplete } from 'primeng/autocomplete';
31
32
  import * as i3$1 from 'primeng/floatlabel';
32
33
  import { FloatLabel, FloatLabelModule } from 'primeng/floatlabel';
@@ -48,7 +49,7 @@ import { Select } from 'primeng/select';
48
49
  import * as i1$5 from 'primeng/toggleswitch';
49
50
  import { ToggleSwitchModule } from 'primeng/toggleswitch';
50
51
  import * as i1$6 from '@ng-bootstrap/ng-bootstrap';
51
- import { NgbDatepickerI18n, NgbCalendarIslamicUmalqura, NgbDatepickerModule, NgbCalendar, NgbCalendarGregorian, NgbDate } from '@ng-bootstrap/ng-bootstrap';
52
+ import { NgbDatepickerI18n, NgbCalendarIslamicUmalqura, NgbDate, NgbDatepickerModule, NgbCalendar, NgbCalendarGregorian } from '@ng-bootstrap/ng-bootstrap';
52
53
  import { trigger, state, transition, style, animate } from '@angular/animations';
53
54
  import '@angular/localize/init';
54
55
  import * as i2$4 from 'primeng/accordion';
@@ -458,46 +459,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
458
459
  }] } });
459
460
 
460
461
  class FileManagementComponent extends BaseInputComponent {
461
- // Inputs
462
462
  existingFiles = input([], ...(ngDevMode ? [{ debugName: "existingFiles" }] : []));
463
463
  acceptedTypes = input('*', ...(ngDevMode ? [{ debugName: "acceptedTypes" }] : []));
464
- maxFileSize = input(10485760, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : [])); //250 MB
464
+ maxFileSize = input(10485760, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : []));
465
465
  maxConcurrentUploads = input(3, ...(ngDevMode ? [{ debugName: "maxConcurrentUploads" }] : []));
466
466
  showTable = input(true, ...(ngDevMode ? [{ debugName: "showTable" }] : []));
467
467
  showDropZone = input(true, ...(ngDevMode ? [{ debugName: "showDropZone" }] : []));
468
468
  allowPreview = input(true, ...(ngDevMode ? [{ debugName: "allowPreview" }] : []));
469
469
  permissonKey = input('', ...(ngDevMode ? [{ debugName: "permissonKey" }] : []));
470
470
  allowedActions = input([], ...(ngDevMode ? [{ debugName: "allowedActions" }] : []));
471
- uploadedFile = signal([], ...(ngDevMode ? [{ debugName: "uploadedFile" }] : []));
472
- // Outputs
471
+ uploadFn = input(undefined, ...(ngDevMode ? [{ debugName: "uploadFn" }] : []));
473
472
  filesUploaded = new EventEmitter();
474
473
  fileDeleted = new EventEmitter();
475
474
  filePreview = new EventEmitter();
476
475
  fileDownload = new EventEmitter();
477
476
  uploadError = new EventEmitter();
478
477
  newFilesChange = new EventEmitter();
478
+ uploadStateChange = new EventEmitter();
479
479
  fileInput;
480
- // State - separate new uploads from existing files
480
+ uploadedFile = signal([], ...(ngDevMode ? [{ debugName: "uploadedFile" }] : []));
481
481
  isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
482
- newFiles = signal([], ...(ngDevMode ? [{ debugName: "newFiles" }] : [])); // Files being uploaded or newly uploaded
482
+ newFiles = signal([], ...(ngDevMode ? [{ debugName: "newFiles" }] : []));
483
+ documentId = null;
484
+ uploadErrorMessage = null;
483
485
  uploadedResponses = [];
484
- // Combined files list for the table (existing + new)
486
+ UploadStatus = UploadStatus;
487
+ _subscription = new Subscription();
488
+ progressIntervals = new Map();
485
489
  allFiles = computed(() => {
486
490
  const existing = this.existingFiles().map((f) => ({
487
491
  ...f,
488
- status: undefined, // Don't show status for existing files
492
+ status: undefined,
489
493
  isNew: false,
490
494
  }));
491
- const newOnes = this.newFiles();
492
- return [...newOnes, ...existing];
495
+ return [...this.newFiles(), ...existing];
493
496
  }, ...(ngDevMode ? [{ debugName: "allFiles" }] : []));
494
- // Get only successfully uploaded new file IDs
495
497
  uploadedNewFileIds = computed(() => {
496
498
  return this.newFiles()
497
499
  .filter((f) => f.status === UploadStatus.SUCCESS && f.id && !f.id.startsWith('temp-'))
498
500
  .map((f) => f.id);
499
501
  }, ...(ngDevMode ? [{ debugName: "uploadedNewFileIds" }] : []));
500
- // Formatted accepted file types for display
501
502
  formattedAcceptedTypes = computed(() => {
502
503
  const accepted = this.acceptedTypes();
503
504
  if (accepted === '*' || accepted === '*/*')
@@ -507,8 +508,12 @@ class FileManagementComponent extends BaseInputComponent {
507
508
  .map((type) => type.trim().replace('.', '').toUpperCase())
508
509
  .join(', ');
509
510
  }, ...(ngDevMode ? [{ debugName: "formattedAcceptedTypes" }] : []));
510
- // Table configuration
511
- // Drag & Drop handlers
511
+ ngOnDestroy() {
512
+ this._subscription.unsubscribe();
513
+ this.progressIntervals.forEach((interval) => clearInterval(interval));
514
+ this.progressIntervals.clear();
515
+ super.ngOnDestroy();
516
+ }
512
517
  onDragOver(event) {
513
518
  event.preventDefault();
514
519
  event.stopPropagation();
@@ -528,7 +533,6 @@ class FileManagementComponent extends BaseInputComponent {
528
533
  this.handleFiles(Array.from(droppedFiles));
529
534
  }
530
535
  }
531
- // Browse button handler
532
536
  onBrowseClick() {
533
537
  this.fileInput.nativeElement.click();
534
538
  }
@@ -536,97 +540,163 @@ class FileManagementComponent extends BaseInputComponent {
536
540
  const input = event.target;
537
541
  if (input.files) {
538
542
  this.handleFiles(Array.from(input.files));
539
- // Reset input to allow selecting the same file again
540
543
  input.value = '';
541
544
  }
542
545
  }
543
- // Public method to trigger file selection from parent
544
546
  triggerFileInput() {
545
547
  this.fileInput?.nativeElement?.click();
546
548
  }
547
- // Public method to append file selection from parent
548
549
  appendFileFromParent(file) {
549
550
  this.handleFiles([file]);
550
551
  }
551
- // Public method to upload files programmatically from parent
552
552
  uploadFilesFromParent(files) {
553
553
  this.handleFiles(files);
554
554
  }
555
- // Public method to get new uploaded file IDs
556
555
  getUploadedFileIds() {
557
556
  return this.uploadedNewFileIds();
558
557
  }
559
- // Public method to clear new files (after save)
560
558
  clearNewFiles() {
561
559
  this.newFiles.set([]);
562
560
  this.uploadedResponses = [];
561
+ this.uploadedFile.set([]);
562
+ this.documentId = null;
563
+ this.emitUploadState();
563
564
  }
564
- // Public method to remove a new file by ID
565
565
  removeNewFile(fileId) {
566
566
  this.newFiles.update((files) => files.filter((f) => f.id !== fileId));
567
567
  }
568
- // Check if there are pending/uploading files
569
- // File handling
568
+ deleteFile() {
569
+ this.uploadedFile.set([]);
570
+ this.newFiles.set([]);
571
+ this.documentId = null;
572
+ this.uploadErrorMessage = null;
573
+ this.control?.reset();
574
+ this.filesUploaded.emit([]);
575
+ this.fileDeleted.emit({ fileId: this.documentId || '', isNew: true });
576
+ this.emitUploadState();
577
+ }
578
+ onDeleteFile(file) {
579
+ const isNewFile = file.isNew;
580
+ this.fileDeleted.emit({ fileId: file.id, isNew: !!isNewFile });
581
+ if (isNewFile) {
582
+ this.newFiles.update((files) => files.filter((f) => f.id !== file.id));
583
+ if (!this.newFiles().length) {
584
+ this.documentId = null;
585
+ this.control?.reset();
586
+ this.emitUploadState();
587
+ }
588
+ }
589
+ }
590
+ onPreviewFile(file) {
591
+ this.filePreview.emit(file);
592
+ }
570
593
  handleFiles(filesToProcess) {
571
594
  const validFiles = [];
572
595
  for (const file of filesToProcess) {
573
- // Validate file size
574
596
  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
- });
597
+ const error = `File ${file.name} exceeds maximum size of ${this.formatFileSize(this.maxFileSize())}`;
598
+ this.uploadErrorMessage = error;
599
+ this.uploadError.emit({ file, error });
600
+ continue;
601
+ }
602
+ if (!this.isValidFileType(file)) {
603
+ const error = `File type not allowed: ${file.type}`;
604
+ this.uploadErrorMessage = error;
605
+ this.uploadError.emit({ file, error });
579
606
  continue;
580
607
  }
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
608
  validFiles.push(file);
590
609
  }
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());
610
+ if (!validFiles.length)
611
+ return;
612
+ if (this.uploadFn()) {
613
+ this.uploadFileImmediately(validFiles[0]);
614
+ return;
596
615
  }
616
+ this.uploadedFile.set(validFiles);
617
+ this.filesUploaded.emit(validFiles);
597
618
  }
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('/*', '/'));
619
+ uploadFileImmediately(file) {
620
+ const uploadFn = this.uploadFn();
621
+ if (!uploadFn)
622
+ return;
623
+ const tempId = this.generateTempId(file);
624
+ const fileItem = {
625
+ id: tempId,
626
+ fileName: file.name,
627
+ size: file.size,
628
+ mimeType: file.type,
629
+ progress: 0,
630
+ status: UploadStatus.UPLOADING,
631
+ file,
632
+ isNew: true,
633
+ };
634
+ this.uploadErrorMessage = null;
635
+ this.documentId = null;
636
+ this.newFiles.set([fileItem]);
637
+ this.uploadedFile.set([file]);
638
+ this.emitUploadState();
639
+ const progressInterval = setInterval(() => {
640
+ this.newFiles.update((files) => files.map((f) => f.id === tempId && (f.progress ?? 0) < 90
641
+ ? { ...f, progress: (f.progress ?? 0) + 10 }
642
+ : f));
643
+ }, 200);
644
+ this.progressIntervals.set(tempId, progressInterval);
645
+ this._subscription.add(uploadFn(file)
646
+ .pipe(finalize(() => {
647
+ const interval = this.progressIntervals.get(tempId);
648
+ if (interval) {
649
+ clearInterval(interval);
650
+ this.progressIntervals.delete(tempId);
615
651
  }
616
- return fileType === type;
652
+ }))
653
+ .subscribe({
654
+ next: (response) => {
655
+ this.documentId = response.documentId;
656
+ this.newFiles.set([
657
+ {
658
+ ...fileItem,
659
+ id: response.documentId,
660
+ progress: 100,
661
+ status: UploadStatus.SUCCESS,
662
+ },
663
+ ]);
664
+ this.control?.setValue(response.documentId);
665
+ this.filesUploaded.emit(response);
666
+ this.emitUploadState();
667
+ },
668
+ error: (error) => {
669
+ this.uploadErrorMessage = error?.message || 'Upload failed. Please try again.';
670
+ this.newFiles.set([
671
+ {
672
+ ...fileItem,
673
+ progress: 0,
674
+ status: UploadStatus.FAILED,
675
+ error: this.uploadErrorMessage ?? undefined,
676
+ },
677
+ ]);
678
+ this.uploadedFile.set([]);
679
+ this.emitUploadState();
680
+ },
681
+ }));
682
+ }
683
+ emitUploadState() {
684
+ const isUploading = this.newFiles().some((f) => f.status === UploadStatus.UPLOADING);
685
+ this.uploadStateChange.emit({
686
+ isUploading,
687
+ documentId: this.documentId,
688
+ hasFile: !!this.documentId || this.uploadedFile().length > 0,
617
689
  });
618
690
  }
619
691
  updateFileFromAttachment(attachment) {
620
692
  this.newFiles.update((currentFiles) => {
621
693
  return currentFiles.map((file) => {
622
- // Match by file name and size
623
694
  if (file.fileName === attachment.nameFile && file.size === attachment.size) {
624
695
  const updatedFile = {
625
696
  ...file,
626
697
  progress: attachment.status?.percentage ?? 0,
627
698
  error: attachment.errorMessage,
628
699
  };
629
- // If upload succeeded, update with response data from serverResponse
630
700
  if (attachment.uploadStatus === UploadStatus.SUCCESS && attachment.serverResponse) {
631
701
  const serverData = attachment.serverResponse;
632
702
  const responseFile = {
@@ -647,20 +717,22 @@ class FileManagementComponent extends BaseInputComponent {
647
717
  });
648
718
  });
649
719
  }
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));
720
+ isValidFileType(file) {
721
+ const accepted = this.acceptedTypes();
722
+ if (accepted === '*' || accepted === '*/*')
723
+ return true;
724
+ const acceptedTypes = accepted.split(',').map((t) => t.trim().toLowerCase());
725
+ const fileType = file.type.toLowerCase();
726
+ const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();
727
+ return acceptedTypes.some((type) => {
728
+ if (type.startsWith('.')) {
729
+ return fileExt === type;
730
+ }
731
+ if (type.endsWith('/*')) {
732
+ return fileType.startsWith(type.replace('/*', '/'));
733
+ }
734
+ return fileType === type;
735
+ });
664
736
  }
665
737
  generateTempId(file) {
666
738
  return `temp-${file.name}-${file.size}-${Date.now()}`;
@@ -674,12 +746,12 @@ class FileManagementComponent extends BaseInputComponent {
674
746
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
675
747
  }
676
748
  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" }] });
749
+ 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 @if (file.status === UploadStatus.UPLOADING || (file.progress && file.progress > 0)) {\r\n <p-progressBar [value]=\"file.progress ?? 0\" [showValue]=\"false\" styleClass=\"upload-progress-bar\"></p-progressBar>\r\n }\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-progress-bar{margin-bottom:10px;height:4px}.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: "component", type: ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FileSizePipe, name: "fileSize" }] });
678
750
  }
679
751
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileManagementComponent, decorators: [{
680
752
  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: [{
753
+ args: [{ selector: 'app-file-management', imports: [CommonModule, TranslatePipe, ButtonModule, TooltipModule, FileSizePipe, ProgressBar], 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 @if (file.status === UploadStatus.UPLOADING || (file.progress && file.progress > 0)) {\r\n <p-progressBar [value]=\"file.progress ?? 0\" [showValue]=\"false\" styleClass=\"upload-progress-bar\"></p-progressBar>\r\n }\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-progress-bar{margin-bottom:10px;height:4px}.upload-error{display:flex;align-items:center;gap:.5rem;color:#ef4444;font-size:.875rem;margin-top:.5rem}\n"] }]
754
+ }], 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
755
  type: Output
684
756
  }], fileDeleted: [{
685
757
  type: Output
@@ -691,6 +763,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
691
763
  type: Output
692
764
  }], newFilesChange: [{
693
765
  type: Output
766
+ }], uploadStateChange: [{
767
+ type: Output
694
768
  }], fileInput: [{
695
769
  type: ViewChild,
696
770
  args: ['fileInput']
@@ -837,7 +911,7 @@ function numbersOnlyValidator(control) {
837
911
  return isNumbersOnly ? null : { numbersOnly: true };
838
912
  }
839
913
 
840
- const WHITESPACE_REGEX = /\s/;
914
+ const IGNORED_CHARS_REGEX = /[\s\d]/; // Whitespace and digits
841
915
  function maxRepeatedCharsValidator(maxRepeats = 3) {
842
916
  return (control) => {
843
917
  const value = control.value;
@@ -847,7 +921,7 @@ function maxRepeatedCharsValidator(maxRepeats = 3) {
847
921
  let count = 1;
848
922
  let prevChar = null;
849
923
  for (const char of str) {
850
- if (WHITESPACE_REGEX.test(char)) {
924
+ if (IGNORED_CHARS_REGEX.test(char)) {
851
925
  continue;
852
926
  }
853
927
  if (prevChar !== null && char === prevChar) {
@@ -1624,6 +1698,7 @@ class HijriCalendarComponent {
1624
1698
  i18n;
1625
1699
  cdr;
1626
1700
  model;
1701
+ disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
1627
1702
  dateSelected = new EventEmitter();
1628
1703
  language = 'en';
1629
1704
  renderer = inject(Renderer2);
@@ -1659,9 +1734,15 @@ class HijriCalendarComponent {
1659
1734
  date.month === today.month &&
1660
1735
  date.day === today.day;
1661
1736
  }
1662
- isDisabled = () => false;
1737
+ isDisabled = (date) => {
1738
+ if (!this.disabledDays || this.disabledDays.length === 0)
1739
+ return false;
1740
+ const ngbDate = new NgbDate(date.year, date.month, date.day);
1741
+ const gregDate = this.calendar.toGregorian(ngbDate);
1742
+ return this.disabledDays.includes(gregDate.getDay());
1743
+ };
1663
1744
  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 });
1664
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: HijriCalendarComponent, isStandalone: true, selector: "app-hijri-calendar", inputs: { model: "model", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1745
+ 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: [
1665
1746
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura },
1666
1747
  { provide: NgbDatepickerI18n, useClass: DynamicHijriI18n }
1667
1748
  ], 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"] }] });
@@ -1674,6 +1755,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1674
1755
  ], 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" }]
1675
1756
  }], ctorParameters: () => [{ type: i1$6.NgbDatepickerI18n }, { type: i0.ChangeDetectorRef }], propDecorators: { model: [{
1676
1757
  type: Input
1758
+ }], disabledDays: [{
1759
+ type: Input
1677
1760
  }], dateSelected: [{
1678
1761
  type: Output
1679
1762
  }], language: [{
@@ -1786,6 +1869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1786
1869
 
1787
1870
  class GregorianCalendarComponent {
1788
1871
  model;
1872
+ disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
1789
1873
  dateSelected = new EventEmitter();
1790
1874
  renderer = inject(Renderer2);
1791
1875
  language = 'en';
@@ -1819,9 +1903,14 @@ class GregorianCalendarComponent {
1819
1903
  date.month === today.month &&
1820
1904
  date.day === today.day;
1821
1905
  }
1822
- isDisabled = () => false;
1906
+ isDisabled = (date) => {
1907
+ if (!this.disabledDays || this.disabledDays.length === 0)
1908
+ return false;
1909
+ const jsDate = new Date(date.year, date.month - 1, date.day);
1910
+ return this.disabledDays.includes(jsDate.getDay());
1911
+ };
1823
1912
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GregorianCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1824
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: GregorianCalendarComponent, isStandalone: true, selector: "app-gregorian-calendar", inputs: { model: "model", language: "language" }, outputs: { dateSelected: "dateSelected" }, providers: [
1913
+ 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: [
1825
1914
  { provide: NgbCalendar, useClass: NgbCalendarGregorian },
1826
1915
  { provide: NgbDatepickerI18n, useClass: DynamicGregorianI18n }
1827
1916
  ], 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 });
@@ -1834,6 +1923,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1834
1923
  ], encapsulation: ViewEncapsulation.None, 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" }]
1835
1924
  }], propDecorators: { model: [{
1836
1925
  type: Input
1926
+ }], disabledDays: [{
1927
+ type: Input
1837
1928
  }], dateSelected: [{
1838
1929
  type: Output
1839
1930
  }], language: [{
@@ -1935,6 +2026,7 @@ class DualCalendarComponent {
1935
2026
  gregorianModel;
1936
2027
  hijriModel;
1937
2028
  currentLang = signal('ar', ...(ngDevMode ? [{ debugName: "currentLang" }] : []));
2029
+ disabledDays = []; // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
1938
2030
  gregorianUTC = new EventEmitter();
1939
2031
  onClose = new EventEmitter();
1940
2032
  gregorianUTCValue = '';
@@ -2107,9 +2199,9 @@ class DualCalendarComponent {
2107
2199
  }
2108
2200
  }
2109
2201
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DualCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2110
- 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", isShown: "isShown", appedToBody: "appedToBody" }, outputs: { gregorianUTC: "gregorianUTC", onClose: "onClose" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
2202
+ 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: [
2111
2203
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura }
2112
- ], 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 (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()\" (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", "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", "language"], outputs: ["dateSelected"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
2204
+ ], 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: [
2113
2205
  trigger('slideDown', [
2114
2206
  state('closed', style({
2115
2207
  height: '0px',
@@ -2161,7 +2253,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2161
2253
  GregorianCalendarComponent
2162
2254
  ], providers: [
2163
2255
  { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura }
2164
- ], 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 (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()\" (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"] }]
2256
+ ], 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"] }]
2165
2257
  }], ctorParameters: () => [], propDecorators: { calendarWrapper: [{
2166
2258
  type: ViewChild,
2167
2259
  args: ['calendarWrapper']
@@ -2177,6 +2269,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2177
2269
  type: Input
2178
2270
  }], currentLang: [{
2179
2271
  type: Input
2272
+ }], disabledDays: [{
2273
+ type: Input
2180
2274
  }], gregorianUTC: [{
2181
2275
  type: Output
2182
2276
  }], onClose: [{
@@ -2208,7 +2302,6 @@ var FormFieldTypeEnum;
2208
2302
 
2209
2303
  class DynamicFormComponent {
2210
2304
  dynamicFormData;
2211
- // Generic field change outputs (optional for consumers)
2212
2305
  selectButtonChange = new EventEmitter();
2213
2306
  selectChange = new EventEmitter();
2214
2307
  selectClicked = new EventEmitter();
@@ -2217,11 +2310,16 @@ class DynamicFormComponent {
2217
2310
  autoCompleteSelect = new EventEmitter();
2218
2311
  popUpFilesUploaded = new EventEmitter();
2219
2312
  fileDeleted = new EventEmitter();
2313
+ uploadStateChange = new EventEmitter();
2220
2314
  inputsNames = [];
2221
2315
  formGroup;
2222
2316
  inputsMap;
2317
+ standaloneFileControl = new FormControl(null);
2223
2318
  fieldType = FormFieldTypeEnum;
2224
2319
  getFormControl = FormUtils.getFormControl;
2320
+ get fileUploadConfig() {
2321
+ return this.dynamicFormData?.fileUpload;
2322
+ }
2225
2323
  ngOnInit() {
2226
2324
  this.updateFormState();
2227
2325
  }
@@ -2235,8 +2333,17 @@ class DynamicFormComponent {
2235
2333
  this.inputsMap = this.dynamicFormData?.inputsMap;
2236
2334
  this.inputsNames = Object.keys(this.inputsMap || {});
2237
2335
  }
2238
- getAcceptedTypes() {
2239
- return FileExtentions.toString();
2336
+ getAcceptedTypes(fileUpload) {
2337
+ return fileUpload?.acceptedTypes ?? FileExtentions.toString();
2338
+ }
2339
+ getMaxFileSize(fileUpload) {
2340
+ return fileUpload?.maxFileSize ?? 262144000;
2341
+ }
2342
+ getFileUploadConfig(inputName) {
2343
+ return this.inputsMap[inputName]?.fileUpload ?? this.dynamicFormData?.fileUpload;
2344
+ }
2345
+ hasUploadFileField() {
2346
+ return this.inputsNames.some((name) => this.inputsMap[name].fieldType === FormFieldTypeEnum.UPLOAD_FILE);
2240
2347
  }
2241
2348
  onFilesUploaded(file) {
2242
2349
  this.popUpFilesUploaded.emit(file);
@@ -2244,13 +2351,16 @@ class DynamicFormComponent {
2244
2351
  onFileDeleted(file) {
2245
2352
  this.fileDeleted.emit(file);
2246
2353
  }
2354
+ onUploadStateChange(state) {
2355
+ this.uploadStateChange.emit(state);
2356
+ }
2247
2357
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2248
- 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)\"></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", "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" }] });
2358
+ 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 [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", "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" }] });
2249
2359
  }
2250
2360
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, decorators: [{
2251
2361
  type: Component,
2252
2362
  args: [{ selector: 'app-dynamic-form', standalone: true, imports: [
2253
- CommonModule,
2363
+ NgClass,
2254
2364
  ReactiveFormsModule,
2255
2365
  DatePickerComponent,
2256
2366
  ValidationErrorsPipe,
@@ -2264,7 +2374,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2264
2374
  SwitchComponent,
2265
2375
  LocalizedLabelPipe,
2266
2376
  CheckboxModule,
2267
- ], 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)\"></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"] }]
2377
+ ], 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\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"] }]
2268
2378
  }], propDecorators: { dynamicFormData: [{
2269
2379
  type: Input,
2270
2380
  args: [{ required: true }]
@@ -2284,6 +2394,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2284
2394
  type: Output
2285
2395
  }], fileDeleted: [{
2286
2396
  type: Output
2397
+ }], uploadStateChange: [{
2398
+ type: Output
2287
2399
  }] } });
2288
2400
 
2289
2401
  class ConfirmationDialogComponent extends DynamicDialogRef {
@@ -2294,23 +2406,43 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
2294
2406
  _subscription = new Subscription();
2295
2407
  dialogFormData;
2296
2408
  uploadedFile;
2409
+ documentId = null;
2410
+ uploadState = { isUploading: false, documentId: null, hasFile: false };
2411
+ get hasFileUpload() {
2412
+ return !!this.dialogFormData?.fileUpload;
2413
+ }
2414
+ get isConfirmDisabled() {
2415
+ if (this.dialogFormData?.formGroup?.invalid) {
2416
+ return true;
2417
+ }
2418
+ if (this.hasFileUpload && (this.uploadState.isUploading || !this.uploadState.documentId)) {
2419
+ return true;
2420
+ }
2421
+ return false;
2422
+ }
2297
2423
  ngOnDestroy() {
2298
2424
  this._subscription.unsubscribe();
2299
2425
  }
2300
2426
  ngOnInit() {
2301
- // closing when navigating back from the browser
2302
2427
  this._subscription.add(this.router.events.pipe(filter((event) => event instanceof NavigationStart)).subscribe(() => {
2303
2428
  if (this.dynamicDialogConfig) {
2304
2429
  this._ref.close(false);
2305
2430
  }
2306
2431
  }));
2307
- this.dialogFormData = this.dynamicDialogConfig.data?.inputForm;
2432
+ const inputForm = this.dynamicDialogConfig.data?.inputForm;
2433
+ const fileUpload = inputForm?.fileUpload ?? this.dynamicDialogConfig.data?.fileUpload;
2434
+ this.dialogFormData = {
2435
+ ...inputForm,
2436
+ formGroup: inputForm?.formGroup ?? new FormGroup({}),
2437
+ inputsMap: inputForm?.inputsMap ?? {},
2438
+ fileUpload,
2439
+ };
2308
2440
  }
2309
2441
  submit() {
2310
- // we should pass submitted data when using form dialog
2311
- // const submitData = { submitted: true, data: this.dialogFormData?.formGroup?.value };
2312
- // this._ref.close(this.dynamicDialogConfig.data.inputForm ? submitData : true);
2313
- if (this.uploadedFile) {
2442
+ if (this.documentId) {
2443
+ this._ref.close({ isSubmitted: true, documentId: this.documentId });
2444
+ }
2445
+ else if (this.uploadedFile) {
2314
2446
  this._ref.close({ isSubmitted: true, file: this.uploadedFile });
2315
2447
  }
2316
2448
  else {
@@ -2321,12 +2453,25 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
2321
2453
  this._ref.close(false);
2322
2454
  }
2323
2455
  onPopFilesUploaded(file) {
2324
- this.uploadedFile = file;
2456
+ if (file?.documentId) {
2457
+ this.documentId = file.documentId;
2458
+ }
2459
+ else {
2460
+ this.uploadedFile = file;
2461
+ }
2325
2462
  }
2326
- onFileDeleted(file) {
2463
+ onFileDeleted() {
2464
+ this.documentId = null;
2465
+ this.uploadedFile = null;
2466
+ }
2467
+ onUploadStateChange(state) {
2468
+ this.uploadState = state;
2469
+ if (state.documentId) {
2470
+ this.documentId = state.documentId;
2471
+ }
2327
2472
  }
2328
2473
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2329
- 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 });
2474
+ 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 });
2330
2475
  }
2331
2476
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
2332
2477
  type: Component,
@@ -2336,7 +2481,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2336
2481
  DynamicDialogModule,
2337
2482
  DynamicFormComponent,
2338
2483
  TranslatePipe,
2339
- ], 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" }]
2484
+ ], 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"] }]
2340
2485
  }] });
2341
2486
 
2342
2487
  class ReadMoreComponent {