cat-documents-ng 1.0.4 → 1.0.6

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 (210) hide show
  1. package/ng-package.json +10 -0
  2. package/package.json +5 -11
  3. package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.html +3 -0
  4. package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.scss +13 -0
  5. package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.spec.ts +70 -0
  6. package/src/Shared/components/confirmation-dialog/confirmation-dialog.component.ts +133 -0
  7. package/src/Shared/components/table-primary/table-primary.component.html +66 -0
  8. package/src/Shared/components/table-primary/table-primary.component.scss +227 -0
  9. package/src/Shared/components/table-primary/table-primary.component.spec.ts +23 -0
  10. package/src/Shared/components/table-primary/table-primary.component.ts +143 -0
  11. package/src/Shared/components/table-primary/table-primary.model.ts +21 -0
  12. package/src/Shared/constant/ERROR.ts +55 -0
  13. package/src/Shared/constant/PERMISSIONS.ts +17 -0
  14. package/src/Shared/constant/SHARED.ts +936 -0
  15. package/{Shared/constant/URLS.d.ts → src/Shared/constant/URLS.ts} +31 -25
  16. package/src/Shared/services/app-config.service.spec.ts +19 -0
  17. package/src/Shared/services/app-config.service.ts +73 -0
  18. package/{Shared/services/global-error.handler.d.ts → src/Shared/services/global-error.handler.ts} +11 -9
  19. package/src/Shared/services/session.service.spec.ts +16 -0
  20. package/src/Shared/services/session.service.ts +76 -0
  21. package/src/Shared/shared.module.ts +25 -0
  22. package/src/lib/document/components/csv-viewer/csv-viewer.component.ts +1 -0
  23. package/src/lib/document/components/document-actions/document-actions.component.html +59 -0
  24. package/src/lib/document/components/document-actions/document-actions.component.scss +362 -0
  25. package/src/lib/document/components/document-actions/document-actions.component.spec.ts +297 -0
  26. package/src/lib/document/components/document-actions/document-actions.component.ts +163 -0
  27. package/src/lib/document/components/document-container/document-container.component.html +36 -0
  28. package/src/lib/document/components/document-container/document-container.component.scss +144 -0
  29. package/src/lib/document/components/document-container/document-container.component.spec.ts +110 -0
  30. package/src/lib/document/components/document-container/document-container.component.ts +363 -0
  31. package/src/lib/document/components/document-content-viewer/document-content-viewer.component.html +332 -0
  32. package/src/lib/document/components/document-content-viewer/document-content-viewer.component.scss +1877 -0
  33. package/src/lib/document/components/document-content-viewer/document-content-viewer.component.spec.ts +258 -0
  34. package/src/lib/document/components/document-content-viewer/document-content-viewer.component.ts +664 -0
  35. package/src/lib/document/components/document-history/document-history.component.html +96 -0
  36. package/src/lib/document/components/document-history/document-history.component.scss +392 -0
  37. package/src/lib/document/components/document-history/document-history.component.spec.ts +93 -0
  38. package/src/lib/document/components/document-history/document-history.component.ts +373 -0
  39. package/src/lib/document/components/document-list/document-list.component.html +46 -0
  40. package/src/lib/document/components/document-list/document-list.component.scss +513 -0
  41. package/src/lib/document/components/document-list/document-list.component.spec.ts +486 -0
  42. package/src/lib/document/components/document-list/document-list.component.ts +682 -0
  43. package/src/lib/document/components/document-list-item/document-list-item.component.html +36 -0
  44. package/src/lib/document/components/document-list-item/document-list-item.component.scss +34 -0
  45. package/src/lib/document/components/document-list-item/document-list-item.component.spec.ts +75 -0
  46. package/src/lib/document/components/document-list-item/document-list-item.component.ts +40 -0
  47. package/src/lib/document/components/document-search/document-search.component.html +64 -0
  48. package/src/lib/document/components/document-search/document-search.component.scss +206 -0
  49. package/src/lib/document/components/document-search/document-search.component.spec.ts +82 -0
  50. package/src/lib/document/components/document-search/document-search.component.ts +163 -0
  51. package/src/lib/document/components/document-status/document-status.component.html +31 -0
  52. package/src/lib/document/components/document-status/document-status.component.scss +192 -0
  53. package/src/lib/document/components/document-status/document-status.component.spec.ts +23 -0
  54. package/src/lib/document/components/document-status/document-status.component.ts +87 -0
  55. package/src/lib/document/components/document-upload/document-upload.component.html +160 -0
  56. package/src/lib/document/components/document-upload/document-upload.component.scss +235 -0
  57. package/src/lib/document/components/document-upload/document-upload.component.spec.ts +95 -0
  58. package/src/lib/document/components/document-upload/document-upload.component.ts +668 -0
  59. package/src/lib/document/components/document-viewer/document-viewer.component.html +50 -0
  60. package/src/lib/document/components/document-viewer/document-viewer.component.scss +187 -0
  61. package/src/lib/document/components/document-viewer/document-viewer.component.spec.ts +79 -0
  62. package/src/lib/document/components/document-viewer/document-viewer.component.ts +261 -0
  63. package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.html +48 -0
  64. package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.scss +320 -0
  65. package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.spec.ts +59 -0
  66. package/src/lib/document/components/document-zoom-controls/document-zoom-controls.component.ts +150 -0
  67. package/src/lib/document/components/documents-menu/documents-menu.component.html +44 -0
  68. package/src/lib/document/components/documents-menu/documents-menu.component.scss +363 -0
  69. package/src/lib/document/components/documents-menu/documents-menu.component.spec.ts +23 -0
  70. package/src/lib/document/components/documents-menu/documents-menu.component.ts +316 -0
  71. package/src/lib/document/components/folder-block/folder-block.component.html +46 -0
  72. package/src/lib/document/components/folder-block/folder-block.component.scss +9 -0
  73. package/src/lib/document/components/folder-block/folder-block.component.spec.ts +70 -0
  74. package/{lib/document/components/folder-block/folder-block.component.d.ts → src/lib/document/components/folder-block/folder-block.component.ts} +28 -12
  75. package/src/lib/document/components/folder-container/folder-container.component.html +56 -0
  76. package/src/lib/document/components/folder-container/folder-container.component.scss +20 -0
  77. package/src/lib/document/components/folder-container/folder-container.component.spec.ts +27 -0
  78. package/src/lib/document/components/folder-container/folder-container.component.ts +328 -0
  79. package/src/lib/document/components/linked-document/linked-document.component.html +23 -0
  80. package/src/lib/document/components/linked-document/linked-document.component.scss +10 -0
  81. package/src/lib/document/components/linked-document/linked-document.component.spec.ts +61 -0
  82. package/src/lib/document/components/linked-document/linked-document.component.ts +49 -0
  83. package/src/lib/document/components/request-document/request-document.component.html +86 -0
  84. package/src/lib/document/components/request-document/request-document.component.scss +16 -0
  85. package/src/lib/document/components/request-document/request-document.component.ts +278 -0
  86. package/src/lib/document/components/sidebar/sidebar.component.html +75 -0
  87. package/src/lib/document/components/sidebar/sidebar.component.scss +157 -0
  88. package/src/lib/document/components/sidebar/sidebar.component.spec.ts +114 -0
  89. package/src/lib/document/components/sidebar/sidebar.component.ts +223 -0
  90. package/src/lib/document/components/user-list/user-list.component.html +33 -0
  91. package/src/lib/document/components/user-list/user-list.component.scss +118 -0
  92. package/src/lib/document/components/user-list/user-list.component.spec.ts +23 -0
  93. package/src/lib/document/components/user-list/user-list.component.ts +181 -0
  94. package/src/lib/document/constant/DOCUMENT_HISTORY.ts +52 -0
  95. package/src/lib/document/directives/document.directive.ts +32 -0
  96. package/src/lib/document/directives/permission.directive.spec.ts +0 -0
  97. package/src/lib/document/directives/permission.directive.ts +72 -0
  98. package/src/lib/document/document.module.ts +351 -0
  99. package/{lib/document/models/document-alert.model.d.ts → src/lib/document/models/document-alert.model.ts} +11 -4
  100. package/src/lib/document/models/document-category.model.ts +30 -0
  101. package/src/lib/document/models/document-history.model.ts +109 -0
  102. package/src/lib/document/models/document-list-response.model.ts +37 -0
  103. package/src/lib/document/models/document-type.model.ts +44 -0
  104. package/src/lib/document/models/document.model.ts +53 -0
  105. package/{lib/document/models/folder.model.d.ts → src/lib/document/models/folder.model.ts} +10 -4
  106. package/src/lib/document/models/status-data.model.ts +31 -0
  107. package/src/lib/document/models/uploaded-file-response.model.ts +7 -0
  108. package/src/lib/document/models/user-list.model.ts +10 -0
  109. package/src/lib/document/services/csv-parser.service.spec.ts +97 -0
  110. package/src/lib/document/services/csv-parser.service.ts +303 -0
  111. package/src/lib/document/services/document-actions.service.ts +125 -0
  112. package/src/lib/document/services/document-content-type.service.ts +193 -0
  113. package/src/lib/document/services/document-history-style.service.ts +138 -0
  114. package/src/lib/document/services/document-history.service.ts +129 -0
  115. package/src/lib/document/services/document-http.service.spec.ts +119 -0
  116. package/src/lib/document/services/document-http.service.ts +497 -0
  117. package/src/lib/document/services/document-list.service.ts +195 -0
  118. package/src/lib/document/services/document-menu.service.ts +277 -0
  119. package/src/lib/document/services/document-scroll.service.ts +138 -0
  120. package/src/lib/document/services/document-severity.service.ts +98 -0
  121. package/src/lib/document/services/document-table-builder.service.ts +82 -0
  122. package/src/lib/document/services/document-upload-business.service.ts +326 -0
  123. package/src/lib/document/services/document-upload-data.service.ts +82 -0
  124. package/src/lib/document/services/document-upload-form.service.ts +149 -0
  125. package/src/lib/document/services/document-upload.service.spec.ts +99 -0
  126. package/src/lib/document/services/document-upload.service.ts +209 -0
  127. package/src/lib/document/services/document-viewer.service.ts +279 -0
  128. package/src/lib/document/services/document-zoom.service.spec.ts +56 -0
  129. package/src/lib/document/services/document-zoom.service.ts +164 -0
  130. package/src/lib/document/services/document.service.ts +356 -0
  131. package/src/lib/document/services/eml-parser.service.ts +444 -0
  132. package/src/lib/document/services/excel-parser.service.spec.ts +66 -0
  133. package/src/lib/document/services/excel-parser.service.ts +483 -0
  134. package/src/lib/document/services/file-format.service.spec.ts +16 -0
  135. package/src/lib/document/services/file-format.service.ts +63 -0
  136. package/src/lib/document/services/status-calculator.service.ts +44 -0
  137. package/src/lib/document/services/user-list.service.ts +77 -0
  138. package/src/lib/document/state/document.query.ts +378 -0
  139. package/{lib/document/state/document.service.d.ts → src/lib/document/state/document.service.ts} +46 -15
  140. package/src/lib/document/state/document.state.ts +100 -0
  141. package/src/lib/document/state/document.store.ts +200 -0
  142. package/{public-api.d.ts → src/public-api.ts} +4 -0
  143. package/tsconfig.lib.json +15 -0
  144. package/tsconfig.lib.prod.json +11 -0
  145. package/tsconfig.spec.json +15 -0
  146. package/Shared/components/confirmation-dialog/confirmation-dialog.component.d.ts +0 -44
  147. package/Shared/components/table-primary/table-primary.component.d.ts +0 -31
  148. package/Shared/components/table-primary/table-primary.model.d.ts +0 -19
  149. package/Shared/constant/ERROR.d.ts +0 -52
  150. package/Shared/constant/SHARED.d.ts +0 -546
  151. package/Shared/services/app-config.service.d.ts +0 -51
  152. package/Shared/services/session.service.d.ts +0 -46
  153. package/Shared/shared.module.d.ts +0 -14
  154. package/fesm2022/cat-documents-ng.mjs +0 -11392
  155. package/fesm2022/cat-documents-ng.mjs.map +0 -1
  156. package/index.d.ts +0 -5
  157. package/lib/document/components/document-actions/document-actions.component.d.ts +0 -78
  158. package/lib/document/components/document-container/document-container.component.d.ts +0 -162
  159. package/lib/document/components/document-content-viewer/document-content-viewer.component.d.ts +0 -291
  160. package/lib/document/components/document-history/document-history.component.d.ts +0 -160
  161. package/lib/document/components/document-list/document-list.component.d.ts +0 -299
  162. package/lib/document/components/document-list-item/document-list-item.component.d.ts +0 -28
  163. package/lib/document/components/document-search/document-search.component.d.ts +0 -77
  164. package/lib/document/components/document-status/document-status.component.d.ts +0 -24
  165. package/lib/document/components/document-upload/document-upload.component.d.ts +0 -321
  166. package/lib/document/components/document-viewer/document-viewer.component.d.ts +0 -137
  167. package/lib/document/components/document-zoom-controls/document-zoom-controls.component.d.ts +0 -33
  168. package/lib/document/components/documents-menu/documents-menu.component.d.ts +0 -110
  169. package/lib/document/components/folder-container/folder-container.component.d.ts +0 -162
  170. package/lib/document/components/linked-document/linked-document.component.d.ts +0 -39
  171. package/lib/document/components/request-document/request-document.component.d.ts +0 -69
  172. package/lib/document/components/sidebar/sidebar.component.d.ts +0 -109
  173. package/lib/document/components/user-list/user-list.component.d.ts +0 -34
  174. package/lib/document/constant/DOCUMENT_HISTORY.d.ts +0 -41
  175. package/lib/document/directives/document.directive.d.ts +0 -20
  176. package/lib/document/directives/permission.directive.d.ts +0 -38
  177. package/lib/document/document.module.d.ts +0 -60
  178. package/lib/document/models/document-category.model.d.ts +0 -24
  179. package/lib/document/models/document-history.model.d.ts +0 -94
  180. package/lib/document/models/document-list-response.model.d.ts +0 -33
  181. package/lib/document/models/document-type.model.d.ts +0 -37
  182. package/lib/document/models/document.model.d.ts +0 -44
  183. package/lib/document/models/status-data.model.d.ts +0 -27
  184. package/lib/document/models/uploaded-file-response.model.d.ts +0 -7
  185. package/lib/document/models/user-list.model.d.ts +0 -8
  186. package/lib/document/services/csv-parser.service.d.ts +0 -88
  187. package/lib/document/services/document-actions.service.d.ts +0 -48
  188. package/lib/document/services/document-content-type.service.d.ts +0 -85
  189. package/lib/document/services/document-history-style.service.d.ts +0 -34
  190. package/lib/document/services/document-history.service.d.ts +0 -42
  191. package/lib/document/services/document-http.service.d.ts +0 -179
  192. package/lib/document/services/document-list.service.d.ts +0 -74
  193. package/lib/document/services/document-menu.service.d.ts +0 -122
  194. package/lib/document/services/document-scroll.service.d.ts +0 -55
  195. package/lib/document/services/document-table-builder.service.d.ts +0 -38
  196. package/lib/document/services/document-upload-business.service.d.ts +0 -107
  197. package/lib/document/services/document-upload-data.service.d.ts +0 -40
  198. package/lib/document/services/document-upload-form.service.d.ts +0 -41
  199. package/lib/document/services/document-upload.service.d.ts +0 -99
  200. package/lib/document/services/document-viewer.service.d.ts +0 -97
  201. package/lib/document/services/document-zoom.service.d.ts +0 -81
  202. package/lib/document/services/document.service.d.ts +0 -161
  203. package/lib/document/services/eml-parser.service.d.ts +0 -116
  204. package/lib/document/services/excel-parser.service.d.ts +0 -169
  205. package/lib/document/services/file-format.service.d.ts +0 -34
  206. package/lib/document/services/status-calculator.service.d.ts +0 -20
  207. package/lib/document/services/user-list.service.d.ts +0 -29
  208. package/lib/document/state/document.query.d.ts +0 -243
  209. package/lib/document/state/document.state.d.ts +0 -61
  210. package/lib/document/state/document.store.d.ts +0 -56
@@ -0,0 +1,209 @@
1
+ import { Injectable, EventEmitter } from '@angular/core';
2
+ import { SHARED } from '../../../Shared/constant/SHARED';
3
+ import { DocumentService } from '../state/document.service';
4
+ import { DocumentStore } from '../state/document.store';
5
+ import { MessageService } from 'primeng/api';
6
+
7
+ /**
8
+ * Service for handling document uploads.
9
+ * @class DocumentUploadService
10
+ * @typedef {DocumentUploadService}
11
+ */
12
+ @Injectable({
13
+ providedIn: 'root'
14
+ })
15
+ export class DocumentUploadService {
16
+
17
+ /**
18
+ * Event emitter for upload completion
19
+ */
20
+ uploadCompleted = new EventEmitter<{file: File, response: any}>();
21
+
22
+ /**
23
+ * The file to upload.
24
+ * @type {*}
25
+ */
26
+ uploadedFile: any;
27
+
28
+ /**
29
+ * Represent contextId
30
+ * @type {string}
31
+ */
32
+ contextId: string = SHARED.EMPTY;
33
+
34
+ /**
35
+ * Represent document name
36
+ * @type {string}
37
+ */
38
+ docName: string = SHARED.EMPTY
39
+
40
+ /**
41
+ * Represent document id
42
+ * @type {string}
43
+ */
44
+ docTypeId: string = SHARED.EMPTY
45
+
46
+ /**
47
+ * Creates an instance of DocumentUploadService.
48
+ * @param {DocumentService} documentService - Service for handling document uploads.
49
+ * @param {DocumentStore} documentUploadStore - Store for managing uploaded documents.
50
+ * @param {MessageService} messageService - Service for displaying messages.
51
+ * @returns {void}
52
+ */
53
+ constructor(public documentService: DocumentService, public documentUploadStore: DocumentStore, public messageService: MessageService) { }
54
+
55
+ /**
56
+ * Prepares the files for upload by creating a FormData object.
57
+ * This method appends each file to the FormData for submission.
58
+ * @returns {Promise<any>} Promise that resolves when upload completes
59
+ */
60
+ handleTemplatedUpload(file: File, contextId: string): Promise<any> {
61
+ return new Promise((resolve, reject) => {
62
+ let formsData = this.handleCreateFormData(file, contextId)
63
+ if (!formsData) {
64
+ const error = new Error('Failed to create form data');
65
+ this.messageService.add({severity: SHARED.SEVERITY,summary: SHARED.UPLOAD_ERROR_SUMMERY,detail: SHARED.UPLOAD_ERROR_DETAILS});
66
+ reject(error);
67
+ return;
68
+ }
69
+ this.documentService.create(formsData)
70
+ .subscribe({
71
+ /**
72
+ * Handles the successful upload event.
73
+ * Updates the list of uploaded files and emits the file ID.
74
+ * @returns {void}
75
+ */
76
+ next: (event) => {
77
+ this.documentUploadStore.setUploadedDocumentFiles(event)
78
+ this.documentUploadStore.setMessage([{severity: SHARED.SUCCESS_SEVERITY,detail : SHARED.UPLOAD_SUCCESS}]);
79
+ this.uploadCompleted.emit({file: file, response: event});
80
+ resolve(event);
81
+ },
82
+ /**
83
+ * Handles the error event during file upload.
84
+ * Updates the progress of the file to indicate failure.
85
+ * @param {any} error - The error object returned by the upload service.
86
+ */
87
+ error: (error) => {
88
+ this.messageService.add({severity: SHARED.SEVERITY,summary: SHARED.UPLOAD_SUMMERY,detail: error?.message});
89
+ reject(error);
90
+ },
91
+ });
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Uploads multiple files sequentially using promises
97
+ * @param files - Array of files to upload
98
+ * @param contextId - The context ID for upload
99
+ * @returns {Promise<any[]>} Promise that resolves with all upload responses
100
+ */
101
+ async uploadFilesSequentially(files: File[], contextId: string): Promise<any[]> {
102
+ const results: any[] = [];
103
+
104
+ for (const file of files) {
105
+ try {
106
+ const result = await this.handleTemplatedUpload(file, contextId);
107
+ results.push(result);
108
+ } catch (error) {
109
+ console.error(`Failed to upload file ${file.name}:`, error);
110
+ results.push({ error: true, fileName: file.name, errorMessage: error });
111
+ }
112
+ }
113
+
114
+ return results;
115
+ }
116
+
117
+ /**
118
+ * Alternative method to upload files sequentially with progress tracking
119
+ * @param files - Array of files to upload
120
+ * @param contextId - The context ID for upload
121
+ * @param onProgress - Optional callback for progress updates
122
+ * @returns {Promise<any[]>} Promise that resolves with all upload responses
123
+ */
124
+ async uploadFilesSequentiallyWithProgress(
125
+ files: File[],
126
+ contextId: string,
127
+ onProgress?: (currentFile: File, currentIndex: number, totalFiles: number) => void
128
+ ): Promise<any[]> {
129
+ const results: any[] = [];
130
+ for (let i = 0; i < files.length; i++) {
131
+ const file = files[i];
132
+ if (onProgress) {
133
+ onProgress(file, i, files.length);
134
+ }
135
+
136
+ try {
137
+ const result = await this.handleTemplatedUpload(file, contextId);
138
+ results.push(result);
139
+ } catch (error) {
140
+ console.error(`Failed to upload file ${file.name}:`, error);
141
+ results.push({ error: true, fileName: file.name, errorMessage: error });
142
+ }
143
+ }
144
+
145
+ return results;
146
+ }
147
+
148
+ /**
149
+ * Get the file and contextId
150
+ * @param file - The file to upload.
151
+ * @param contextId - The contextId to upload.
152
+ */
153
+ getUploadFileData(file: File, contextId: string) {
154
+ if (file && contextId) {
155
+ this.uploadedFile = file;
156
+ this.contextId = contextId;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Get the document name and document type id
162
+ * @param documentName - The document name to upload.
163
+ * @param documentTypeId - The document type id to upload.
164
+ */
165
+ getDocumentNameAndType(documentTypeId: string) {
166
+ if (documentTypeId && documentTypeId !== SHARED.EMPTY) {
167
+ this.docTypeId = documentTypeId
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Handle the creation of formdata.
173
+ * @returns {*} - The formdata object.
174
+ */
175
+ handleCreateFormData(uploadedFile?: File, contextId?: string) {
176
+
177
+ if (uploadedFile) {
178
+ let formData = new FormData();
179
+ formData.append(SHARED.FILE, uploadedFile, uploadedFile.name);
180
+ formData.append(SHARED.CONTEXT_ID, this.contextId || contextId || SHARED.EMPTY)
181
+ return formData;
182
+ }else{
183
+ return null;
184
+ }
185
+
186
+ }
187
+
188
+ /**
189
+ * Generic method to sort any list of objects by a specified property.
190
+ * Supports fallback properties if the primary property is undefined.
191
+ * @param list - Array of objects to sort
192
+ * @param primaryProperty - Primary property to sort by
193
+ * @param fallbackProperty - Optional fallback property if primary is undefined
194
+ * @returns Sorted array
195
+ */
196
+ sortListByProperty<T>(list: T[], primaryProperty: keyof T, fallbackProperty?: keyof T): T[] {
197
+ return list.sort((a, b) => {
198
+ const valueA = a[primaryProperty] || (fallbackProperty ? a[fallbackProperty] : SHARED.EMPTY);
199
+ const valueB = b[primaryProperty] || (fallbackProperty ? b[fallbackProperty] : SHARED.EMPTY);
200
+
201
+ if (typeof valueA === 'string' && typeof valueB === 'string') {
202
+ return valueA.localeCompare(valueB);
203
+ }
204
+ if (valueA < valueB) return -1;
205
+ if (valueA > valueB) return 1;
206
+ return 0;
207
+ });
208
+ }
209
+ }
@@ -0,0 +1,279 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ import { DocumentHttpService } from './document-http.service';
4
+ import { DocumentHelperService } from './document.service';
5
+ import { DocumentListItem } from '../models/document-list-response.model';
6
+ import { DocumentHistorySection } from '../models/document-history.model';
7
+ import { DocumentAction } from './document-actions.service';
8
+ import { DocumentAlertList, SHARED, SUPPORTED_IMAGE_TYPES } from '../../../Shared/constant/SHARED';
9
+ import { MessageService } from 'primeng/api';
10
+ import { DocumentStore } from '../state/document.store';
11
+ import { DocumentQuery } from '../state/document.query';
12
+
13
+ export interface DocumentViewerState {
14
+ selectedDocument?: DocumentListItem;
15
+ documentHistory: DocumentHistorySection[];
16
+ showDocumentHistory: boolean;
17
+ isActionLoading: boolean;
18
+ documentStatus: 'pending' | 'accepted' | 'rejected';
19
+ documentIsUploaded: boolean;
20
+ alertData: any;
21
+ deleteError: any;
22
+ deleteSuccess: boolean;
23
+ }
24
+
25
+ @Injectable({
26
+ providedIn: 'root'
27
+ })
28
+ export class DocumentViewerService {
29
+ constructor(
30
+ private documentHttpService: DocumentHttpService,
31
+ private documentService: DocumentHelperService,
32
+ private messageService: MessageService,
33
+ private documentStore: DocumentStore,
34
+ private documentQuery: DocumentQuery
35
+ ) {}
36
+
37
+ /**
38
+ * Gets the current document viewer state as an observable
39
+ */
40
+ get state$(): Observable<DocumentViewerState> {
41
+ return this.documentQuery.selectDocumentViewerState();
42
+ }
43
+
44
+ /**
45
+ * Gets the current document viewer state synchronously
46
+ */
47
+ getCurrentState(): DocumentViewerState {
48
+ return this.documentQuery.getDocumentViewerState();
49
+ }
50
+
51
+ /**
52
+ * Updates the selected document and recalculates all computed properties
53
+ * @param document The selected document
54
+ */
55
+ updateSelectedDocument(document: DocumentListItem, skipLoadDocumentHistory: boolean = false): void {
56
+ this.documentService.set(document);
57
+ const alertData = this.getAlertData(document);
58
+ const documentStatus = this.calculateDocumentStatus(document);
59
+ const documentIsUploaded = this.calculateIsDocumentUploaded(document);
60
+
61
+ this.documentStore.updateDocumentViewerState(
62
+ document,
63
+ undefined,
64
+ undefined,
65
+ undefined,
66
+ documentStatus,
67
+ documentIsUploaded,
68
+ alertData
69
+ );
70
+
71
+ if( !skipLoadDocumentHistory && document?._id ) this.loadDocumentHistory(document._id);
72
+ }
73
+
74
+ /**
75
+ * Loads document history data
76
+ * @param documentId The document ID
77
+ */
78
+ loadDocumentHistory(documentId: string): void {
79
+ if (documentId) {
80
+ this.documentHttpService.getDocumentHistory(documentId)
81
+ .subscribe({
82
+ next: (history) => {
83
+ this.documentStore.updateDocumentViewerState(
84
+ undefined,
85
+ history,
86
+ true
87
+ );
88
+ },
89
+ error: (error) => {
90
+ this.documentStore.updateDocumentViewerState(
91
+ undefined,
92
+ undefined,
93
+ false
94
+ );
95
+ }
96
+ });
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Determines if the given content type is an image
102
+ * @param contentType The MIME type of the content
103
+ * @returns True if the content type is an image
104
+ */
105
+ isImage(contentType?: string): boolean {
106
+ return contentType ? SUPPORTED_IMAGE_TYPES.includes(contentType) : false;
107
+ }
108
+
109
+ /**
110
+ * Handles document actions and updates status
111
+ * @param action The action performed
112
+ * @param contextId The context ID for API calls
113
+ */
114
+ handleDocumentAction(action: DocumentAction, contextId?: string): void {
115
+ const currentState = this.documentQuery.getDocumentViewerState();
116
+ if (!currentState.selectedDocument?._id) {
117
+ console.error('No document ID available');
118
+ return;
119
+ }
120
+
121
+ switch (action.type) {
122
+ case SHARED.ACCEPT_ACTION:
123
+ this.updateDocumentStatus(SHARED.STATUS_APPROVED, action.note || SHARED.DOCUMENT_ACCEPTED_MESSAGE, contextId);
124
+ break;
125
+ case SHARED.REJECT_ACTION:
126
+ this.updateDocumentStatus(SHARED.STATUS_REJECTED, action.note || SHARED.DOCUMENT_REJECTED_MESSAGE, contextId);
127
+ break;
128
+ case SHARED.DELETE_ACTION:
129
+ this.deleteDocument(currentState.selectedDocument._id, contextId);
130
+ // Don't emit success event here - it will be emitted only on successful delete
131
+ break;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Updates the document status via API call and refreshes all related data
137
+ * @param status The new status (Approved, Rejected)
138
+ * @param description The status update description
139
+ * @param contextId The context ID for API calls
140
+ */
141
+ private updateDocumentStatus(status: string, description: string, contextId?: string): void {
142
+ const currentState = this.documentQuery.getDocumentViewerState();
143
+ if (!currentState.selectedDocument?._id) {
144
+ console.error('No document ID available');
145
+ return;
146
+ }
147
+
148
+ this.documentStore.setIsActionLoading(true);
149
+
150
+ this.documentHttpService.updateDocumentStatus(
151
+ currentState.selectedDocument._id,
152
+ status,
153
+ description
154
+ ).subscribe({
155
+ next: (response) => {
156
+ if (currentState.selectedDocument && response.status) {
157
+ const normalizedStatus = response.normalizedStatus || response.status.toLowerCase();
158
+ const updatedDocument = {
159
+ ...currentState.selectedDocument,
160
+ status: normalizedStatus
161
+ };
162
+
163
+ this.updateSelectedDocument(updatedDocument);
164
+ }
165
+ this.refreshAllData(contextId);
166
+ },
167
+ error: (error) => {
168
+ console.error('Error updating document status:', error);
169
+ },
170
+ complete: () => {
171
+ this.documentStore.setIsActionLoading(false);
172
+ }
173
+ });
174
+ }
175
+
176
+ /**
177
+ * Deletes a document without immediate refresh - refresh will happen when viewer is closed
178
+ * @param documentId The ID of the document to delete
179
+ * @param contextId The context ID for API calls
180
+ */
181
+ private deleteDocument(documentId: string, contextId?: string): void {
182
+ if (!contextId) {
183
+ console.error('No context ID available for delete operation');
184
+ return;
185
+ }
186
+
187
+ this.documentStore.setIsActionLoading(true);
188
+
189
+ this.documentHttpService.deleteDocument(documentId, contextId).subscribe({
190
+ next: (res:any) => {
191
+ if(res){
192
+ // this.documentService.refreshAllDataWithCurrentFilters(contextId);
193
+ this.documentStore.setDeleteSuccess(true);
194
+ this.documentStore.clearDocumentViewerState();
195
+ }
196
+ },
197
+ error: (error) => {
198
+ this.documentStore.setIsActionLoading(false);
199
+ this.documentStore.setDeleteError(error.message);
200
+ }
201
+ });
202
+ }
203
+
204
+ /**
205
+ * Refreshes all related data after document status update
206
+ * @param contextId The context ID for API calls
207
+ */
208
+ private refreshAllData(contextId?: string): void {
209
+ if (!contextId) {
210
+ console.error('No context ID available for data refresh');
211
+ return;
212
+ }
213
+
214
+ const currentState = this.documentQuery.getDocumentViewerState();
215
+ if (currentState.selectedDocument?._id) {
216
+ this.loadDocumentHistory(currentState.selectedDocument._id);
217
+ }
218
+
219
+ // Use the same refresh method as other components for consistency
220
+ this.documentService.refreshAllDataWithCurrentFilters(contextId);
221
+ }
222
+
223
+ /**
224
+ * Gets alert data for the document
225
+ * @param document The document
226
+ * @returns Alert data
227
+ */
228
+ private getAlertData(document: DocumentListItem): any {
229
+ return DocumentAlertList.find((res: any) => res.status === document?.status);
230
+ }
231
+
232
+ /**
233
+ * Calculates the current status of the document for the actions component
234
+ * @param document The document
235
+ * @returns The current document status
236
+ */
237
+ private calculateDocumentStatus(document: DocumentListItem): 'pending' | 'accepted' | 'rejected' {
238
+ if (!document) return SHARED.STATUS_PENDING as 'pending';
239
+
240
+ // First check statusId from API response if available
241
+ if (document.statusId) {
242
+ switch (document.statusId.toLowerCase()) {
243
+ case SHARED.STATUS_APPROVED.toLowerCase():
244
+ return SHARED.STATUS_ACCEPTED as 'accepted';
245
+ case SHARED.STATUS_REJECTED.toLowerCase():
246
+ return SHARED.STATUS_REJECTED_LOWERCASE as 'rejected';
247
+ case SHARED.STATUS_PENDING:
248
+ return SHARED.STATUS_PENDING as 'pending';
249
+ }
250
+ }
251
+
252
+ // Fall back to status field mapping
253
+ switch (document.status?.toLowerCase()) {
254
+ case SHARED.STATUS_APPROVED.toLowerCase():
255
+ case SHARED.STATUS_ACCEPTED:
256
+ return SHARED.STATUS_ACCEPTED as 'accepted';
257
+ case SHARED.STATUS_REJECTED.toLowerCase():
258
+ case SHARED.STATUS_DECLINED:
259
+ return SHARED.STATUS_REJECTED_LOWERCASE as 'rejected';
260
+ default:
261
+ return SHARED.STATUS_PENDING as 'pending';
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Calculates if the document is uploaded and ready for actions
267
+ * @param document The document
268
+ * @returns True if document is uploaded
269
+ */
270
+ private calculateIsDocumentUploaded(document: DocumentListItem): boolean {
271
+ if (!document) return false;
272
+
273
+ // Check if document has a URL and is not in a pending state
274
+ const isPending = document.statusId?.toLowerCase() === SHARED.STATUS_PENDING ||
275
+ document.status?.toLowerCase() === SHARED.STATUS_PENDING;
276
+
277
+ return !!(document.documentUrl && !isPending);
278
+ }
279
+ }
@@ -0,0 +1,56 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+ import { DocumentZoomService } from './document-zoom.service';
3
+
4
+ describe('DocumentZoomService', () => {
5
+ let service: DocumentZoomService;
6
+
7
+ beforeEach(() => {
8
+ TestBed.configureTestingModule({});
9
+ service = TestBed.inject(DocumentZoomService);
10
+ });
11
+
12
+ it('should be created', () => {
13
+ expect(service).toBeTruthy();
14
+ });
15
+
16
+ it('should start with default zoom level', () => {
17
+ expect(service.currentZoom).toBe(100);
18
+ });
19
+
20
+ it('should zoom in correctly', () => {
21
+ service.zoomIn();
22
+ expect(service.currentZoom).toBe(125);
23
+ });
24
+
25
+ it('should zoom out correctly', () => {
26
+ service.zoomOut();
27
+ expect(service.currentZoom).toBe(75);
28
+ });
29
+
30
+ it('should respect max zoom limit', () => {
31
+ service.setZoom(400);
32
+ service.zoomIn();
33
+ expect(service.currentZoom).toBe(400);
34
+ });
35
+
36
+ it('should respect min zoom limit', () => {
37
+ service.setZoom(25);
38
+ service.zoomOut();
39
+ expect(service.currentZoom).toBe(25);
40
+ });
41
+
42
+ it('should reset zoom to default', () => {
43
+ service.setZoom(200);
44
+ service.resetZoom();
45
+ expect(service.currentZoom).toBe(100);
46
+ });
47
+
48
+ it('should emit zoom changes', (done) => {
49
+ service.zoomLevel$.subscribe(zoom => {
50
+ expect(zoom).toBe(150);
51
+ done();
52
+ });
53
+
54
+ service.setZoom(150);
55
+ });
56
+ });
@@ -0,0 +1,164 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject, Observable } from 'rxjs';
3
+
4
+ export interface ZoomConfig {
5
+ defaultZoom: number;
6
+ zoomStep: number;
7
+ minZoom: number;
8
+ maxZoom: number;
9
+ }
10
+
11
+ @Injectable({
12
+ providedIn: 'root'
13
+ })
14
+ export class DocumentZoomService {
15
+ private readonly DEFAULT_CONFIG: ZoomConfig = {
16
+ defaultZoom: 100,
17
+ zoomStep: 25,
18
+ minZoom: 25,
19
+ maxZoom: 400
20
+ };
21
+
22
+ private zoomLevelSubject = new BehaviorSubject<number>(this.DEFAULT_CONFIG.defaultZoom);
23
+ private config: ZoomConfig = { ...this.DEFAULT_CONFIG };
24
+
25
+ /**
26
+ * Gets the current zoom level as an observable
27
+ */
28
+ get zoomLevel$(): Observable<number> {
29
+ return this.zoomLevelSubject.asObservable();
30
+ }
31
+
32
+ /**
33
+ * Gets the current zoom level value
34
+ */
35
+ get currentZoom(): number {
36
+ return this.zoomLevelSubject.value;
37
+ }
38
+
39
+ /**
40
+ * Gets the current zoom configuration
41
+ */
42
+ get zoomConfig(): ZoomConfig {
43
+ return { ...this.config };
44
+ }
45
+
46
+ /**
47
+ * Sets custom zoom configuration
48
+ */
49
+ setZoomConfig(config: Partial<ZoomConfig>): void {
50
+ this.config = { ...this.DEFAULT_CONFIG, ...config };
51
+ this.setZoom(this.config.defaultZoom);
52
+ }
53
+
54
+ /**
55
+ * Zooms in by the configured step
56
+ */
57
+ zoomIn(): void {
58
+ const newZoom = Math.min(
59
+ this.currentZoom + this.config.zoomStep,
60
+ this.config.maxZoom
61
+ );
62
+ this.setZoom(newZoom);
63
+ }
64
+
65
+ /**
66
+ * Zooms out by the configured step
67
+ */
68
+ zoomOut(): void {
69
+ const newZoom = Math.max(
70
+ this.currentZoom - this.config.zoomStep,
71
+ this.config.minZoom
72
+ );
73
+ this.setZoom(newZoom);
74
+ }
75
+
76
+ /**
77
+ * Sets zoom to a specific level
78
+ */
79
+ setZoom(zoom: number): void {
80
+ const clampedZoom = Math.max(
81
+ this.config.minZoom,
82
+ Math.min(zoom, this.config.maxZoom)
83
+ );
84
+ this.zoomLevelSubject.next(clampedZoom);
85
+ }
86
+
87
+ /**
88
+ * Resets zoom to default level
89
+ */
90
+ resetZoom(): void {
91
+ this.setZoom(this.config.defaultZoom);
92
+ }
93
+
94
+ /**
95
+ * Handles mouse wheel zoom
96
+ */
97
+ handleWheelZoom(event: WheelEvent, zoomFactor: number = 0.1): void {
98
+ event.preventDefault();
99
+ // Only use deltaY for zoom (vertical wheel movement)
100
+ const delta = event.deltaY > 0 ? -1 : 1;
101
+ const zoomStep = this.config.zoomStep * zoomFactor;
102
+ const newZoom = this.currentZoom + (delta * zoomStep);
103
+ this.setZoom(newZoom);
104
+ }
105
+
106
+ /**
107
+ * Applies zoom transform to an iframe element
108
+ * @param iframe - The iframe element to apply zoom to
109
+ * @param zoomLevel - The zoom level to apply (defaults to current zoom)
110
+ */
111
+ applyIframeZoom(iframe: HTMLIFrameElement, zoomLevel?: number): void {
112
+ const zoom = zoomLevel ?? this.currentZoom;
113
+ const zoomScale = zoom / 100;
114
+
115
+ if (zoom === 100) {
116
+ iframe.style.transform = 'none';
117
+ iframe.style.width = '100%';
118
+ iframe.style.height = '100%';
119
+ } else {
120
+ iframe.style.transform = `scale(${zoomScale})`;
121
+ iframe.style.transformOrigin = 'top left';
122
+ iframe.style.width = `${100 / zoomScale}%`;
123
+ iframe.style.height = `${100 / zoomScale}%`;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Applies zoom transform to multiple iframe elements
129
+ * @param iframes - Array of iframe elements to apply zoom to
130
+ * @param zoomLevel - The zoom level to apply (defaults to current zoom)
131
+ */
132
+ applyIframeZoomToMultiple(iframes: HTMLIFrameElement[], zoomLevel?: number): void {
133
+ iframes.forEach(iframe => this.applyIframeZoom(iframe, zoomLevel));
134
+ }
135
+
136
+ /**
137
+ * Applies zoom transform to iframes within a container element
138
+ * @param container - The container element to search for iframes
139
+ * @param zoomLevel - The zoom level to apply (defaults to current zoom)
140
+ */
141
+ applyIframeZoomToContainer(container: HTMLElement, zoomLevel?: number): void {
142
+ const iframes = container.querySelectorAll('iframe') as NodeListOf<HTMLIFrameElement>;
143
+ this.applyIframeZoomToMultiple(Array.from(iframes), zoomLevel);
144
+ }
145
+
146
+ /**
147
+ * Applies zoom transform to iframes within multiple container elements
148
+ * @param containers - Array of container elements to search for iframes
149
+ * @param zoomLevel - The zoom level to apply (defaults to current zoom)
150
+ */
151
+ applyIframeZoomToContainers(containers: HTMLElement[], zoomLevel?: number): void {
152
+ containers.forEach(container => this.applyIframeZoomToContainer(container, zoomLevel));
153
+ }
154
+
155
+ /**
156
+ * Applies zoom transform to iframes by CSS selector
157
+ * @param selector - CSS selector to find iframe containers
158
+ * @param zoomLevel - The zoom level to apply (defaults to current zoom)
159
+ */
160
+ applyIframeZoomBySelector(selector: string, zoomLevel?: number): void {
161
+ const containers = document.querySelectorAll(selector) as NodeListOf<HTMLElement>;
162
+ this.applyIframeZoomToContainers(Array.from(containers), zoomLevel);
163
+ }
164
+ }