cat-documents-ng 0.2.81 → 0.2.82
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.
|
@@ -2892,7 +2892,7 @@ class DocumentUploadComponent {
|
|
|
2892
2892
|
* @param event - Event containing the selected files
|
|
2893
2893
|
*/
|
|
2894
2894
|
async onSelectedFiles(event) {
|
|
2895
|
-
|
|
2895
|
+
const startIndex = this.uploadedFiles.length;
|
|
2896
2896
|
for (let i = 0; i < event.currentFiles.length; i++) {
|
|
2897
2897
|
const file = event.currentFiles[i];
|
|
2898
2898
|
const initialUploadedFile = {
|
|
@@ -2910,20 +2910,18 @@ class DocumentUploadComponent {
|
|
|
2910
2910
|
this.uploadedFiles.push(initialUploadedFile);
|
|
2911
2911
|
this.fileProgress.set(file, 0);
|
|
2912
2912
|
}
|
|
2913
|
-
// Start uploading files one by one
|
|
2914
2913
|
for (let i = 0; i < event.currentFiles.length; i++) {
|
|
2915
2914
|
const file = event.currentFiles[i];
|
|
2915
|
+
const actualIndex = startIndex + i; // Calculate the actual index in the array
|
|
2916
2916
|
try {
|
|
2917
|
-
await this.handleTemplatedUpload(file,
|
|
2917
|
+
await this.handleTemplatedUpload(file, actualIndex);
|
|
2918
2918
|
}
|
|
2919
2919
|
catch (error) {
|
|
2920
2920
|
console.error(`Failed to upload file ${i + 1}/${event.currentFiles.length}: ${file.name}`, error);
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
this.uploadedFiles[
|
|
2925
|
-
this.uploadedFiles[fileIndex].isUploading = false;
|
|
2926
|
-
this.uploadedFiles[fileIndex].progress = -1;
|
|
2921
|
+
if (this.uploadedFiles[actualIndex]) {
|
|
2922
|
+
this.uploadedFiles[actualIndex].hasError = true;
|
|
2923
|
+
this.uploadedFiles[actualIndex].isUploading = false;
|
|
2924
|
+
this.uploadedFiles[actualIndex].progress = -1;
|
|
2927
2925
|
}
|
|
2928
2926
|
}
|
|
2929
2927
|
}
|
|
@@ -2988,15 +2986,15 @@ class DocumentUploadComponent {
|
|
|
2988
2986
|
async handleTemplatedUpload(file, index) {
|
|
2989
2987
|
if (!this.formService.validateContextId(this.contextId, 'Context ID is required for upload.'))
|
|
2990
2988
|
return;
|
|
2991
|
-
// Start progress
|
|
2992
|
-
this.
|
|
2989
|
+
// Start smooth progress from 1 to 90
|
|
2990
|
+
this.startSmoothProgress(file, index);
|
|
2993
2991
|
try {
|
|
2994
2992
|
const response = await this.documentUploadService.uploadFile(file, this.contextId);
|
|
2995
2993
|
// Update the uploaded file with response data
|
|
2996
2994
|
const uploadedFile = {
|
|
2997
2995
|
file: file,
|
|
2998
2996
|
formattedSize: this.businessService.formatFileSize(file.size, this.config),
|
|
2999
|
-
progress:
|
|
2997
|
+
progress: 100,
|
|
3000
2998
|
uploadResponse: response,
|
|
3001
2999
|
url: response.url,
|
|
3002
3000
|
contentType: response.contentType,
|
|
@@ -3007,37 +3005,37 @@ class DocumentUploadComponent {
|
|
|
3007
3005
|
};
|
|
3008
3006
|
// Replace the file in the array with the response
|
|
3009
3007
|
this.uploadedFiles[index] = uploadedFile;
|
|
3010
|
-
this.fileProgress.set(file,
|
|
3008
|
+
this.fileProgress.set(file, 100);
|
|
3011
3009
|
this.cdr.detectChanges();
|
|
3012
3010
|
}
|
|
3013
3011
|
catch (error) {
|
|
3014
3012
|
// Mark file as error
|
|
3015
3013
|
this.uploadedFiles[index].hasError = true;
|
|
3016
3014
|
this.uploadedFiles[index].isUploading = false;
|
|
3017
|
-
this.uploadedFiles[index].progress =
|
|
3018
|
-
this.fileProgress.set(file,
|
|
3015
|
+
this.uploadedFiles[index].progress = 0;
|
|
3016
|
+
this.fileProgress.set(file, 0);
|
|
3019
3017
|
this.cdr.detectChanges();
|
|
3020
3018
|
console.error('Upload failed:', error);
|
|
3021
3019
|
}
|
|
3022
3020
|
}
|
|
3023
3021
|
/**
|
|
3024
|
-
* Starts progress
|
|
3022
|
+
* Starts smooth progress animation for a file upload from 0 to 90.
|
|
3025
3023
|
* @param file - The file being uploaded
|
|
3026
3024
|
* @param index - The index of the file in uploadedFiles array
|
|
3027
3025
|
*/
|
|
3028
|
-
|
|
3026
|
+
startSmoothProgress(file, index) {
|
|
3029
3027
|
let progress = 0;
|
|
3030
3028
|
const progressInterval = setInterval(() => {
|
|
3031
3029
|
if (progress < 90) {
|
|
3032
|
-
progress +=
|
|
3033
|
-
this.uploadedFiles[index].progress =
|
|
3034
|
-
this.fileProgress.set(file,
|
|
3030
|
+
progress += 2; // Smooth increment of 2%
|
|
3031
|
+
this.uploadedFiles[index].progress = progress;
|
|
3032
|
+
this.fileProgress.set(file, progress);
|
|
3035
3033
|
this.cdr.detectChanges();
|
|
3036
3034
|
}
|
|
3037
3035
|
else {
|
|
3038
3036
|
clearInterval(progressInterval);
|
|
3039
3037
|
}
|
|
3040
|
-
},
|
|
3038
|
+
}, 100); // Update every 100ms for smooth progress
|
|
3041
3039
|
}
|
|
3042
3040
|
/**
|
|
3043
3041
|
* Removes a document from the uploaded files list.
|
|
@@ -3077,7 +3075,10 @@ class DocumentUploadComponent {
|
|
|
3077
3075
|
* @param file - The file to get progress for
|
|
3078
3076
|
* @returns The upload progress percentage (0-100)
|
|
3079
3077
|
*/
|
|
3080
|
-
getProgress(file) {
|
|
3078
|
+
getProgress(file) {
|
|
3079
|
+
const progress = this.fileProgress.get(file);
|
|
3080
|
+
return progress !== undefined ? progress : 0;
|
|
3081
|
+
}
|
|
3081
3082
|
/**
|
|
3082
3083
|
* Checks if a file is currently uploading.
|
|
3083
3084
|
* @param file - The file to check
|
|
@@ -3085,20 +3086,66 @@ class DocumentUploadComponent {
|
|
|
3085
3086
|
*/
|
|
3086
3087
|
isFileUploading(file) {
|
|
3087
3088
|
const progress = this.fileProgress.get(file);
|
|
3088
|
-
return progress !== undefined && progress > 0 && progress <
|
|
3089
|
+
return progress !== undefined && progress > 0 && progress < 100;
|
|
3089
3090
|
}
|
|
3090
3091
|
/**
|
|
3091
3092
|
* Checks if a file has been successfully uploaded.
|
|
3092
3093
|
* @param file - The file to check
|
|
3093
3094
|
* @returns True if the file is uploaded, false otherwise
|
|
3094
3095
|
*/
|
|
3095
|
-
isFileUploaded(file) { return this.fileProgress.get(file) ===
|
|
3096
|
+
isFileUploaded(file) { return this.fileProgress.get(file) === 100; }
|
|
3096
3097
|
/**
|
|
3097
3098
|
* Checks if a file upload encountered an error.
|
|
3098
3099
|
* @param file - The file to check
|
|
3099
3100
|
* @returns True if the file has an error, false otherwise
|
|
3100
3101
|
*/
|
|
3101
|
-
isFileError(file) {
|
|
3102
|
+
isFileError(file) {
|
|
3103
|
+
const progress = this.fileProgress.get(file);
|
|
3104
|
+
const uploadedFile = this.uploadedFiles.find(uf => uf.file === file);
|
|
3105
|
+
return progress === 0 && uploadedFile?.hasError === true;
|
|
3106
|
+
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Gets the number of files currently uploading.
|
|
3109
|
+
* @returns The count of files currently being uploaded
|
|
3110
|
+
*/
|
|
3111
|
+
getUploadingCount() {
|
|
3112
|
+
return this.uploadedFiles.filter(file => file.isUploading).length;
|
|
3113
|
+
}
|
|
3114
|
+
/**
|
|
3115
|
+
* Gets the number of files that have been successfully uploaded.
|
|
3116
|
+
* @returns The count of successfully uploaded files
|
|
3117
|
+
*/
|
|
3118
|
+
getUploadedCount() {
|
|
3119
|
+
return this.uploadedFiles.filter(file => file.progress === 100 && !file.hasError).length;
|
|
3120
|
+
}
|
|
3121
|
+
/**
|
|
3122
|
+
* Gets the number of files that failed to upload.
|
|
3123
|
+
* @returns The count of failed uploads
|
|
3124
|
+
*/
|
|
3125
|
+
getFailedCount() {
|
|
3126
|
+
return this.uploadedFiles.filter(file => file.hasError).length;
|
|
3127
|
+
}
|
|
3128
|
+
/**
|
|
3129
|
+
* Gets the total number of files in the upload queue.
|
|
3130
|
+
* @returns The total count of files (uploading + uploaded + failed)
|
|
3131
|
+
*/
|
|
3132
|
+
getTotalCount() {
|
|
3133
|
+
return this.uploadedFiles.length;
|
|
3134
|
+
}
|
|
3135
|
+
/**
|
|
3136
|
+
* Checks if there are any files currently uploading.
|
|
3137
|
+
* @returns True if any files are uploading, false otherwise
|
|
3138
|
+
*/
|
|
3139
|
+
hasUploadingFiles() {
|
|
3140
|
+
return this.getUploadingCount() > 0;
|
|
3141
|
+
}
|
|
3142
|
+
/**
|
|
3143
|
+
* Checks if all files have completed (either uploaded or failed).
|
|
3144
|
+
* @returns True if all files have completed, false otherwise
|
|
3145
|
+
*/
|
|
3146
|
+
allFilesCompleted() {
|
|
3147
|
+
return this.getTotalCount() > 0 && this.getUploadingCount() === 0;
|
|
3148
|
+
}
|
|
3102
3149
|
/**
|
|
3103
3150
|
* Resets the form to its initial state.
|
|
3104
3151
|
* Clears all selections, uploaded files, and progress tracking.
|
|
@@ -3263,11 +3310,11 @@ class DocumentUploadComponent {
|
|
|
3263
3310
|
this.dataService.destroy();
|
|
3264
3311
|
}
|
|
3265
3312
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DocumentUploadComponent, deps: [{ token: DocumentUploadService }, { token: i3.PrimeNGConfig }, { token: FileFormatService }, { token: i3.MessageService }, { token: i0.ChangeDetectorRef }, { token: DocumentUploadBusinessService }, { token: DocumentUploadFormService }, { token: DocumentUploadDataService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3266
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DocumentUploadComponent, isStandalone: false, selector: "lib-document-upload", inputs: { contextId: "contextId" }, outputs: { onFormValidationChange: "onFormValidationChange", onUploadSuccess: "onUploadSuccess" }, viewQueries: [{ propertyName: "fileUploader", first: true, predicate: ["fileUploader"], descendants: true }], ngImport: i0, template: "<div class=\"document-upload-container\">\n <!-- Assignment Section -->\n <div class=\"assignment-section\">\n <h4>Assign to Applicant(s) or Application</h4>\n <div class=\"radio-group\">\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Applicant\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'applicant'\"\n ></p-radioButton>\n <label [for]=\"'applicant'\" class=\"radio-label\">Applicant(s)</label>\n </div>\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Application\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'application'\"\n ></p-radioButton>\n <label [for]=\"'application'\" class=\"radio-label\">Application</label>\n </div>\n </div>\n </div>\n\n <!-- Applicant Selection (only shown when Applicant is selected) -->\n <div class=\"applicant-section\" *ngIf=\"selectedAssignmentType === 'Applicant'\">\n <h4>Select Applicant(s)</h4>\n <div class=\"grid\">\n <div \n *ngFor=\"let applicant of filteredApplicantList\" \n class=\"applicant-item col-12 md:col-6\"\n >\n <p-radioButton \n name=\"selectedApplicant\"\n [value]=\"applicant._id\"\n [(ngModel)]=\"selectedApplicant\"\n [inputId]=\"'applicant-' + applicant._id\"\n (onClick)=\"onApplicantSelectionChange()\"\n ></p-radioButton>\n <label [for]=\"'applicant-' + applicant._id\" class=\"applicant-label\">\n {{ applicant.name }}\n </label>\n </div>\n </div>\n </div>\n\n <!-- Category Selection -->\n <div class=\"category-section\">\n <h4>Category</h4>\n <p-dropdown\n [options]=\"categoryOptions\"\n [(ngModel)]=\"selectedCategory\"\n placeholder=\"Select Category type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onCategoryChange()\"\n [disabled]=\"!categoryOptions.length\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- Document Type Selection -->\n <div class=\"document-type-section\">\n <h4>Document Type</h4>\n <p-dropdown\n [options]=\"documentTypeOptions\"\n [(ngModel)]=\"selectedDocumentType\"\n placeholder=\"Select Document type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onDocumentTypeChange()\"\n [disabled]=\"!documentTypeOptions.length || !selectedCategory\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- File Upload Section -->\n <div class=\"file-upload-section\">\n <h4>Upload Documents</h4>\n <div class=\"grid\">\n <div class=\"col-12 md:col-12\">\n <p-fileUpload \n #fileUploader \n [multiple]=\"true\" \n auto=\"true\" \n accept=\"image/png,application/pdf\" \n maxFileSize=\"26214400\"\n (onSelect)=\"onSelectedFiles($event)\"\n >\n <ng-template pTemplate=\"header\" let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\">\n <div class=\"docHeader p-2 flex flex-wrap justify-content-between align-items-center flex-1 gap-2\">\n <div class=\"flex gap-2\">\n <p-button \n (onClick)=\"choose($event, chooseCallback)\" \n icon=\"pi pi-images\" \n [rounded]=\"true\"\n [outlined]=\"true\" \n />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\" let-removeFileCallback=\"removeFileCallback\"\n let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"col-12 md:col-12 p-0\">\n <div class=\"col-12 md:col-12 p-0\" *ngIf=\"uploadedFiles.length > 0\">\n <div *ngFor=\"let uploadedFile of uploadedFiles; let i = index\"\n class=\"m-0 flex flex-column align-items-center gap-1 mt-3\">\n <div class=\"col-12 md:col-12 p-0 flex documentInfo\">\n <div class=\"documentImage\">\n <img src=\"../../../../assets/images/document.png\" [alt]=\"uploadedFile.file.name\" width=\"45\" height=\"50\"\n class=\"object-contain\" />\n </div>\n <div class=\"flex w-full flex-column mt-2 ml-2\">\n <div class=\"flex justify-content-between\">\n <div style=\"font-weight: bold;font-size: 14px\">\n {{ uploadedFile.fileName || uploadedFile.file.name }}\n </div>\n <i class=\"pi pi-times cursor-pointer\" (click)=\"handleDocumentRemove(uploadedFile.file,i)\"></i>\n </div>\n <div class=\"flex justify-content-between mt-1\">\n <div style=\"color: #676B89; font-size: 12px;\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\">\n <i [class]=\"{\n 'pi pi-verified': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'pi pi-spin pi-spinner': uploadedFile.isUploading,\n 'pi pi-exclamation-triangle': uploadedFile.hasError\n }\"></i>\n {{ uploadedFile.formattedSize }}\n </div>\n <div class=\"white-space-nowrap\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\" \n style=\"font-family: 14px;\"> \n <span *ngIf=\"uploadedFile.hasError\">Upload Failed</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress === 100\">Uploaded</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress < 100\">{{ uploadedFile.progress }}%</span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"col-12 md:col-12 p-0\">\n <p-progressBar \n [value]=\"uploadedFile.hasError ? 0 : uploadedFile.progress\" \n [showValue]=\"false\" \n styleClass=\"h-1/2rem md:ml-auto relative\"\n [ngClass]=\"{\n 'exceeded-progress-bar': uploadedFile.progress > 100,\n 'error-progress-bar': uploadedFile.hasError\n }\"\n >\n </p-progressBar>\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"empty\" let-chooseCallback=\"chooseCallback\">\n <div *ngIf=\"!uploadedFiles.length\" class=\"flex align-items-center justify-content-center flex-column\"\n (click)=\"triggerFileUpload()\">\n <i class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400\"></i>\n <p class=\"mt-4 mb-0\">Drag and drop files here to upload.</p>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n </p-fileUpload>\n </div>\n </div>\n </div>\n</div>", styles: [".flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.flex-col{flex-direction:column}.text-muted-color{color:#6c757d}.p-fileupload-buttonbar{padding:0}.p-fileupload-content{background-color:#0f8bfd1a}.p-fileupload .p-fileupload-content{padding:1rem}.docHeader .p-button-icon{padding:.5rem}.document-upload-container{padding:1rem;max-height:90vh}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1.5rem}.assignment-section h4,.applicant-section h4,.category-section h4,.document-type-section h4,.file-upload-section h4{margin:0 0 .75rem;font-size:1rem;font-weight:600;color:#212529}.upload-status{margin-bottom:1rem;padding:.75rem;background-color:#f8f9fa;border-radius:.5rem;border-left:4px solid #0F8BFD}.upload-status .status-message{display:flex;align-items:center;font-size:.9rem;color:#495057}.upload-status .status-message .pi{font-size:1rem}.upload-status .status-message .pi.pi-spinner{color:#0f8bfd}.upload-status .status-message .pi.pi-check-circle{color:#28a745}.upload-status .status-message .pi.pi-clock{color:#ffc107}.radio-group{display:flex;gap:.75rem}.radio-item{display:flex;align-items:center;gap:.5rem;cursor:pointer;transition:all .2s ease}.radio-item:has(.p-radiobutton-box.p-highlight) .radio-label{color:#0f8bfd;font-weight:600}.radio-label{font-size:.9rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease}::ng-deep .p-dropdown{width:100%}::ng-deep .p-dropdown .p-dropdown-label{font-size:.9rem;color:#495057}::ng-deep .p-dropdown .p-dropdown-trigger{color:#6c757d}::ng-deep .p-dropdown:not(.p-disabled):hover{border-color:#0f8bfd}::ng-deep .p-dropdown:not(.p-disabled).p-focus{border-color:#0f8bfd;box-shadow:0 0 0 2px #0f8bfd33}::ng-deep .p-radiobutton .p-radiobutton-box{border-color:#ced4da;border-radius:4px;width:18px;height:18px}::ng-deep .p-radiobutton .p-radiobutton-box:hover{border-color:#0f8bfd}::ng-deep .p-radiobutton .p-radiobutton-box.p-highlight{border-color:#0f8bfd;background-color:transparent}::ng-deep .p-radiobutton .p-radiobutton-icon{background-color:#0f8bfd;width:8px;height:8px;border-radius:2px}.applicant-section .grid{margin:0;padding:0}.applicant-section .applicant-item{display:flex;align-items:center;gap:.75rem;border-radius:.5rem;background-color:#fff;transition:all .2s ease;cursor:pointer;margin-bottom:.75rem}.applicant-section .applicant-item:has(.p-radiobutton-box.p-highlight) .applicant-label{color:#0f8bfd;font-weight:600}.applicant-section .applicant-label{font-size:.95rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-weight:500;margin:0;transition:color .2s ease}@media (max-width: 768px){.applicant-section .applicant-item{margin-bottom:.5rem;padding:.75rem;min-height:50px}.applicant-section .applicant-label{font-size:.9rem}.document-upload-container{padding:.75rem}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1rem}}.category-section .p-dropdown,.document-type-section .p-dropdown{width:100%!important;min-width:100%!important}.category-section .p-dropdown-panel,.document-type-section .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-dropdown{width:100%!important}:host ::ng-deep .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-progressbar.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}:host ::ng-deep .p-progressbar.success-progress-bar .p-progressbar-value{background-color:#28a745!important}:host ::ng-deep .p-progressbar.exceeded-progress-bar .p-progressbar-value{background-color:#ffc107!important}.applicant-list{display:none}.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}.text-green-500{color:#28a745!important}.text-blue-500{color:#0f8bfd!important}.text-red-500{color:#dc3545!important}.pi-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i9.FileUpload, selector: "p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "component", type: i10.ProgressBar, selector: "p-progressBar", inputs: ["value", "showValue", "styleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: i11.RadioButton, selector: "p-radioButton", inputs: ["value", "formControlName", "name", "disabled", "label", "variant", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "labelStyleClass", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i13.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
3313
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DocumentUploadComponent, isStandalone: false, selector: "lib-document-upload", inputs: { contextId: "contextId" }, outputs: { onFormValidationChange: "onFormValidationChange", onUploadSuccess: "onUploadSuccess" }, viewQueries: [{ propertyName: "fileUploader", first: true, predicate: ["fileUploader"], descendants: true }], ngImport: i0, template: "<div class=\"document-upload-container\">\n <!-- Assignment Section -->\n <div class=\"assignment-section\">\n <h4>Assign to Applicant(s) or Application</h4>\n <div class=\"radio-group\">\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Applicant\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'applicant'\"\n ></p-radioButton>\n <label [for]=\"'applicant'\" class=\"radio-label\">Applicant(s)</label>\n </div>\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Application\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'application'\"\n ></p-radioButton>\n <label [for]=\"'application'\" class=\"radio-label\">Application</label>\n </div>\n </div>\n </div>\n\n <!-- Applicant Selection (only shown when Applicant is selected) -->\n <div class=\"applicant-section\" *ngIf=\"selectedAssignmentType === 'Applicant'\">\n <h4>Select Applicant(s)</h4>\n <div class=\"grid\">\n <div \n *ngFor=\"let applicant of filteredApplicantList\" \n class=\"applicant-item col-12 md:col-6\"\n >\n <p-radioButton \n name=\"selectedApplicant\"\n [value]=\"applicant._id\"\n [(ngModel)]=\"selectedApplicant\"\n [inputId]=\"'applicant-' + applicant._id\"\n (onClick)=\"onApplicantSelectionChange()\"\n ></p-radioButton>\n <label [for]=\"'applicant-' + applicant._id\" class=\"applicant-label\">\n {{ applicant.name }}\n </label>\n </div>\n </div>\n </div>\n\n <!-- Category Selection -->\n <div class=\"category-section\">\n <h4>Category</h4>\n <p-dropdown\n [options]=\"categoryOptions\"\n [(ngModel)]=\"selectedCategory\"\n placeholder=\"Select Category type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onCategoryChange()\"\n [disabled]=\"!categoryOptions.length\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- Document Type Selection -->\n <div class=\"document-type-section\">\n <h4>Document Type</h4>\n <p-dropdown\n [options]=\"documentTypeOptions\"\n [(ngModel)]=\"selectedDocumentType\"\n placeholder=\"Select Document type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onDocumentTypeChange()\"\n [disabled]=\"!documentTypeOptions.length || !selectedCategory\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- File Upload Section -->\n <div class=\"file-upload-section\">\n <h4>Upload Documents</h4>\n \n <!-- Upload Status Summary -->\n <div class=\"upload-status-summary\" *ngIf=\"getTotalCount() > 0\">\n <div class=\"status-grid\">\n <div class=\"status-item\">\n <span class=\"status-label\">Total Files:</span>\n <span class=\"status-value\">{{ getTotalCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getUploadingCount() > 0\">\n <span class=\"status-label\">Uploading:</span>\n <span class=\"status-value uploading\">{{ getUploadingCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getUploadedCount() > 0\">\n <span class=\"status-label\">Uploaded:</span>\n <span class=\"status-value uploaded\">{{ getUploadedCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getFailedCount() > 0\">\n <span class=\"status-label\">Failed:</span>\n <span class=\"status-value failed\">{{ getFailedCount() }}</span>\n </div>\n </div>\n </div>\n \n <div class=\"grid\">\n <div class=\"col-12 md:col-12\">\n <p-fileUpload \n #fileUploader \n [multiple]=\"true\" \n auto=\"true\" \n accept=\"image/png,application/pdf\" \n maxFileSize=\"26214400\"\n (onSelect)=\"onSelectedFiles($event)\"\n >\n <ng-template pTemplate=\"header\" let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\">\n <div class=\"docHeader p-2 flex flex-wrap justify-content-between align-items-center flex-1 gap-2\">\n <div class=\"flex gap-2\">\n <p-button \n (onClick)=\"choose($event, chooseCallback)\" \n icon=\"pi pi-images\" \n [rounded]=\"true\"\n [outlined]=\"true\" \n />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\" let-removeFileCallback=\"removeFileCallback\"\n let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"col-12 md:col-12 p-0\">\n <div class=\"col-12 md:col-12 p-0\" *ngIf=\"uploadedFiles.length > 0\">\n <div *ngFor=\"let uploadedFile of uploadedFiles; let i = index\"\n class=\"m-0 flex flex-column align-items-center gap-1 mt-3\">\n <div class=\"col-12 md:col-12 p-0 flex documentInfo\">\n <div class=\"documentImage\">\n <img src=\"../../../../assets/images/document.png\" [alt]=\"uploadedFile.file.name\" width=\"45\" height=\"50\"\n class=\"object-contain\" />\n </div>\n <div class=\"flex w-full flex-column mt-2 ml-2\">\n <div class=\"flex justify-content-between\">\n <div style=\"font-weight: bold;font-size: 14px\">\n {{ uploadedFile.fileName || uploadedFile.file.name }}\n </div>\n <i class=\"pi pi-times cursor-pointer\" (click)=\"handleDocumentRemove(uploadedFile.file,i)\"></i>\n </div>\n <div class=\"flex justify-content-between mt-1\">\n <div style=\"color: #676B89; font-size: 12px;\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\">\n <i [class]=\"{\n 'pi pi-verified': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'pi pi-spin pi-spinner': uploadedFile.isUploading,\n 'pi pi-exclamation-triangle': uploadedFile.hasError\n }\"></i>\n {{ uploadedFile.formattedSize }}\n </div>\n <div class=\"white-space-nowrap\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\" \n style=\"font-family: 14px;\"> \n <span *ngIf=\"uploadedFile.hasError\">Upload Failed</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress === 100\">Uploaded</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress < 100\">{{ uploadedFile.progress }}%</span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"col-12 md:col-12 p-0\">\n <p-progressBar \n [value]=\"uploadedFile.hasError ? 0 : uploadedFile.progress\" \n [showValue]=\"false\" \n styleClass=\"h-1/2rem md:ml-auto relative\"\n [ngClass]=\"{\n 'exceeded-progress-bar': uploadedFile.progress > 100,\n 'error-progress-bar': uploadedFile.hasError\n }\"\n >\n </p-progressBar>\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"empty\" let-chooseCallback=\"chooseCallback\">\n <div *ngIf=\"!uploadedFiles.length\" class=\"flex align-items-center justify-content-center flex-column\"\n (click)=\"triggerFileUpload()\">\n <i class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400\"></i>\n <p class=\"mt-4 mb-0\">Drag and drop files here to upload.</p>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n </p-fileUpload>\n </div>\n </div>\n </div>\n</div>", styles: [".flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.flex-col{flex-direction:column}.text-muted-color{color:#6c757d}.p-fileupload-buttonbar{padding:0}.p-fileupload-content{background-color:#0f8bfd1a}.p-fileupload .p-fileupload-content{padding:1rem}.docHeader .p-button-icon{padding:.5rem}.document-upload-container{padding:1rem;max-height:90vh}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1.5rem}.assignment-section h4,.applicant-section h4,.category-section h4,.document-type-section h4,.file-upload-section h4{margin:0 0 .75rem;font-size:1rem;font-weight:600;color:#212529}.upload-status{margin-bottom:1rem;padding:.75rem;background-color:#f8f9fa;border-radius:.5rem;border-left:4px solid #0F8BFD}.upload-status .status-message{display:flex;align-items:center;font-size:.9rem;color:#495057}.upload-status .status-message .pi{font-size:1rem}.upload-status .status-message .pi.pi-spinner{color:#0f8bfd}.upload-status .status-message .pi.pi-check-circle{color:#28a745}.upload-status .status-message .pi.pi-clock{color:#ffc107}.upload-status-summary{background-color:#f8f9fa;border-radius:.5rem;padding:1rem;margin-bottom:1rem;border:1px solid #e9ecef}.upload-status-summary .status-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:1rem;align-items:center}.upload-status-summary .status-item{display:flex;flex-direction:column;align-items:center;text-align:center}.upload-status-summary .status-item .status-label{font-size:.8rem;color:#6c757d;margin-bottom:.25rem;font-weight:500}.upload-status-summary .status-item .status-value{font-size:1.5rem;font-weight:600;color:#212529}.upload-status-summary .status-item .status-value.uploading{color:#0f8bfd}.upload-status-summary .status-item .status-value.uploaded{color:#28a745}.upload-status-summary .status-item .status-value.failed{color:#dc3545}.radio-group{display:flex;gap:.75rem}.radio-item{display:flex;align-items:center;gap:.5rem;cursor:pointer;transition:all .2s ease}.radio-item:has(.p-radiobutton-box.p-highlight) .radio-label{color:#0f8bfd;font-weight:600}.radio-label{font-size:.9rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease}::ng-deep .p-dropdown{width:100%}::ng-deep .p-dropdown .p-dropdown-label{font-size:.9rem;color:#495057}::ng-deep .p-dropdown .p-dropdown-trigger{color:#6c757d}::ng-deep .p-dropdown:not(.p-disabled):hover{border-color:#0f8bfd}::ng-deep .p-dropdown:not(.p-disabled).p-focus{border-color:#0f8bfd;box-shadow:0 0 0 2px #0f8bfd33}::ng-deep .p-radiobutton .p-radiobutton-box{border-color:#ced4da;border-radius:4px;width:18px;height:18px}::ng-deep .p-radiobutton .p-radiobutton-box:hover{border-color:#0f8bfd}::ng-deep .p-radiobutton .p-radiobutton-box.p-highlight{border-color:#0f8bfd;background-color:transparent}::ng-deep .p-radiobutton .p-radiobutton-icon{background-color:#0f8bfd;width:8px;height:8px;border-radius:2px}.applicant-section .grid{margin:0;padding:0}.applicant-section .applicant-item{display:flex;align-items:center;gap:.75rem;border-radius:.5rem;background-color:#fff;transition:all .2s ease;cursor:pointer;margin-bottom:.75rem}.applicant-section .applicant-item:has(.p-radiobutton-box.p-highlight) .applicant-label{color:#0f8bfd;font-weight:600}.applicant-section .applicant-label{font-size:.95rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-weight:500;margin:0;transition:color .2s ease}@media (max-width: 768px){.applicant-section .applicant-item{margin-bottom:.5rem;padding:.75rem;min-height:50px}.applicant-section .applicant-label{font-size:.9rem}.document-upload-container{padding:.75rem}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1rem}}.category-section .p-dropdown,.document-type-section .p-dropdown{width:100%!important;min-width:100%!important}.category-section .p-dropdown-panel,.document-type-section .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-dropdown{width:100%!important}:host ::ng-deep .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-progressbar.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}:host ::ng-deep .p-progressbar.success-progress-bar .p-progressbar-value{background-color:#28a745!important}:host ::ng-deep .p-progressbar.exceeded-progress-bar .p-progressbar-value{background-color:#ffc107!important}.applicant-list{display:none}.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}.text-green-500{color:#28a745!important}.text-blue-500{color:#0f8bfd!important}.text-red-500{color:#dc3545!important}.pi-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i9.FileUpload, selector: "p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "component", type: i10.ProgressBar, selector: "p-progressBar", inputs: ["value", "showValue", "styleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: i11.RadioButton, selector: "p-radioButton", inputs: ["value", "formControlName", "name", "disabled", "label", "variant", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "labelStyleClass", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i13.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
3267
3314
|
}
|
|
3268
3315
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DocumentUploadComponent, decorators: [{
|
|
3269
3316
|
type: Component,
|
|
3270
|
-
args: [{ selector: 'lib-document-upload', standalone: false, encapsulation: ViewEncapsulation.None, template: "<div class=\"document-upload-container\">\n <!-- Assignment Section -->\n <div class=\"assignment-section\">\n <h4>Assign to Applicant(s) or Application</h4>\n <div class=\"radio-group\">\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Applicant\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'applicant'\"\n ></p-radioButton>\n <label [for]=\"'applicant'\" class=\"radio-label\">Applicant(s)</label>\n </div>\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Application\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'application'\"\n ></p-radioButton>\n <label [for]=\"'application'\" class=\"radio-label\">Application</label>\n </div>\n </div>\n </div>\n\n <!-- Applicant Selection (only shown when Applicant is selected) -->\n <div class=\"applicant-section\" *ngIf=\"selectedAssignmentType === 'Applicant'\">\n <h4>Select Applicant(s)</h4>\n <div class=\"grid\">\n <div \n *ngFor=\"let applicant of filteredApplicantList\" \n class=\"applicant-item col-12 md:col-6\"\n >\n <p-radioButton \n name=\"selectedApplicant\"\n [value]=\"applicant._id\"\n [(ngModel)]=\"selectedApplicant\"\n [inputId]=\"'applicant-' + applicant._id\"\n (onClick)=\"onApplicantSelectionChange()\"\n ></p-radioButton>\n <label [for]=\"'applicant-' + applicant._id\" class=\"applicant-label\">\n {{ applicant.name }}\n </label>\n </div>\n </div>\n </div>\n\n <!-- Category Selection -->\n <div class=\"category-section\">\n <h4>Category</h4>\n <p-dropdown\n [options]=\"categoryOptions\"\n [(ngModel)]=\"selectedCategory\"\n placeholder=\"Select Category type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onCategoryChange()\"\n [disabled]=\"!categoryOptions.length\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- Document Type Selection -->\n <div class=\"document-type-section\">\n <h4>Document Type</h4>\n <p-dropdown\n [options]=\"documentTypeOptions\"\n [(ngModel)]=\"selectedDocumentType\"\n placeholder=\"Select Document type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onDocumentTypeChange()\"\n [disabled]=\"!documentTypeOptions.length || !selectedCategory\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- File Upload Section -->\n <div class=\"file-upload-section\">\n <h4>Upload Documents</h4>\n <div class=\"grid\">\n <div class=\"col-12 md:col-12\">\n <p-fileUpload \n #fileUploader \n [multiple]=\"true\" \n auto=\"true\" \n accept=\"image/png,application/pdf\" \n maxFileSize=\"26214400\"\n (onSelect)=\"onSelectedFiles($event)\"\n >\n <ng-template pTemplate=\"header\" let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\">\n <div class=\"docHeader p-2 flex flex-wrap justify-content-between align-items-center flex-1 gap-2\">\n <div class=\"flex gap-2\">\n <p-button \n (onClick)=\"choose($event, chooseCallback)\" \n icon=\"pi pi-images\" \n [rounded]=\"true\"\n [outlined]=\"true\" \n />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\" let-removeFileCallback=\"removeFileCallback\"\n let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"col-12 md:col-12 p-0\">\n <div class=\"col-12 md:col-12 p-0\" *ngIf=\"uploadedFiles.length > 0\">\n <div *ngFor=\"let uploadedFile of uploadedFiles; let i = index\"\n class=\"m-0 flex flex-column align-items-center gap-1 mt-3\">\n <div class=\"col-12 md:col-12 p-0 flex documentInfo\">\n <div class=\"documentImage\">\n <img src=\"../../../../assets/images/document.png\" [alt]=\"uploadedFile.file.name\" width=\"45\" height=\"50\"\n class=\"object-contain\" />\n </div>\n <div class=\"flex w-full flex-column mt-2 ml-2\">\n <div class=\"flex justify-content-between\">\n <div style=\"font-weight: bold;font-size: 14px\">\n {{ uploadedFile.fileName || uploadedFile.file.name }}\n </div>\n <i class=\"pi pi-times cursor-pointer\" (click)=\"handleDocumentRemove(uploadedFile.file,i)\"></i>\n </div>\n <div class=\"flex justify-content-between mt-1\">\n <div style=\"color: #676B89; font-size: 12px;\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\">\n <i [class]=\"{\n 'pi pi-verified': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'pi pi-spin pi-spinner': uploadedFile.isUploading,\n 'pi pi-exclamation-triangle': uploadedFile.hasError\n }\"></i>\n {{ uploadedFile.formattedSize }}\n </div>\n <div class=\"white-space-nowrap\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\" \n style=\"font-family: 14px;\"> \n <span *ngIf=\"uploadedFile.hasError\">Upload Failed</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress === 100\">Uploaded</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress < 100\">{{ uploadedFile.progress }}%</span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"col-12 md:col-12 p-0\">\n <p-progressBar \n [value]=\"uploadedFile.hasError ? 0 : uploadedFile.progress\" \n [showValue]=\"false\" \n styleClass=\"h-1/2rem md:ml-auto relative\"\n [ngClass]=\"{\n 'exceeded-progress-bar': uploadedFile.progress > 100,\n 'error-progress-bar': uploadedFile.hasError\n }\"\n >\n </p-progressBar>\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"empty\" let-chooseCallback=\"chooseCallback\">\n <div *ngIf=\"!uploadedFiles.length\" class=\"flex align-items-center justify-content-center flex-column\"\n (click)=\"triggerFileUpload()\">\n <i class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400\"></i>\n <p class=\"mt-4 mb-0\">Drag and drop files here to upload.</p>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n </p-fileUpload>\n </div>\n </div>\n </div>\n</div>", styles: [".flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.flex-col{flex-direction:column}.text-muted-color{color:#6c757d}.p-fileupload-buttonbar{padding:0}.p-fileupload-content{background-color:#0f8bfd1a}.p-fileupload .p-fileupload-content{padding:1rem}.docHeader .p-button-icon{padding:.5rem}.document-upload-container{padding:1rem;max-height:90vh}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1.5rem}.assignment-section h4,.applicant-section h4,.category-section h4,.document-type-section h4,.file-upload-section h4{margin:0 0 .75rem;font-size:1rem;font-weight:600;color:#212529}.upload-status{margin-bottom:1rem;padding:.75rem;background-color:#f8f9fa;border-radius:.5rem;border-left:4px solid #0F8BFD}.upload-status .status-message{display:flex;align-items:center;font-size:.9rem;color:#495057}.upload-status .status-message .pi{font-size:1rem}.upload-status .status-message .pi.pi-spinner{color:#0f8bfd}.upload-status .status-message .pi.pi-check-circle{color:#28a745}.upload-status .status-message .pi.pi-clock{color:#ffc107}.radio-group{display:flex;gap:.75rem}.radio-item{display:flex;align-items:center;gap:.5rem;cursor:pointer;transition:all .2s ease}.radio-item:has(.p-radiobutton-box.p-highlight) .radio-label{color:#0f8bfd;font-weight:600}.radio-label{font-size:.9rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease}::ng-deep .p-dropdown{width:100%}::ng-deep .p-dropdown .p-dropdown-label{font-size:.9rem;color:#495057}::ng-deep .p-dropdown .p-dropdown-trigger{color:#6c757d}::ng-deep .p-dropdown:not(.p-disabled):hover{border-color:#0f8bfd}::ng-deep .p-dropdown:not(.p-disabled).p-focus{border-color:#0f8bfd;box-shadow:0 0 0 2px #0f8bfd33}::ng-deep .p-radiobutton .p-radiobutton-box{border-color:#ced4da;border-radius:4px;width:18px;height:18px}::ng-deep .p-radiobutton .p-radiobutton-box:hover{border-color:#0f8bfd}::ng-deep .p-radiobutton .p-radiobutton-box.p-highlight{border-color:#0f8bfd;background-color:transparent}::ng-deep .p-radiobutton .p-radiobutton-icon{background-color:#0f8bfd;width:8px;height:8px;border-radius:2px}.applicant-section .grid{margin:0;padding:0}.applicant-section .applicant-item{display:flex;align-items:center;gap:.75rem;border-radius:.5rem;background-color:#fff;transition:all .2s ease;cursor:pointer;margin-bottom:.75rem}.applicant-section .applicant-item:has(.p-radiobutton-box.p-highlight) .applicant-label{color:#0f8bfd;font-weight:600}.applicant-section .applicant-label{font-size:.95rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-weight:500;margin:0;transition:color .2s ease}@media (max-width: 768px){.applicant-section .applicant-item{margin-bottom:.5rem;padding:.75rem;min-height:50px}.applicant-section .applicant-label{font-size:.9rem}.document-upload-container{padding:.75rem}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1rem}}.category-section .p-dropdown,.document-type-section .p-dropdown{width:100%!important;min-width:100%!important}.category-section .p-dropdown-panel,.document-type-section .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-dropdown{width:100%!important}:host ::ng-deep .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-progressbar.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}:host ::ng-deep .p-progressbar.success-progress-bar .p-progressbar-value{background-color:#28a745!important}:host ::ng-deep .p-progressbar.exceeded-progress-bar .p-progressbar-value{background-color:#ffc107!important}.applicant-list{display:none}.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}.text-green-500{color:#28a745!important}.text-blue-500{color:#0f8bfd!important}.text-red-500{color:#dc3545!important}.pi-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
3317
|
+
args: [{ selector: 'lib-document-upload', standalone: false, encapsulation: ViewEncapsulation.None, template: "<div class=\"document-upload-container\">\n <!-- Assignment Section -->\n <div class=\"assignment-section\">\n <h4>Assign to Applicant(s) or Application</h4>\n <div class=\"radio-group\">\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Applicant\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'applicant'\"\n ></p-radioButton>\n <label [for]=\"'applicant'\" class=\"radio-label\">Applicant(s)</label>\n </div>\n <div class=\"radio-item\">\n <p-radioButton \n name=\"assignmentType\" \n value=\"Application\" \n [(ngModel)]=\"selectedAssignmentType\"\n (onClick)=\"onAssignmentTypeChange()\"\n [inputId]=\"'application'\"\n ></p-radioButton>\n <label [for]=\"'application'\" class=\"radio-label\">Application</label>\n </div>\n </div>\n </div>\n\n <!-- Applicant Selection (only shown when Applicant is selected) -->\n <div class=\"applicant-section\" *ngIf=\"selectedAssignmentType === 'Applicant'\">\n <h4>Select Applicant(s)</h4>\n <div class=\"grid\">\n <div \n *ngFor=\"let applicant of filteredApplicantList\" \n class=\"applicant-item col-12 md:col-6\"\n >\n <p-radioButton \n name=\"selectedApplicant\"\n [value]=\"applicant._id\"\n [(ngModel)]=\"selectedApplicant\"\n [inputId]=\"'applicant-' + applicant._id\"\n (onClick)=\"onApplicantSelectionChange()\"\n ></p-radioButton>\n <label [for]=\"'applicant-' + applicant._id\" class=\"applicant-label\">\n {{ applicant.name }}\n </label>\n </div>\n </div>\n </div>\n\n <!-- Category Selection -->\n <div class=\"category-section\">\n <h4>Category</h4>\n <p-dropdown\n [options]=\"categoryOptions\"\n [(ngModel)]=\"selectedCategory\"\n placeholder=\"Select Category type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onCategoryChange()\"\n [disabled]=\"!categoryOptions.length\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- Document Type Selection -->\n <div class=\"document-type-section\">\n <h4>Document Type</h4>\n <p-dropdown\n [options]=\"documentTypeOptions\"\n [(ngModel)]=\"selectedDocumentType\"\n placeholder=\"Select Document type\"\n optionLabel=\"label\"\n optionValue=\"_id\"\n (onChange)=\"onDocumentTypeChange()\"\n [disabled]=\"!documentTypeOptions.length || !selectedCategory\"\n class=\"w-full\"\n ></p-dropdown>\n </div>\n\n <!-- File Upload Section -->\n <div class=\"file-upload-section\">\n <h4>Upload Documents</h4>\n \n <!-- Upload Status Summary -->\n <div class=\"upload-status-summary\" *ngIf=\"getTotalCount() > 0\">\n <div class=\"status-grid\">\n <div class=\"status-item\">\n <span class=\"status-label\">Total Files:</span>\n <span class=\"status-value\">{{ getTotalCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getUploadingCount() > 0\">\n <span class=\"status-label\">Uploading:</span>\n <span class=\"status-value uploading\">{{ getUploadingCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getUploadedCount() > 0\">\n <span class=\"status-label\">Uploaded:</span>\n <span class=\"status-value uploaded\">{{ getUploadedCount() }}</span>\n </div>\n <div class=\"status-item\" *ngIf=\"getFailedCount() > 0\">\n <span class=\"status-label\">Failed:</span>\n <span class=\"status-value failed\">{{ getFailedCount() }}</span>\n </div>\n </div>\n </div>\n \n <div class=\"grid\">\n <div class=\"col-12 md:col-12\">\n <p-fileUpload \n #fileUploader \n [multiple]=\"true\" \n auto=\"true\" \n accept=\"image/png,application/pdf\" \n maxFileSize=\"26214400\"\n (onSelect)=\"onSelectedFiles($event)\"\n >\n <ng-template pTemplate=\"header\" let-chooseCallback=\"chooseCallback\" let-clearCallback=\"clearCallback\">\n <div class=\"docHeader p-2 flex flex-wrap justify-content-between align-items-center flex-1 gap-2\">\n <div class=\"flex gap-2\">\n <p-button \n (onClick)=\"choose($event, chooseCallback)\" \n icon=\"pi pi-images\" \n [rounded]=\"true\"\n [outlined]=\"true\" \n />\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\" let-removeFileCallback=\"removeFileCallback\"\n let-removeUploadedFileCallback=\"removeUploadedFileCallback\">\n <div class=\"col-12 md:col-12 p-0\">\n <div class=\"col-12 md:col-12 p-0\" *ngIf=\"uploadedFiles.length > 0\">\n <div *ngFor=\"let uploadedFile of uploadedFiles; let i = index\"\n class=\"m-0 flex flex-column align-items-center gap-1 mt-3\">\n <div class=\"col-12 md:col-12 p-0 flex documentInfo\">\n <div class=\"documentImage\">\n <img src=\"../../../../assets/images/document.png\" [alt]=\"uploadedFile.file.name\" width=\"45\" height=\"50\"\n class=\"object-contain\" />\n </div>\n <div class=\"flex w-full flex-column mt-2 ml-2\">\n <div class=\"flex justify-content-between\">\n <div style=\"font-weight: bold;font-size: 14px\">\n {{ uploadedFile.fileName || uploadedFile.file.name }}\n </div>\n <i class=\"pi pi-times cursor-pointer\" (click)=\"handleDocumentRemove(uploadedFile.file,i)\"></i>\n </div>\n <div class=\"flex justify-content-between mt-1\">\n <div style=\"color: #676B89; font-size: 12px;\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\">\n <i [class]=\"{\n 'pi pi-verified': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'pi pi-spin pi-spinner': uploadedFile.isUploading,\n 'pi pi-exclamation-triangle': uploadedFile.hasError\n }\"></i>\n {{ uploadedFile.formattedSize }}\n </div>\n <div class=\"white-space-nowrap\" \n [ngClass]=\"{\n 'text-green-500': uploadedFile.progress === 100 && !uploadedFile.hasError,\n 'text-blue-500': uploadedFile.isUploading,\n 'text-red-500': uploadedFile.hasError\n }\" \n style=\"font-family: 14px;\"> \n <span *ngIf=\"uploadedFile.hasError\">Upload Failed</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress === 100\">Uploaded</span>\n <span *ngIf=\"!uploadedFile.hasError && uploadedFile.progress < 100\">{{ uploadedFile.progress }}%</span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"col-12 md:col-12 p-0\">\n <p-progressBar \n [value]=\"uploadedFile.hasError ? 0 : uploadedFile.progress\" \n [showValue]=\"false\" \n styleClass=\"h-1/2rem md:ml-auto relative\"\n [ngClass]=\"{\n 'exceeded-progress-bar': uploadedFile.progress > 100,\n 'error-progress-bar': uploadedFile.hasError\n }\"\n >\n </p-progressBar>\n </div>\n </div>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"empty\" let-chooseCallback=\"chooseCallback\">\n <div *ngIf=\"!uploadedFiles.length\" class=\"flex align-items-center justify-content-center flex-column\"\n (click)=\"triggerFileUpload()\">\n <i class=\"pi pi-cloud-upload border-2 border-circle p-5 text-8xl text-400 border-400\"></i>\n <p class=\"mt-4 mb-0\">Drag and drop files here to upload.</p>\n </div>\n </ng-template>\n <ng-template pTemplate=\"file\"> </ng-template>\n </p-fileUpload>\n </div>\n </div>\n </div>\n</div>", styles: [".flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.flex-col{flex-direction:column}.text-muted-color{color:#6c757d}.p-fileupload-buttonbar{padding:0}.p-fileupload-content{background-color:#0f8bfd1a}.p-fileupload .p-fileupload-content{padding:1rem}.docHeader .p-button-icon{padding:.5rem}.document-upload-container{padding:1rem;max-height:90vh}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1.5rem}.assignment-section h4,.applicant-section h4,.category-section h4,.document-type-section h4,.file-upload-section h4{margin:0 0 .75rem;font-size:1rem;font-weight:600;color:#212529}.upload-status{margin-bottom:1rem;padding:.75rem;background-color:#f8f9fa;border-radius:.5rem;border-left:4px solid #0F8BFD}.upload-status .status-message{display:flex;align-items:center;font-size:.9rem;color:#495057}.upload-status .status-message .pi{font-size:1rem}.upload-status .status-message .pi.pi-spinner{color:#0f8bfd}.upload-status .status-message .pi.pi-check-circle{color:#28a745}.upload-status .status-message .pi.pi-clock{color:#ffc107}.upload-status-summary{background-color:#f8f9fa;border-radius:.5rem;padding:1rem;margin-bottom:1rem;border:1px solid #e9ecef}.upload-status-summary .status-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:1rem;align-items:center}.upload-status-summary .status-item{display:flex;flex-direction:column;align-items:center;text-align:center}.upload-status-summary .status-item .status-label{font-size:.8rem;color:#6c757d;margin-bottom:.25rem;font-weight:500}.upload-status-summary .status-item .status-value{font-size:1.5rem;font-weight:600;color:#212529}.upload-status-summary .status-item .status-value.uploading{color:#0f8bfd}.upload-status-summary .status-item .status-value.uploaded{color:#28a745}.upload-status-summary .status-item .status-value.failed{color:#dc3545}.radio-group{display:flex;gap:.75rem}.radio-item{display:flex;align-items:center;gap:.5rem;cursor:pointer;transition:all .2s ease}.radio-item:has(.p-radiobutton-box.p-highlight) .radio-label{color:#0f8bfd;font-weight:600}.radio-label{font-size:.9rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease}::ng-deep .p-dropdown{width:100%}::ng-deep .p-dropdown .p-dropdown-label{font-size:.9rem;color:#495057}::ng-deep .p-dropdown .p-dropdown-trigger{color:#6c757d}::ng-deep .p-dropdown:not(.p-disabled):hover{border-color:#0f8bfd}::ng-deep .p-dropdown:not(.p-disabled).p-focus{border-color:#0f8bfd;box-shadow:0 0 0 2px #0f8bfd33}::ng-deep .p-radiobutton .p-radiobutton-box{border-color:#ced4da;border-radius:4px;width:18px;height:18px}::ng-deep .p-radiobutton .p-radiobutton-box:hover{border-color:#0f8bfd}::ng-deep .p-radiobutton .p-radiobutton-box.p-highlight{border-color:#0f8bfd;background-color:transparent}::ng-deep .p-radiobutton .p-radiobutton-icon{background-color:#0f8bfd;width:8px;height:8px;border-radius:2px}.applicant-section .grid{margin:0;padding:0}.applicant-section .applicant-item{display:flex;align-items:center;gap:.75rem;border-radius:.5rem;background-color:#fff;transition:all .2s ease;cursor:pointer;margin-bottom:.75rem}.applicant-section .applicant-item:has(.p-radiobutton-box.p-highlight) .applicant-label{color:#0f8bfd;font-weight:600}.applicant-section .applicant-label{font-size:.95rem;color:#495057;cursor:pointer;-webkit-user-select:none;user-select:none;flex:1;font-weight:500;margin:0;transition:color .2s ease}@media (max-width: 768px){.applicant-section .applicant-item{margin-bottom:.5rem;padding:.75rem;min-height:50px}.applicant-section .applicant-label{font-size:.9rem}.document-upload-container{padding:.75rem}.assignment-section,.applicant-section,.category-section,.document-type-section,.file-upload-section{margin-bottom:1rem}}.category-section .p-dropdown,.document-type-section .p-dropdown{width:100%!important;min-width:100%!important}.category-section .p-dropdown-panel,.document-type-section .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-dropdown{width:100%!important}:host ::ng-deep .p-dropdown-panel{width:100%!important}:host ::ng-deep .p-progressbar.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}:host ::ng-deep .p-progressbar.success-progress-bar .p-progressbar-value{background-color:#28a745!important}:host ::ng-deep .p-progressbar.exceeded-progress-bar .p-progressbar-value{background-color:#ffc107!important}.applicant-list{display:none}.error-progress-bar .p-progressbar-value{background-color:#dc3545!important}.text-green-500{color:#28a745!important}.text-blue-500{color:#0f8bfd!important}.text-red-500{color:#dc3545!important}.pi-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
3271
3318
|
}], ctorParameters: () => [{ type: DocumentUploadService }, { type: i3.PrimeNGConfig }, { type: FileFormatService }, { type: i3.MessageService }, { type: i0.ChangeDetectorRef }, { type: DocumentUploadBusinessService }, { type: DocumentUploadFormService }, { type: DocumentUploadDataService }], propDecorators: { contextId: [{
|
|
3272
3319
|
type: Input
|
|
3273
3320
|
}], fileUploader: [{
|