@corp-products/ui-components 3.6.7 → 3.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { ViewEncapsulation, Component, Input, ChangeDetectionStrategy, model, inject, Pipe, EventEmitter, Output, Injectable, Renderer2, ChangeDetectorRef, signal, effect, HostListener, ViewChild, InjectionToken, Injector, createComponent, ViewContainerRef, ApplicationRef, EnvironmentInjector, DestroyRef } from '@angular/core';
|
|
2
|
+
import { ViewEncapsulation, Component, Input, ChangeDetectionStrategy, model, inject, Pipe, EventEmitter, Output, Injectable, Renderer2, ChangeDetectorRef, signal, effect, HostListener, ViewChild, input, computed, InjectionToken, Injector, createComponent, ViewContainerRef, ApplicationRef, EnvironmentInjector, DestroyRef } from '@angular/core';
|
|
3
3
|
import * as i1 from 'primeng/button';
|
|
4
4
|
import { Button, ButtonModule, ButtonStyle } from 'primeng/button';
|
|
5
5
|
import * as i1$1 from '@angular/common';
|
|
@@ -870,6 +870,7 @@ var FormFieldTypeEnum;
|
|
|
870
870
|
FormFieldTypeEnum["SWITCH"] = "switch";
|
|
871
871
|
FormFieldTypeEnum["AUTO_COMPLETE"] = "auto-complete";
|
|
872
872
|
FormFieldTypeEnum["HIJRI_DATE_PICKER"] = "hijri-date";
|
|
873
|
+
FormFieldTypeEnum["UPLOAD_FILE"] = "upload-file";
|
|
873
874
|
})(FormFieldTypeEnum || (FormFieldTypeEnum = {}));
|
|
874
875
|
|
|
875
876
|
const WEEKDAYS = {
|
|
@@ -1532,6 +1533,342 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1532
1533
|
args: ['document:click', ['$event']]
|
|
1533
1534
|
}] } });
|
|
1534
1535
|
|
|
1536
|
+
/**
|
|
1537
|
+
* Transforms file size from bytes to readable format (B, KB, MB, GB, TB).
|
|
1538
|
+
*
|
|
1539
|
+
* Usage:
|
|
1540
|
+
* {{ fileSize | fileSize }} // Default: auto unit, 2 decimals
|
|
1541
|
+
* {{ fileSize | fileSize:0 }} // Auto unit, 0 decimals
|
|
1542
|
+
* {{ fileSize | fileSize:2:'MB' }} // Force MB, 2 decimals
|
|
1543
|
+
*
|
|
1544
|
+
* @param value - File size in bytes
|
|
1545
|
+
* @param decimals - Number of decimal places (default: 2)
|
|
1546
|
+
* @param unit - Unit: 'B', 'KB', 'MB', 'GB', 'TB' (default: auto)
|
|
1547
|
+
*/
|
|
1548
|
+
class FileSizePipe {
|
|
1549
|
+
units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
1550
|
+
k = 1024;
|
|
1551
|
+
transform(bytes, decimals = 2, unit) {
|
|
1552
|
+
if (bytes === null || bytes === undefined || isNaN(bytes)) {
|
|
1553
|
+
return '0 B';
|
|
1554
|
+
}
|
|
1555
|
+
if (bytes === 0) {
|
|
1556
|
+
return '0 B';
|
|
1557
|
+
}
|
|
1558
|
+
// If a specific unit is requested
|
|
1559
|
+
if (unit) {
|
|
1560
|
+
const unitIndex = this.units.indexOf(unit);
|
|
1561
|
+
if (unitIndex === -1) {
|
|
1562
|
+
return this.autoFormat(bytes, decimals);
|
|
1563
|
+
}
|
|
1564
|
+
const divisor = Math.pow(this.k, unitIndex);
|
|
1565
|
+
const value = bytes / divisor;
|
|
1566
|
+
return `${this.formatNumber(value, decimals)} ${unit}`;
|
|
1567
|
+
}
|
|
1568
|
+
// Auto-detect the best unit
|
|
1569
|
+
return this.autoFormat(bytes, decimals);
|
|
1570
|
+
}
|
|
1571
|
+
autoFormat(bytes, decimals) {
|
|
1572
|
+
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(this.k));
|
|
1573
|
+
const unitIndex = Math.min(i, this.units.length - 1);
|
|
1574
|
+
const value = bytes / Math.pow(this.k, unitIndex);
|
|
1575
|
+
return `${this.formatNumber(value, decimals)} ${this.units[unitIndex]}`;
|
|
1576
|
+
}
|
|
1577
|
+
formatNumber(value, decimals) {
|
|
1578
|
+
return parseFloat(value.toFixed(decimals)).toString();
|
|
1579
|
+
}
|
|
1580
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileSizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1581
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FileSizePipe, isStandalone: true, name: "fileSize" });
|
|
1582
|
+
}
|
|
1583
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileSizePipe, decorators: [{
|
|
1584
|
+
type: Pipe,
|
|
1585
|
+
args: [{
|
|
1586
|
+
name: 'fileSize',
|
|
1587
|
+
standalone: true,
|
|
1588
|
+
}]
|
|
1589
|
+
}] });
|
|
1590
|
+
|
|
1591
|
+
var UploadStatus;
|
|
1592
|
+
(function (UploadStatus) {
|
|
1593
|
+
UploadStatus["PENDING"] = "pending";
|
|
1594
|
+
UploadStatus["UPLOADING"] = "uploading";
|
|
1595
|
+
UploadStatus["SUCCESS"] = "success";
|
|
1596
|
+
UploadStatus["FAILED"] = "failed";
|
|
1597
|
+
})(UploadStatus || (UploadStatus = {}));
|
|
1598
|
+
|
|
1599
|
+
class FileManagementComponent {
|
|
1600
|
+
// Inputs
|
|
1601
|
+
existingFiles = input([], ...(ngDevMode ? [{ debugName: "existingFiles" }] : []));
|
|
1602
|
+
acceptedTypes = input('*', ...(ngDevMode ? [{ debugName: "acceptedTypes" }] : []));
|
|
1603
|
+
maxFileSize = input(10485760, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : [])); //250 MB
|
|
1604
|
+
maxConcurrentUploads = input(3, ...(ngDevMode ? [{ debugName: "maxConcurrentUploads" }] : []));
|
|
1605
|
+
showTable = input(true, ...(ngDevMode ? [{ debugName: "showTable" }] : []));
|
|
1606
|
+
showDropZone = input(true, ...(ngDevMode ? [{ debugName: "showDropZone" }] : []));
|
|
1607
|
+
allowPreview = input(true, ...(ngDevMode ? [{ debugName: "allowPreview" }] : []));
|
|
1608
|
+
permissonKey = input('', ...(ngDevMode ? [{ debugName: "permissonKey" }] : []));
|
|
1609
|
+
allowedActions = input([], ...(ngDevMode ? [{ debugName: "allowedActions" }] : []));
|
|
1610
|
+
uploadedFile = signal([], ...(ngDevMode ? [{ debugName: "uploadedFile" }] : []));
|
|
1611
|
+
// Outputs
|
|
1612
|
+
filesUploaded = new EventEmitter();
|
|
1613
|
+
fileDeleted = new EventEmitter();
|
|
1614
|
+
filePreview = new EventEmitter();
|
|
1615
|
+
fileDownload = new EventEmitter();
|
|
1616
|
+
uploadError = new EventEmitter();
|
|
1617
|
+
newFilesChange = new EventEmitter();
|
|
1618
|
+
fileInput;
|
|
1619
|
+
destroy$ = new Subject();
|
|
1620
|
+
// State - separate new uploads from existing files
|
|
1621
|
+
isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
|
|
1622
|
+
newFiles = signal([], ...(ngDevMode ? [{ debugName: "newFiles" }] : [])); // Files being uploaded or newly uploaded
|
|
1623
|
+
uploadedResponses = [];
|
|
1624
|
+
// Combined files list for the table (existing + new)
|
|
1625
|
+
allFiles = computed(() => {
|
|
1626
|
+
const existing = this.existingFiles().map((f) => ({
|
|
1627
|
+
...f,
|
|
1628
|
+
status: undefined, // Don't show status for existing files
|
|
1629
|
+
isNew: false,
|
|
1630
|
+
}));
|
|
1631
|
+
const newOnes = this.newFiles();
|
|
1632
|
+
return [...newOnes, ...existing];
|
|
1633
|
+
}, ...(ngDevMode ? [{ debugName: "allFiles" }] : []));
|
|
1634
|
+
// Get only successfully uploaded new file IDs
|
|
1635
|
+
uploadedNewFileIds = computed(() => {
|
|
1636
|
+
return this.newFiles()
|
|
1637
|
+
.filter((f) => f.status === UploadStatus.SUCCESS && f.id && !f.id.startsWith('temp-'))
|
|
1638
|
+
.map((f) => f.id);
|
|
1639
|
+
}, ...(ngDevMode ? [{ debugName: "uploadedNewFileIds" }] : []));
|
|
1640
|
+
// Formatted accepted file types for display
|
|
1641
|
+
formattedAcceptedTypes = computed(() => {
|
|
1642
|
+
const accepted = this.acceptedTypes();
|
|
1643
|
+
if (accepted === '*' || accepted === '*/*')
|
|
1644
|
+
return '';
|
|
1645
|
+
return accepted
|
|
1646
|
+
.split(',')
|
|
1647
|
+
.map((type) => type.trim().replace('.', '').toUpperCase())
|
|
1648
|
+
.join(', ');
|
|
1649
|
+
}, ...(ngDevMode ? [{ debugName: "formattedAcceptedTypes" }] : []));
|
|
1650
|
+
// Table configuration
|
|
1651
|
+
constructor() {
|
|
1652
|
+
// Emit when new files change
|
|
1653
|
+
effect(() => {
|
|
1654
|
+
const newFilesList = this.newFiles();
|
|
1655
|
+
this.newFilesChange.emit(newFilesList);
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
ngOnDestroy() {
|
|
1659
|
+
this.destroy$.next();
|
|
1660
|
+
this.destroy$.complete();
|
|
1661
|
+
}
|
|
1662
|
+
// Drag & Drop handlers
|
|
1663
|
+
onDragOver(event) {
|
|
1664
|
+
event.preventDefault();
|
|
1665
|
+
event.stopPropagation();
|
|
1666
|
+
this.isDragOver.set(true);
|
|
1667
|
+
}
|
|
1668
|
+
onDragLeave(event) {
|
|
1669
|
+
event.preventDefault();
|
|
1670
|
+
event.stopPropagation();
|
|
1671
|
+
this.isDragOver.set(false);
|
|
1672
|
+
}
|
|
1673
|
+
onDrop(event) {
|
|
1674
|
+
event.preventDefault();
|
|
1675
|
+
event.stopPropagation();
|
|
1676
|
+
this.isDragOver.set(false);
|
|
1677
|
+
const droppedFiles = event.dataTransfer?.files;
|
|
1678
|
+
if (droppedFiles) {
|
|
1679
|
+
this.handleFiles(Array.from(droppedFiles));
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
// Browse button handler
|
|
1683
|
+
onBrowseClick() {
|
|
1684
|
+
this.fileInput.nativeElement.click();
|
|
1685
|
+
}
|
|
1686
|
+
onFileInputChange(event) {
|
|
1687
|
+
const input = event.target;
|
|
1688
|
+
if (input.files) {
|
|
1689
|
+
this.handleFiles(Array.from(input.files));
|
|
1690
|
+
// Reset input to allow selecting the same file again
|
|
1691
|
+
input.value = '';
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
// Public method to trigger file selection from parent
|
|
1695
|
+
triggerFileInput() {
|
|
1696
|
+
this.fileInput?.nativeElement?.click();
|
|
1697
|
+
}
|
|
1698
|
+
// Public method to append file selection from parent
|
|
1699
|
+
appendFileFromParent(file) {
|
|
1700
|
+
this.handleFiles([file]);
|
|
1701
|
+
}
|
|
1702
|
+
// Public method to upload files programmatically from parent
|
|
1703
|
+
uploadFilesFromParent(files) {
|
|
1704
|
+
this.handleFiles(files);
|
|
1705
|
+
}
|
|
1706
|
+
// Public method to get new uploaded file IDs
|
|
1707
|
+
getUploadedFileIds() {
|
|
1708
|
+
return this.uploadedNewFileIds();
|
|
1709
|
+
}
|
|
1710
|
+
// Public method to clear new files (after save)
|
|
1711
|
+
clearNewFiles() {
|
|
1712
|
+
this.newFiles.set([]);
|
|
1713
|
+
this.uploadedResponses = [];
|
|
1714
|
+
}
|
|
1715
|
+
// Public method to remove a new file by ID
|
|
1716
|
+
removeNewFile(fileId) {
|
|
1717
|
+
this.newFiles.update((files) => files.filter((f) => f.id !== fileId));
|
|
1718
|
+
}
|
|
1719
|
+
// Check if there are pending/uploading files
|
|
1720
|
+
// File handling
|
|
1721
|
+
handleFiles(filesToProcess) {
|
|
1722
|
+
const validFiles = [];
|
|
1723
|
+
for (const file of filesToProcess) {
|
|
1724
|
+
// Validate file size
|
|
1725
|
+
if (file.size > this.maxFileSize()) {
|
|
1726
|
+
this.uploadError.emit({
|
|
1727
|
+
file,
|
|
1728
|
+
error: `File ${file.name} exceeds maximum size of ${this.formatFileSize(this.maxFileSize())}`,
|
|
1729
|
+
});
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1732
|
+
// Validate file type
|
|
1733
|
+
// if (!this.isValidFileType(file)) {
|
|
1734
|
+
// this.uploadError.emit({
|
|
1735
|
+
// file,
|
|
1736
|
+
// error: `File type not allowed: ${file.type}`,
|
|
1737
|
+
// });
|
|
1738
|
+
// continue;
|
|
1739
|
+
// }
|
|
1740
|
+
validFiles.push(file);
|
|
1741
|
+
}
|
|
1742
|
+
if (validFiles.length > 0) {
|
|
1743
|
+
// this.uploadFiles(validFiles);
|
|
1744
|
+
this.uploadedFile.set(validFiles);
|
|
1745
|
+
this.filesUploaded.emit(validFiles);
|
|
1746
|
+
console.log('uploadedFile', this.uploadedFile());
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
deleteFile() {
|
|
1750
|
+
this.uploadedFile.set([]);
|
|
1751
|
+
this.filesUploaded.emit([]);
|
|
1752
|
+
}
|
|
1753
|
+
isValidFileType(file) {
|
|
1754
|
+
const accepted = this.acceptedTypes();
|
|
1755
|
+
if (accepted === '*' || accepted === '*/*')
|
|
1756
|
+
return true;
|
|
1757
|
+
const acceptedTypes = accepted.split(',').map((t) => t.trim().toLowerCase());
|
|
1758
|
+
const fileType = file.type.toLowerCase();
|
|
1759
|
+
const fileExt = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
1760
|
+
return acceptedTypes.some((type) => {
|
|
1761
|
+
if (type.startsWith('.')) {
|
|
1762
|
+
return fileExt === type;
|
|
1763
|
+
}
|
|
1764
|
+
if (type.endsWith('/*')) {
|
|
1765
|
+
return fileType.startsWith(type.replace('/*', '/'));
|
|
1766
|
+
}
|
|
1767
|
+
return fileType === type;
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
updateFileFromAttachment(attachment) {
|
|
1771
|
+
this.newFiles.update((currentFiles) => {
|
|
1772
|
+
return currentFiles.map((file) => {
|
|
1773
|
+
// Match by file name and size
|
|
1774
|
+
if (file.fileName === attachment.nameFile && file.size === attachment.size) {
|
|
1775
|
+
const updatedFile = {
|
|
1776
|
+
...file,
|
|
1777
|
+
progress: attachment.status?.percentage ?? 0,
|
|
1778
|
+
error: attachment.errorMessage,
|
|
1779
|
+
};
|
|
1780
|
+
// If upload succeeded, update with response data from serverResponse
|
|
1781
|
+
if (attachment.uploadStatus === UploadStatus.SUCCESS && attachment.serverResponse) {
|
|
1782
|
+
const serverData = attachment.serverResponse;
|
|
1783
|
+
const responseFile = {
|
|
1784
|
+
id: attachment.id || serverData?.id || file.id,
|
|
1785
|
+
fileName: serverData?.fileName || attachment.nameFile,
|
|
1786
|
+
size: serverData?.size || attachment.size,
|
|
1787
|
+
mimeType: serverData?.mimeType || file.mimeType,
|
|
1788
|
+
};
|
|
1789
|
+
this.uploadedResponses.push(responseFile);
|
|
1790
|
+
return {
|
|
1791
|
+
...updatedFile,
|
|
1792
|
+
id: responseFile.id,
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
return updatedFile;
|
|
1796
|
+
}
|
|
1797
|
+
return file;
|
|
1798
|
+
});
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
// Actions
|
|
1802
|
+
onDeleteFile(file) {
|
|
1803
|
+
const isNewFile = file.isNew;
|
|
1804
|
+
this.fileDeleted.emit({ fileId: file.id, isNew: !!isNewFile });
|
|
1805
|
+
if (isNewFile) {
|
|
1806
|
+
// Remove from newFiles list immediately for new uploads
|
|
1807
|
+
this.newFiles.update((files) => files.filter((f) => f.id !== file.id));
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
onPreviewFile(file) {
|
|
1811
|
+
this.filePreview.emit(file);
|
|
1812
|
+
}
|
|
1813
|
+
removeFileFromList(fileId) {
|
|
1814
|
+
this.newFiles.update((current) => current.filter((f) => f.id !== fileId));
|
|
1815
|
+
}
|
|
1816
|
+
generateTempId(file) {
|
|
1817
|
+
return `temp-${file.name}-${file.size}-${Date.now()}`;
|
|
1818
|
+
}
|
|
1819
|
+
formatFileSize(bytes) {
|
|
1820
|
+
if (bytes === 0)
|
|
1821
|
+
return '0 B';
|
|
1822
|
+
const k = 1024;
|
|
1823
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
1824
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1825
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
1826
|
+
}
|
|
1827
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileManagementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1828
|
+
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 }], 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" }] });
|
|
1829
|
+
}
|
|
1830
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileManagementComponent, decorators: [{
|
|
1831
|
+
type: Component,
|
|
1832
|
+
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"] }]
|
|
1833
|
+
}], ctorParameters: () => [], 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: [{
|
|
1834
|
+
type: Output
|
|
1835
|
+
}], fileDeleted: [{
|
|
1836
|
+
type: Output
|
|
1837
|
+
}], filePreview: [{
|
|
1838
|
+
type: Output
|
|
1839
|
+
}], fileDownload: [{
|
|
1840
|
+
type: Output
|
|
1841
|
+
}], uploadError: [{
|
|
1842
|
+
type: Output
|
|
1843
|
+
}], newFilesChange: [{
|
|
1844
|
+
type: Output
|
|
1845
|
+
}], fileInput: [{
|
|
1846
|
+
type: ViewChild,
|
|
1847
|
+
args: ['fileInput']
|
|
1848
|
+
}] } });
|
|
1849
|
+
|
|
1850
|
+
class LocalizedLabelPipe {
|
|
1851
|
+
translateService = inject(TranslateService);
|
|
1852
|
+
transform(label) {
|
|
1853
|
+
if (!label)
|
|
1854
|
+
return '';
|
|
1855
|
+
const lang = this.translateService.getCurrentLang() || 'ar';
|
|
1856
|
+
const suffix = lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
1857
|
+
const key = label + `${suffix}`;
|
|
1858
|
+
return key;
|
|
1859
|
+
}
|
|
1860
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: LocalizedLabelPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1861
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: LocalizedLabelPipe, isStandalone: true, name: "localizedLabel", pure: false });
|
|
1862
|
+
}
|
|
1863
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: LocalizedLabelPipe, decorators: [{
|
|
1864
|
+
type: Pipe,
|
|
1865
|
+
args: [{
|
|
1866
|
+
name: 'localizedLabel',
|
|
1867
|
+
standalone: true,
|
|
1868
|
+
pure: false,
|
|
1869
|
+
}]
|
|
1870
|
+
}] });
|
|
1871
|
+
|
|
1535
1872
|
class DynamicFormComponent {
|
|
1536
1873
|
dynamicFormData;
|
|
1537
1874
|
// Generic field change outputs (optional for consumers)
|
|
@@ -1540,6 +1877,8 @@ class DynamicFormComponent {
|
|
|
1540
1877
|
switchChange = new EventEmitter();
|
|
1541
1878
|
autoCompleteSearch = new EventEmitter();
|
|
1542
1879
|
autoCompleteSelect = new EventEmitter();
|
|
1880
|
+
popUpFilesUploaded = new EventEmitter();
|
|
1881
|
+
fileDeleted = new EventEmitter();
|
|
1543
1882
|
inputsNames = [];
|
|
1544
1883
|
formGroup;
|
|
1545
1884
|
inputsMap;
|
|
@@ -1550,8 +1889,14 @@ class DynamicFormComponent {
|
|
|
1550
1889
|
this.inputsMap = this.dynamicFormData?.inputsMap;
|
|
1551
1890
|
this.inputsNames = Object.keys(this.inputsMap || {});
|
|
1552
1891
|
}
|
|
1892
|
+
onFilesUploaded(file) {
|
|
1893
|
+
this.popUpFilesUploaded.emit(file);
|
|
1894
|
+
}
|
|
1895
|
+
onFileDeleted(file) {
|
|
1896
|
+
this.fileDeleted.emit(file);
|
|
1897
|
+
}
|
|
1553
1898
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1554
|
-
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", switchChange: "switchChange", autoCompleteSearch: "autoCompleteSearch", autoCompleteSelect: "autoCompleteSelect" }, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"grid grid-cols-12 gap-x-2\">\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
|
|
1899
|
+
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", switchChange: "switchChange", autoCompleteSearch: "autoCompleteSearch", autoCompleteSelect: "autoCompleteSelect", popUpFilesUploaded: "popUpFilesUploaded", fileDeleted: "fileDeleted" }, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"grid grid-cols-12 gap-x-2\">\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 [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 }\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'\">\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 <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')\"\r\n [filter]=\"inputsMap[inputName].filter || false\"\r\n [multiple]=\"inputsMap[inputName].multiple || false\" [showClear]=\"inputsMap[inputName].showClear || false\"\r\n [checkmark]=\"inputsMap[inputName].checkmark ?? true\" [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n (change)=\"selectChange.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.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'\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager [maxFileSize]=\"262144000\" [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\" (filesUploaded)=\"onFilesUploaded($event)\" (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>\r\n", styles: [""], 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[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", "hourFormat", "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"], outputs: ["gregorianUTC", "onClose"] }, { kind: "component", type: InputComponent, selector: "stc-input", inputs: ["type", "contentType", "size", "prefix", "rows", "cols", "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", "selectedItemsLabel", "basicInput", "variant", "defaultColor"], outputs: ["change"] }, { kind: "component", type: AutoCompleteComponent, selector: "stc-auto-complete", inputs: ["selectedItemTemplate", "items", "minLengthToSearch", "delay", "basicInput", "typeAhead", "variant"], outputs: ["onSearch", "selectOption"] }, { kind: "component", type: SwitchComponent, selector: "stc-switch", inputs: ["label", "key", "checked"], outputs: ["onChange"] }, { kind: "pipe", type: ValidationErrorsPipe, name: "validationErrors" }, { kind: "pipe", type: LocalizedLabelPipe, name: "localizedLabel" }] });
|
|
1555
1900
|
}
|
|
1556
1901
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
1557
1902
|
type: Component,
|
|
@@ -1564,10 +1909,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1564
1909
|
SelectButtonComponent,
|
|
1565
1910
|
DualCalendarComponent,
|
|
1566
1911
|
InputComponent,
|
|
1912
|
+
FileManagementComponent,
|
|
1567
1913
|
SelectComponent,
|
|
1568
1914
|
AutoCompleteComponent,
|
|
1569
1915
|
SwitchComponent,
|
|
1570
|
-
|
|
1916
|
+
LocalizedLabelPipe
|
|
1917
|
+
], template: "<form [formGroup]=\"formGroup\" class=\"dynamic-form\">\r\n <div class=\"grid grid-cols-12 gap-x-2\">\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 [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 }\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'\">\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 <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')\"\r\n [filter]=\"inputsMap[inputName].filter || false\"\r\n [multiple]=\"inputsMap[inputName].multiple || false\" [showClear]=\"inputsMap[inputName].showClear || false\"\r\n [checkmark]=\"inputsMap[inputName].checkmark ?? true\" [filterBy]=\"inputsMap[inputName].filterBy || ''\"\r\n [selectedItemsLabel]=\"inputsMap[inputName].selectedItemsLabel || ''\"\r\n [size]=\"inputsMap[inputName].size || 'small'\" [variant]=\"inputsMap[inputName].variant || 'over'\"\r\n (change)=\"selectChange.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.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'\" />\r\n }\r\n @case(fieldType.UPLOAD_FILE) {\r\n <app-file-management #fileManager #groupFileManager [maxFileSize]=\"262144000\" [maxConcurrentUploads]=\"1\"\r\n [allowPreview]=\"true\" (filesUploaded)=\"onFilesUploaded($event)\" (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>\r\n" }]
|
|
1571
1918
|
}], propDecorators: { dynamicFormData: [{
|
|
1572
1919
|
type: Input,
|
|
1573
1920
|
args: [{ required: true }]
|
|
@@ -1581,6 +1928,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1581
1928
|
type: Output
|
|
1582
1929
|
}], autoCompleteSelect: [{
|
|
1583
1930
|
type: Output
|
|
1931
|
+
}], popUpFilesUploaded: [{
|
|
1932
|
+
type: Output
|
|
1933
|
+
}], fileDeleted: [{
|
|
1934
|
+
type: Output
|
|
1584
1935
|
}] } });
|
|
1585
1936
|
|
|
1586
1937
|
class ConfirmationDialogComponent extends DynamicDialogRef {
|
|
@@ -1590,6 +1941,7 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
|
|
|
1590
1941
|
_ref = inject(DynamicDialogRef);
|
|
1591
1942
|
_subscription = new Subscription();
|
|
1592
1943
|
dialogFormData;
|
|
1944
|
+
uploadedFile;
|
|
1593
1945
|
ngOnDestroy() {
|
|
1594
1946
|
this._subscription.unsubscribe();
|
|
1595
1947
|
}
|
|
@@ -1606,13 +1958,23 @@ class ConfirmationDialogComponent extends DynamicDialogRef {
|
|
|
1606
1958
|
// we should pass submitted data when using form dialog
|
|
1607
1959
|
// const submitData = { submitted: true, data: this.dialogFormData?.formGroup?.value };
|
|
1608
1960
|
// this._ref.close(this.dynamicDialogConfig.data.inputForm ? submitData : true);
|
|
1609
|
-
this.
|
|
1961
|
+
if (this.uploadedFile) {
|
|
1962
|
+
this._ref.close({ isSubmitted: true, file: this.uploadedFile });
|
|
1963
|
+
}
|
|
1964
|
+
else {
|
|
1965
|
+
this._ref.close(true);
|
|
1966
|
+
}
|
|
1610
1967
|
}
|
|
1611
1968
|
close() {
|
|
1612
1969
|
this._ref.close(false);
|
|
1613
1970
|
}
|
|
1971
|
+
onPopFilesUploaded(file) {
|
|
1972
|
+
this.uploadedFile = file;
|
|
1973
|
+
}
|
|
1974
|
+
onFileDeleted(file) {
|
|
1975
|
+
}
|
|
1614
1976
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1615
|
-
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\"></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}", 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", "switchChange", "autoCompleteSearch", "autoCompleteSelect"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
|
|
1977
|
+
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", "switchChange", "autoCompleteSearch", "autoCompleteSelect", "popUpFilesUploaded", "fileDeleted"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
|
|
1616
1978
|
}
|
|
1617
1979
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogComponent, decorators: [{
|
|
1618
1980
|
type: Component,
|
|
@@ -1622,7 +1984,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1622
1984
|
DynamicDialogModule,
|
|
1623
1985
|
DynamicFormComponent,
|
|
1624
1986
|
TranslatePipe,
|
|
1625
|
-
], 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\"></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}" }]
|
|
1987
|
+
], 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" }]
|
|
1626
1988
|
}] });
|
|
1627
1989
|
|
|
1628
1990
|
class ReadMoreComponent {
|
|
@@ -2026,7 +2388,7 @@ class ConfirmationDialogService {
|
|
|
2026
2388
|
return of(false); // or EMPTY / throwError — depending on your logic
|
|
2027
2389
|
}
|
|
2028
2390
|
// Emit true/false when dialog closes
|
|
2029
|
-
return ref.onClose.pipe(filter$1((res) => res !== undefined), map((res) =>
|
|
2391
|
+
return ref.onClose.pipe(filter$1((res) => res !== undefined), map((res) => res));
|
|
2030
2392
|
}
|
|
2031
2393
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogService, deps: [{ token: i1$8.DialogService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2032
2394
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfirmationDialogService, providedIn: 'root' });
|