cat-documents-ng 0.1.28 → 0.1.30

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.
Files changed (92) hide show
  1. package/ng-package.json +11 -0
  2. package/package.json +20 -25
  3. package/{Shared/constant/ERROR.d.ts → src/Shared/constant/ERROR.ts} +38 -36
  4. package/src/Shared/constant/PERMISSIONS.ts +16 -0
  5. package/src/Shared/constant/SHARED.ts +312 -0
  6. package/{Shared/constant/URLS.d.ts → src/Shared/constant/URLS.ts} +65 -60
  7. package/src/Shared/services/app-config.service.spec.ts +19 -0
  8. package/src/Shared/services/app-config.service.ts +73 -0
  9. package/{Shared/services/global-error.handler.d.ts → src/Shared/services/global-error.handler.ts} +29 -27
  10. package/src/Shared/services/session.service.spec.ts +16 -0
  11. package/src/Shared/services/session.service.ts +76 -0
  12. package/src/assets/config/api.config.json +20 -0
  13. package/src/lib/document/components/document-container/document-container.component.html +14 -0
  14. package/src/lib/document/components/document-container/document-container.component.scss +8 -0
  15. package/src/lib/document/components/document-container/document-container.component.spec.ts +110 -0
  16. package/src/lib/document/components/document-container/document-container.component.ts +173 -0
  17. package/src/lib/document/components/document-list/document-list.component.html +81 -0
  18. package/src/lib/document/components/document-list/document-list.component.scss +82 -0
  19. package/src/lib/document/components/document-list/document-list.component.spec.ts +96 -0
  20. package/src/lib/document/components/document-list/document-list.component.ts +244 -0
  21. package/src/lib/document/components/document-list-item/document-list-item.component.html +36 -0
  22. package/src/lib/document/components/document-list-item/document-list-item.component.scss +34 -0
  23. package/src/lib/document/components/document-list-item/document-list-item.component.spec.ts +75 -0
  24. package/src/lib/document/components/document-list-item/document-list-item.component.ts +40 -0
  25. package/src/lib/document/components/document-upload/document-upload.component.html +56 -0
  26. package/src/lib/document/components/document-upload/document-upload.component.scss +32 -0
  27. package/src/lib/document/components/document-upload/document-upload.component.spec.ts +95 -0
  28. package/src/lib/document/components/document-upload/document-upload.component.ts +162 -0
  29. package/src/lib/document/components/document-viewer/document-viewer.component.html +98 -0
  30. package/src/lib/document/components/document-viewer/document-viewer.component.scss +54 -0
  31. package/src/lib/document/components/document-viewer/document-viewer.component.spec.ts +79 -0
  32. package/src/lib/document/components/document-viewer/document-viewer.component.ts +106 -0
  33. package/src/lib/document/components/folder-block/folder-block.component.html +46 -0
  34. package/src/lib/document/components/folder-block/folder-block.component.scss +9 -0
  35. package/src/lib/document/components/folder-block/folder-block.component.spec.ts +70 -0
  36. package/{lib/document/components/folder-block/folder-block.component.d.ts → src/lib/document/components/folder-block/folder-block.component.ts} +53 -37
  37. package/src/lib/document/components/folder-container/folder-container.component.html +2 -0
  38. package/src/lib/document/components/folder-container/folder-container.component.scss +0 -0
  39. package/src/lib/document/components/folder-container/folder-container.component.spec.ts +27 -0
  40. package/src/lib/document/components/folder-container/folder-container.component.ts +37 -0
  41. package/src/lib/document/components/linked-document/linked-document.component.html +23 -0
  42. package/src/lib/document/components/linked-document/linked-document.component.scss +10 -0
  43. package/src/lib/document/components/linked-document/linked-document.component.spec.ts +61 -0
  44. package/src/lib/document/components/linked-document/linked-document.component.ts +49 -0
  45. package/src/lib/document/directives/document.directive.ts +32 -0
  46. package/src/lib/document/directives/permission.directive.spec.ts +0 -0
  47. package/src/lib/document/directives/permission.directive.ts +66 -0
  48. package/src/lib/document/document.module.ts +241 -0
  49. package/{lib/document/models/document-alert.model.d.ts → src/lib/document/models/document-alert.model.ts} +45 -38
  50. package/src/lib/document/models/document-type.model.ts +44 -0
  51. package/src/lib/document/models/document.model.ts +53 -0
  52. package/{lib/document/models/folder.model.d.ts → src/lib/document/models/folder.model.ts} +35 -29
  53. package/src/lib/document/services/document-http.service.spec.ts +119 -0
  54. package/src/lib/document/services/document-http.service.ts +125 -0
  55. package/src/lib/document/services/document-upload.service.spec.ts +99 -0
  56. package/src/lib/document/services/document-upload.service.ts +127 -0
  57. package/src/lib/document/services/document.service.ts +29 -0
  58. package/src/lib/document/services/file-format.service.spec.ts +16 -0
  59. package/src/lib/document/services/file-format.service.ts +41 -0
  60. package/src/lib/document/state/document.query.ts +52 -0
  61. package/{lib/document/state/document.service.d.ts → src/lib/document/state/document.service.ts} +95 -64
  62. package/{lib/document/state/document.state.d.ts → src/lib/document/state/document.state.ts} +52 -36
  63. package/src/lib/document/state/document.store.ts +51 -0
  64. package/{public-api.d.ts → src/public-api.ts} +10 -6
  65. package/tsconfig.lib.json +15 -0
  66. package/tsconfig.lib.prod.json +11 -0
  67. package/tsconfig.spec.json +15 -0
  68. package/Shared/constant/PERMISSIONS.d.ts +0 -15
  69. package/Shared/constant/SHARED.d.ts +0 -209
  70. package/Shared/services/app-config.service.d.ts +0 -51
  71. package/Shared/services/session.service.d.ts +0 -46
  72. package/fesm2022/cat-documents-ng.mjs +0 -2538
  73. package/fesm2022/cat-documents-ng.mjs.map +0 -1
  74. package/index.d.ts +0 -5
  75. package/lib/document/components/document-container/document-container.component.d.ts +0 -85
  76. package/lib/document/components/document-list/document-list.component.d.ts +0 -160
  77. package/lib/document/components/document-list-item/document-list-item.component.d.ts +0 -28
  78. package/lib/document/components/document-upload/document-upload.component.d.ts +0 -120
  79. package/lib/document/components/document-viewer/document-viewer.component.d.ts +0 -73
  80. package/lib/document/components/folder-container/folder-container.component.d.ts +0 -29
  81. package/lib/document/components/linked-document/linked-document.component.d.ts +0 -38
  82. package/lib/document/directives/document.directive.d.ts +0 -20
  83. package/lib/document/directives/permission.directive.d.ts +0 -38
  84. package/lib/document/document.module.d.ts +0 -40
  85. package/lib/document/models/document-type.model.d.ts +0 -37
  86. package/lib/document/models/document.model.d.ts +0 -44
  87. package/lib/document/services/document-http.service.d.ts +0 -69
  88. package/lib/document/services/document-upload.service.d.ts +0 -67
  89. package/lib/document/services/document.service.d.ts +0 -20
  90. package/lib/document/services/file-format.service.d.ts +0 -23
  91. package/lib/document/state/document.query.d.ts +0 -42
  92. package/lib/document/state/document.store.d.ts +0 -29
@@ -0,0 +1,95 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { DocumentUploadComponent } from './document-upload.component';
3
+ import { FileUploadModule } from 'primeng/fileupload';
4
+ import { HttpClientTestingModule } from '@angular/common/http/testing';
5
+ import { MessageService, PrimeNGConfig } from 'primeng/api';
6
+ import { ChangeDetectorRef } from '@angular/core';
7
+ import { FileFormatService } from '../../services/file-format.service';
8
+ import { DocumentService } from '../../state/document.service';
9
+ import { DocumentUploadService } from '../../services/document-upload.service';
10
+
11
+ describe('DocumentUploadComponent', () => {
12
+ let component: DocumentUploadComponent;
13
+ let fixture: ComponentFixture<DocumentUploadComponent>;
14
+ let mockFileFormatService: jasmine.SpyObj<FileFormatService>;
15
+ let mockDocumentService: jasmine.SpyObj<DocumentService>;
16
+ let mockDocumentUploadService: jasmine.SpyObj<DocumentUploadService>;
17
+
18
+ beforeEach(async () => {
19
+ mockFileFormatService = jasmine.createSpyObj('FileFormatService', ['formatFileSize']);
20
+ mockDocumentService = jasmine.createSpyObj('DocumentService', ['uploadDocument']);
21
+ mockDocumentUploadService = jasmine.createSpyObj('DocumentUploadService', ['getUploadFileData']);
22
+
23
+ await TestBed.configureTestingModule({
24
+ declarations: [DocumentUploadComponent],
25
+ imports: [FileUploadModule, HttpClientTestingModule],
26
+ providers: [
27
+ MessageService,
28
+ PrimeNGConfig,
29
+ ChangeDetectorRef,
30
+ { provide: FileFormatService, useValue: mockFileFormatService },
31
+ { provide: DocumentService, useValue: mockDocumentService },
32
+ { provide: DocumentUploadService, useValue: mockDocumentUploadService },
33
+ ],
34
+ }).compileComponents();
35
+
36
+ fixture = TestBed.createComponent(DocumentUploadComponent);
37
+ component = fixture.componentInstance;
38
+ fixture.detectChanges();
39
+ });
40
+
41
+ it('should create', () => {
42
+ expect(component).toBeTruthy();
43
+ });
44
+
45
+ it('should trigger file upload dialog when triggerFileUpload is called', () => {
46
+ spyOn(component.fileUploader, 'choose');
47
+ component.triggerFileUpload();
48
+ expect(component.fileUploader.choose).toHaveBeenCalled();
49
+ });
50
+
51
+ it('should handle file selection and upload', () => {
52
+ const mockFile = new File(['content'], 'test.pdf', { type: 'application/pdf' });
53
+ const event = { currentFiles: [mockFile] };
54
+ mockFileFormatService.formatFileSize.and.returnValue('10 KB');
55
+ component.onSelectedFiles(event);
56
+ expect(mockDocumentUploadService.getUploadFileData).toHaveBeenCalledWith(mockFile, component.contextId);
57
+ expect(component.uploadedFiles.length).toBe(1);
58
+ expect(component.uploadedFiles[0].file).toBe(mockFile);
59
+ expect(component.uploadedFiles[0].formattedSize).toBe('10 KB');
60
+ expect(component.uploadedFiles[0].progress).toBe(100);
61
+ });
62
+
63
+ it('should remove a file from the uploaded files list', () => {
64
+ const mockFile = new File(['content'], 'test.pdf', { type: 'application/pdf' });
65
+ component.uploadedFiles = [
66
+ { file: mockFile, formattedSize: '10 KB', progress: 100 },
67
+ ];
68
+ const fileProgressSpy = spyOn(component.fileProgress, 'delete');
69
+ component.handleDocumentRemove(mockFile, 0);
70
+ expect(component.uploadedFiles.length).toBe(0);
71
+ expect(fileProgressSpy).toHaveBeenCalledWith(mockFile);
72
+ });
73
+
74
+ it('should calculate and return file progress', () => {
75
+ const mockFile = new File(['content'], 'test.pdf', { type: 'application/pdf' });
76
+ component.fileProgress.set(mockFile, 75);
77
+ const progress = component.getProgress(mockFile);
78
+ expect(progress).toBe(75);
79
+ });
80
+
81
+ it('should format file size correctly', () => {
82
+ mockFileFormatService.formatFileSize.and.returnValue('10 KB');
83
+ component.formatSize(10240);
84
+ expect(component.fileSize).toBe('10 KB');
85
+ expect(mockFileFormatService.formatFileSize).toHaveBeenCalledWith(10240, jasmine.any(PrimeNGConfig));
86
+ });
87
+
88
+ it('should clear files after selection', () => {
89
+ spyOn(component.fileUploader, 'clear');
90
+ const mockFile = new File(['content'], 'test.pdf', { type: 'application/pdf' });
91
+ const event = { currentFiles: [mockFile] };
92
+ component.onSelectedFiles(event);
93
+ expect(component.fileUploader.clear).toHaveBeenCalled();
94
+ });
95
+ });
@@ -0,0 +1,162 @@
1
+ import { ChangeDetectorRef, Component, Input, ViewChild, ViewEncapsulation } from '@angular/core';
2
+ import { FileUpload } from 'primeng/fileupload';
3
+ import { MessageService } from 'primeng/api';
4
+ import { PrimeNGConfig } from 'primeng/api';
5
+ import { SHARED } from '../../../../Shared/constant/SHARED';
6
+ import { FileFormatService } from '../../services/file-format.service';
7
+ import { DocumentService } from '../../state/document.service';
8
+ import { DocumentUploadService } from '../../services/document-upload.service';
9
+
10
+ /**
11
+ * A component for handling document uploads, including file selection, removal, and progress tracking.
12
+ * @class DocumentUploadComponent
13
+ */
14
+ @Component({
15
+ selector: 'lib-document-upload',
16
+ templateUrl: './document-upload.component.html',
17
+ styleUrls: ['./document-upload.component.scss'],
18
+ standalone: false,
19
+ encapsulation: ViewEncapsulation.None
20
+ })
21
+ export class DocumentUploadComponent {
22
+
23
+
24
+ /**
25
+ * Represents the file size.
26
+ * @type {number}
27
+ */
28
+ fileSize: string = SHARED.EMPTY;
29
+ /**
30
+ * Represent contextId
31
+ * @type {string}
32
+ */
33
+ @Input() contextId: string = SHARED.EMPTY
34
+
35
+ /**
36
+ * To make file explorer visible.
37
+ * @type {!FileUpload}
38
+ */
39
+ @ViewChild('fileUploader') fileUploader!: FileUpload;
40
+
41
+ fileProgress: Map<File, number> = new Map();
42
+
43
+ /**
44
+ * List of files selected for upload.
45
+ * @type {File[]}
46
+ */
47
+ uploadedFiles: { file: File; formattedSize: string; progress: number }[] = [];
48
+
49
+
50
+ /**
51
+ * Percentage of the total size calculated for displaying upload progress.
52
+ * @type {number}
53
+ */
54
+ totalSizePercent: number = SHARED.INITIAL_COUNT;
55
+
56
+ /**
57
+ * The current upload progress percentage (SHARED.INITIAL_VALUE-100).
58
+ * @type {number}
59
+ */
60
+ uploadProgress: number = SHARED.INITIAL_COUNT;
61
+
62
+
63
+ /**
64
+ * Creates an instance of DocumentUploadComponent.
65
+ * @class
66
+ * @param {DocumentUploadService} documentUpload - Service for handling document upload.
67
+ * @param {DocumentService} uploadService - Service for handling document upload.
68
+ * @param {PrimeNGConfig} config - PrimeNG configuration.
69
+ * @param {FileFormatService} fileFormatService - Service for formatting file sizes.
70
+ * @param {MessageService} messageService - Service for displaying messages.
71
+ * @param {ChangeDetectorRef} cdr - Service for detecting changes.
72
+ */
73
+ constructor(public documentUpload : DocumentUploadService,public uploadService: DocumentService, private config: PrimeNGConfig, public fileFormatService: FileFormatService, public messageService: MessageService, public cdr: ChangeDetectorRef) { }
74
+
75
+ /**
76
+ * Open the file explorer.
77
+ * @param {*} event - The triggering event.
78
+ * @param {() => void} callback - A callback function to execute.
79
+ * @returns {void} - No return value.
80
+ */
81
+ choose(event: any, callback: () => void) {
82
+ callback();
83
+ }
84
+
85
+ /**
86
+ * Prepares the files for upload by creating a FormData object.
87
+ * This method appends each file to the FormData for submission.
88
+ * @param {File} file - The file to upload.
89
+ * @returns {void}
90
+ */
91
+ handleTemplatedUpload(file: File) {
92
+ this.documentUpload.getUploadFileData(file, this.contextId)
93
+ const formattedSize = this.fileFormatService.formatFileSize(file.size, this.config);
94
+ const progress = 100;
95
+ this.uploadedFiles.push({ file, formattedSize, progress });
96
+ this.fileProgress.set(file, progress);
97
+ this.totalSizePercent = 100;
98
+ }
99
+
100
+ /**
101
+ * Handle the creation of formdata.
102
+ * @param {File} file - The file to append in formdata.
103
+ * @returns {*} - The formdata object.
104
+ */
105
+ handleCreateFormData(file: File) {
106
+ const formData = new FormData();
107
+ formData.append(SHARED.FILE, file, file.name);
108
+ formData.append(SHARED.CONTEXT_ID, this.contextId)
109
+ return formData;
110
+ }
111
+ /**
112
+ * Handles the event when new files are selected.
113
+ * @param { { currentFiles: File[] } } event - The event containing the newly selected files.
114
+ * @returns {void} - No return value.
115
+ */
116
+ onSelectedFiles(event: { currentFiles: File[] }): void {
117
+ event.currentFiles.forEach((file: File) => {
118
+ this.handleTemplatedUpload(file);
119
+ });
120
+ this.fileUploader.clear();
121
+ }
122
+
123
+ /**
124
+ * Formats the given file size in bytes into a readable format (e.g., KB, MB).
125
+ * @param {number} bytes - The size of the file in bytes.
126
+ * @returns {string} The formatted file size (e.g., '1.2 KB', '2.3 MB').
127
+ */
128
+ formatSize(bytes: number) {
129
+ this.fileSize = this.fileFormatService.formatFileSize(bytes, this.config)
130
+ }
131
+
132
+ /**
133
+ * Handles the removal of a file from the uploaded files list.
134
+ * @param {File} file - The file to be removed.
135
+ * @param {number} index - The index of the file in the uploaded files list.
136
+ */
137
+ handleDocumentRemove(file: File, index: number): void {
138
+ this.uploadedFiles.splice(index, 1);
139
+ this.fileProgress.delete(file);
140
+ this.cdr.detectChanges();
141
+ }
142
+
143
+ /**
144
+ * Major progress for the progress bar.
145
+ * @param {File} file - File to check progress for.
146
+ * @returns {number} - The progress percentage for the file.
147
+ */
148
+ getProgress(file: File): number {
149
+ return this.fileProgress.get(file) || SHARED.INITIAL_COUNT;
150
+ }
151
+
152
+ /**
153
+ * Triggers the file upload dialog.
154
+ * Opens the file explorer for selecting files.
155
+ * @returns {void}
156
+ */
157
+ triggerFileUpload() {
158
+ this.fileUploader.choose();
159
+ }
160
+
161
+ }
162
+
@@ -0,0 +1,98 @@
1
+ <div class="grid">
2
+ <div class="col-12">
3
+ <div class="p-fluid p-formgrid grid m-0">
4
+ <div class="col-12 md:col-12 md:flex justify-content-evenly">
5
+ @if(selectedDocument){
6
+ <div id="outerContainer col-12 md:col-7">
7
+ <div
8
+ *ngIf="isImage(selectedDocument?.contentType)"
9
+ class="img-container"
10
+ >
11
+ <img
12
+ [src]="selectedDocument?.documentUrl || ''"
13
+ class="uploadedImages"
14
+ alt="Document Image"
15
+ />
16
+ </div>
17
+ @if(selectedDocument?.contentType && selectedDocument?.contentType === "application/pdf"){
18
+ <div class="pdf-container">
19
+ <pdf-viewer
20
+ [src]="selectedDocument?.documentUrl || ''"
21
+ [rotation]="0"
22
+ [original-size]="false"
23
+ [show-all]="true"
24
+ [fit-to-page]="false"
25
+ [zoom]="1"
26
+ [zoom-scale]="'page-width'"
27
+ [stick-to-page]="false"
28
+ [render-text]="true"
29
+ [external-link-target]="'blank'"
30
+ [autoresize]="true"
31
+ [show-borders]="false"
32
+ style="width: 50vw; height: 75vh"
33
+ ></pdf-viewer>
34
+ </div>
35
+ }@else{
36
+ <div class="incorrect-docType">
37
+ ContentType is incorrect.
38
+ </div>
39
+ }
40
+ </div>
41
+ }
42
+
43
+ <div class="left-part col-12 md:col-3 pt-0">
44
+ <div class="alerts mb-4 pb-1">
45
+ <button
46
+ type="button"
47
+ *ngIf="
48
+ (alertData?.status !== 'Pending' && !!alertData?.status) ||
49
+ alertData?.isAlert === false
50
+ "
51
+ class="bg-green-500 border-none border-round-md flex align-items-center mb-3 p-2 px-3"
52
+ >
53
+ <i
54
+ class="pi pi-verified mr-2 cursor-pointer"
55
+ [ngStyle]="{
56
+ color:
57
+ alertData?.status === 'Pending' &&
58
+ alertData?.isAlert !== false
59
+ ? '#FFFFFF'
60
+ : '#8A8EA6'
61
+ }"
62
+ style="font-size: 20px"
63
+ ></i>
64
+ <span class="font-semibold text-white">Verified</span>
65
+ </button>
66
+ <div
67
+ class="card mb-0"
68
+ [ngClass]="
69
+ (alertData?.status === 'Pending' || !alertData?.status) &&
70
+ alertData?.isAlert !== false
71
+ ? 'alert-card'
72
+ : 'success-alert'
73
+ "
74
+ >
75
+ <div class="flex align-items-center mb-2 pb-1" *ngIf="alertData?.status !== 'Verified'">
76
+ <h4 class="mr-3 mt-0 mb-0 text-color font-bold" style="font-size: 21px; font-weight: bold; border-color: rgba(68, 72, 109, 0.2) ;" >Alerts</h4>
77
+ <i
78
+ class="pi pi-exclamation-triangle"
79
+ style="font-size: 20px"
80
+ [ngStyle]="{
81
+ color:
82
+ (alertData?.status === 'Pending' || !alertData?.status) &&
83
+ alertData?.isAlert !== false
84
+ ? '#FB392D'
85
+ : '#8A8EA6'
86
+ }"
87
+ ></i>
88
+ </div>
89
+ <p class="text-color mb-0">{{ alertData?.alertMessage }}</p>
90
+ </div>
91
+ </div>
92
+ <ng-content></ng-content>
93
+ <app-linked-document (selectedDocumentChange)="handleSelectedDocument($event)" [selectedDocument]="selectedDocument" [documentList]="documentList"></app-linked-document>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
@@ -0,0 +1,54 @@
1
+ .alert-card {
2
+ background-color: #fb392d1a;
3
+ }
4
+
5
+ .success-alert {
6
+ border-radius: 10px;
7
+ border: 1px solid rgba(251, 57, 45, 0.1);
8
+ background: linear-gradient(0deg, #dedede 0%, #dedede 100%), #fff;
9
+ }
10
+
11
+ .p-timeline-event-opposite {
12
+ display: none;
13
+ }
14
+ .decription {
15
+ color: #676b89;
16
+ }
17
+ .textAreaControl textarea {
18
+ width: 100%;
19
+ resize: vertical;
20
+ max-width: 100%;
21
+ }
22
+
23
+ .document-btn-wrapper {
24
+ .p-button-outlined {
25
+ color: #f57c00;
26
+ }
27
+ }
28
+
29
+ .document-viewer{
30
+ .p-dialog{
31
+ width: 100%;
32
+ height: 100%;
33
+ max-height: 100% !important;
34
+ box-shadow: none !important;
35
+ }
36
+ .p-dialog-header-close-icon{
37
+ height: 20px;
38
+ width: 20px;
39
+ }
40
+ .p-dialog-header{
41
+ background-color:#FFF;
42
+ border-radius: 0;
43
+ }
44
+ .p-dialog-content{
45
+ background-color:#FFF;
46
+ border-radius: 0;
47
+ }
48
+ }
49
+
50
+ .uploadedImages{
51
+ width: 95%;
52
+ height: 100%;
53
+ object-fit: contain;
54
+ }
@@ -0,0 +1,79 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { DocumentViewerComponent } from './document-viewer.component';
3
+ import { TimelineModule } from 'primeng/timeline';
4
+ import { FormsModule } from '@angular/forms';
5
+ import { CheckboxModule } from 'primeng/checkbox';
6
+ import { HttpClientModule } from '@angular/common/http';
7
+ import { DocumentService } from '../../services/document.service';
8
+ import { DocumentHttpService } from '../../services/document-http.service';
9
+ import { of } from 'rxjs';
10
+ import { DocumentModel } from '../../models/document.model';
11
+ import { LinkedDocumentComponent } from '../linked-document/linked-document.component';
12
+
13
+ describe('DocumentViewerComponent', () => {
14
+ let component: DocumentViewerComponent;
15
+ let fixture: ComponentFixture<DocumentViewerComponent>;
16
+ let documentService: jasmine.SpyObj<DocumentService>;
17
+
18
+ beforeEach(async () => {
19
+ const documentServiceSpy = jasmine.createSpyObj('DocumentService', ['set']);
20
+
21
+ await TestBed.configureTestingModule({
22
+ declarations: [DocumentViewerComponent, LinkedDocumentComponent],
23
+ imports: [TimelineModule, FormsModule, CheckboxModule, HttpClientModule],
24
+ providers: [
25
+ { provide: DocumentService, useValue: documentServiceSpy },
26
+ DocumentHttpService,
27
+ ],
28
+ }).compileComponents();
29
+
30
+ fixture = TestBed.createComponent(DocumentViewerComponent);
31
+ component = fixture.componentInstance;
32
+ documentService = TestBed.inject(DocumentService) as jasmine.SpyObj<DocumentService>;
33
+ fixture.detectChanges();
34
+ });
35
+
36
+ it('should create', () => {
37
+ expect(component).toBeTruthy();
38
+ });
39
+
40
+ it('should call set method of documentService on ngOnChanges when selectedDocument is set', () => {
41
+ const document: DocumentModel = { _id: '22', contentType: 'image/png', documentUrl: 'http://example.com/image.png', status: 'approved' };
42
+ component.selectedDocument = document;
43
+ component.ngOnChanges();
44
+ expect(documentService.set).toHaveBeenCalledWith(document);
45
+ });
46
+
47
+ it('should determine if content type is an image', () => {
48
+ const validImageType = 'image/png';
49
+ const invalidImageType = 'application/pdf';
50
+ expect(component.isImage(validImageType)).toBeTrue();
51
+ expect(component.isImage(invalidImageType)).toBeFalse();
52
+ });
53
+
54
+ it('should set selectedDocument correctly when handleSelectedDocument is called', () => {
55
+ const document: DocumentModel = { _id: '22', contentType: 'image/png', documentUrl: 'http://example.com/image.png' };
56
+ component.handleSelectedDocument(document);
57
+ expect(component.selectedDocument).toEqual(document);
58
+ expect(documentService.set).toHaveBeenCalledWith(document);
59
+ });
60
+
61
+ it('should display the document image if selectedDocument is an image', () => {
62
+ const imageDocument: DocumentModel = {
63
+ _id : "122",
64
+ contentType: 'image/png',
65
+ documentUrl: 'http://example.com/image.png',
66
+ };
67
+ component.selectedDocument = imageDocument;
68
+ fixture.detectChanges();
69
+ const imgElement = fixture.debugElement.nativeElement.querySelector('.img-container img');
70
+ expect(imgElement).toBeTruthy();
71
+ expect(imgElement.src).toContain('http://example.com/image.png');
72
+ });
73
+
74
+ it('should update isVerified flag', () => {
75
+ component.isVerified = true;
76
+ fixture.detectChanges();
77
+ expect(component.isVerified).toBeTrue();
78
+ });
79
+ });
@@ -0,0 +1,106 @@
1
+ import {
2
+ Component,
3
+ Input,
4
+ OnChanges,
5
+ OnDestroy,
6
+ SimpleChanges,
7
+ ViewEncapsulation,
8
+ } from '@angular/core';
9
+ import { DynamicDialogRef } from 'primeng/dynamicdialog';
10
+ import { DocumentAlertList, DUMMYSUMMARY, SHARED, SUPPORTED_IMAGE_TYPES } from '../../../../Shared/constant/SHARED';
11
+ import { DocumentHttpService } from '../../services/document-http.service';
12
+ import { Subscription } from 'rxjs';
13
+ import { DocumentModel } from '../../models/document.model';
14
+ import { DocumentService } from '../../services/document.service';
15
+
16
+ /**
17
+ * Component for viewing and managing document details.
18
+ * @class DocumentViewerComponent
19
+ * @typedef {DocumentViewerComponent}
20
+ */
21
+ @Component({
22
+ selector: 'document-viewer',
23
+ templateUrl: './document-viewer.component.html',
24
+ standalone : false,
25
+ styleUrl: './document-viewer.component.scss',
26
+ encapsulation: ViewEncapsulation.None,
27
+ })
28
+ export class DocumentViewerComponent implements OnChanges, OnDestroy {
29
+ /**
30
+ * Get the selected document by user.
31
+ * @type {*}
32
+ */
33
+ @Input() selectedDocument?: DocumentModel; // <-- Made optional to prevent undefined issues
34
+ /**
35
+ * Get the selected document by user.
36
+ * @type {*}
37
+ */
38
+ @Input() documentList?: DocumentModel[]; // <-- Made optional to prevent undefined issues
39
+
40
+ /**
41
+ * Indicates whether a checkbox is selected.
42
+ * @type {boolean}
43
+ */
44
+ checked: boolean = false;
45
+
46
+ /**
47
+ * Reference to the dynamic dialog used for displaying additional details.
48
+ * @type {(DynamicDialogRef | undefined)}
49
+ */
50
+ ref: DynamicDialogRef | undefined;
51
+
52
+ /**
53
+ * Indicates whether the document has been verified.
54
+ * @type {boolean}
55
+ */
56
+ isVerified: boolean = false;
57
+
58
+ /**
59
+ * Data used for displaying alert messages.
60
+ * @type {any}
61
+ */
62
+ alertData!: any;
63
+
64
+ /**
65
+ * Holds the subscription to manage observable cleanup.
66
+ * @private
67
+ * @type {Subscription}
68
+ */
69
+ private subscription: Subscription = new Subscription();
70
+ /**
71
+ * Initializes a new instance of the DocumentViewerComponent.
72
+ * @param {DocumentHttpService} documentHttpService - Handle the http service.
73
+ * @param {DocumentService} documentService - Handle the states.
74
+ */
75
+ constructor(public documentHttpService : DocumentHttpService, private documentService: DocumentService) {}
76
+
77
+ /**
78
+ * Fetches the alerts for the selected document.
79
+ * @returns {void}
80
+ */
81
+ ngOnChanges() {
82
+ if (this.selectedDocument) {
83
+ this.documentService.set(this.selectedDocument);
84
+ this.alertData = DocumentAlertList.find((res: any) => res.status === this.selectedDocument?.status);
85
+ }
86
+ }
87
+
88
+ handleSelectedDocument(document:DocumentModel){
89
+ this.selectedDocument = document
90
+ this.documentService.set(this.selectedDocument);
91
+ }
92
+
93
+ /**
94
+ * Determines if the given content type is an image.
95
+ * @param {string | undefined} contentType - The MIME type of the content.
96
+ * @returns {boolean} `true` if the content type is an image; otherwise, `false`.
97
+ */
98
+ isImage(contentType?: string): boolean {
99
+ return contentType ? SUPPORTED_IMAGE_TYPES.includes(contentType) : false;
100
+ }
101
+
102
+ ngOnDestroy(): void {
103
+ this.subscription.unsubscribe();
104
+ }
105
+
106
+ }
@@ -0,0 +1,46 @@
1
+ <div class="card p-0 folder-info">
2
+ <div class="text-900 text-xl font-semibold ml-2 mb-1">Folders</div>
3
+ <div class="grid m-0">
4
+ <div *ngFor="let folder of folderList" class="col-12 md:col-6 xl:col-4 container-wrapper">
5
+ <div
6
+ class="p-3 border-1 h-full surface-border flex flex-column justify-content-between hover:surface-100 cursor-pointer border-round"
7
+ (click)="handleClickForFilter(folder._id)"
8
+ >
9
+ <div class="icon">
10
+ <img src="../../../../assets/images/FolderImg.png" alt="" />
11
+ </div>
12
+ <div class="flex flex-column">
13
+ <span class="text-600 mt-2"> {{ folder.documentCount }} Files </span>
14
+ <span class="text-900 text-lg mt-2 mb-2 font-semibold font-medium">
15
+ {{ folder.folderName }}
16
+ </span>
17
+ </div>
18
+ <hr />
19
+ <div class="flex justify-content-between">
20
+ <div class="flex flex-column">
21
+ <span>Missing</span>
22
+ <span
23
+ [ngClass]="{
24
+ 'text-pink-500': missingFileCount > 0,
25
+ 'text-green-500': missingFileCount === 0
26
+ }"
27
+ >
28
+ {{ missingFileCount }}
29
+ </span>
30
+ </div>
31
+ <div class="flex flex-column">
32
+ <span>Pending</span>
33
+ <span
34
+ [ngClass]="{
35
+ 'text-yellow-500': pendingFileCount > 0,
36
+ 'text-green-500': pendingFileCount === 0
37
+ }"
38
+ >
39
+ {{ pendingFileCount }}
40
+ </span>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
@@ -0,0 +1,9 @@
1
+ .container-wrapper{
2
+ &:nth-child(3n + 1) {
3
+ padding-left: 0;
4
+ }
5
+
6
+ &:nth-child(3n) {
7
+ padding-right: 0;
8
+ }
9
+ }