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,326 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Observable, Subject, takeUntil } from 'rxjs';
3
+ import { DocumentHttpService } from './document-http.service';
4
+ import { FileFormatService } from './file-format.service';
5
+ import { UserListModel } from '../models/user-list.model';
6
+ import { DocumentCategory } from '../models/document-category.model';
7
+ import { DocumentTypeModel } from '../models/document-type.model';
8
+ import { SHARED } from '../../../Shared/constant/SHARED';
9
+ import { UploadedFileResponse } from '../models/uploaded-file-response.model';
10
+
11
+ export interface UploadedFile {
12
+ file: File;
13
+ formattedSize?: string;
14
+ progress?: number;
15
+ uploadResponse?: UploadedFileResponse; // Store the upload response for later use
16
+ url?: string; // Store the file URL from upload response
17
+ contentType?: string;
18
+ fileName?: string; // Store the file name from upload response
19
+ size?: string; // Store the formatted size from upload response
20
+ }
21
+
22
+ export interface DocumentUploadPayload {
23
+ source: 'Applicant' | 'Application';
24
+ categoryId: string;
25
+ documentTypeId: string;
26
+ applicantId?: string;
27
+ contextId: string;
28
+ documents: {
29
+ fileName: string;
30
+ fileSize: number;
31
+ uploadedFileId?: string;
32
+ url?: string; // Store the file URL from upload response
33
+ contentType?: string;
34
+ size?: string; // Store the formatted size from upload response
35
+ }[];
36
+ }
37
+
38
+ @Injectable({
39
+ providedIn: 'root'
40
+ })
41
+ export class DocumentUploadBusinessService {
42
+ private destroy$ = new Subject<void>();
43
+
44
+ constructor(
45
+ private documentHttpService: DocumentHttpService,
46
+ private fileFormatService: FileFormatService
47
+ ) {}
48
+
49
+ /**
50
+ * Loads applicants for a given context ID
51
+ */
52
+ loadApplicants(contextId: string): Observable<UserListModel[]> {
53
+ return this.documentHttpService.getUserListByContextId(contextId);
54
+ }
55
+
56
+ /**
57
+ * Loads categories based on assignment type
58
+ */
59
+ loadCategories(assignmentType: string): Observable<DocumentCategory[]> {
60
+ return this.documentHttpService.getCategoriesBySource(assignmentType);
61
+ }
62
+
63
+ /**
64
+ * Loads document types based on category
65
+ */
66
+ loadDocumentTypes(categoryId: string): Observable<DocumentTypeModel[]> {
67
+ return this.documentHttpService.getDocumentTypesByCategory(categoryId);
68
+ }
69
+
70
+ /**
71
+ * Filters applicants based on assignment type
72
+ */
73
+ filterApplicants(applicantList: UserListModel[], assignmentType: 'Applicant' | 'Application'): UserListModel[] {
74
+ if (assignmentType === SHARED.APPLICANT) {
75
+ return applicantList.filter(applicant => applicant.name !== SHARED.APPLICATION_DOCS);
76
+ } else {
77
+ return applicantList.filter(applicant => applicant.name === SHARED.APPLICATION_DOCS);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Helper method to validate form data and return validation result
83
+ */
84
+ private validateFormData(
85
+ assignmentType: 'Applicant' | 'Application' | null,
86
+ selectedCategory: string,
87
+ selectedDocumentType: string,
88
+ selectedApplicant: string,
89
+ uploadedFiles: UploadedFile[],
90
+ categoryOptions: DocumentCategory[],
91
+ documentTypeOptions: DocumentTypeModel[]
92
+ ): { isValid: boolean; message: string } {
93
+ // Check assignment type
94
+ if (!assignmentType) {
95
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_ASSIGNMENT_TYPE };
96
+ }
97
+
98
+ // Check if options are loaded
99
+ if (!categoryOptions.length || !documentTypeOptions.length) {
100
+ return { isValid: false, message: SHARED.VALIDATION_OPTIONS_NOT_LOADED };
101
+ }
102
+
103
+ // Check category
104
+ if (!selectedCategory) {
105
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_CATEGORY };
106
+ }
107
+
108
+ // Check document type
109
+ if (!selectedDocumentType) {
110
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_DOCUMENT_TYPE };
111
+ }
112
+
113
+ // Check files
114
+ if (uploadedFiles.length === 0) {
115
+ return { isValid: false, message: SHARED.VALIDATION_UPLOAD_AT_LEAST_ONE };
116
+ }
117
+
118
+ // Check if all files are uploaded
119
+ const incompleteFiles = uploadedFiles.filter(file => file.progress !== 100);
120
+ if (incompleteFiles.length > 0) {
121
+ return { isValid: false, message: SHARED.VALIDATION_WAIT_FOR_UPLOAD };
122
+ }
123
+
124
+ // For Applicant type, check applicant selection
125
+ if (assignmentType === SHARED.APPLICANT && !selectedApplicant) {
126
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_APPLICANT };
127
+ }
128
+
129
+ return { isValid: true, message: SHARED.VALIDATION_ALL_FIELDS_COMPLETED };
130
+ }
131
+
132
+ /**
133
+ * Validates form data
134
+ */
135
+ validateForm(
136
+ assignmentType: 'Applicant' | 'Application' | null,
137
+ selectedCategory: string,
138
+ selectedDocumentType: string,
139
+ selectedApplicant: string,
140
+ uploadedFiles: UploadedFile[],
141
+ categoryOptions: DocumentCategory[],
142
+ documentTypeOptions: DocumentTypeModel[]
143
+ ): boolean {
144
+ return this.validateFormData(
145
+ assignmentType,
146
+ selectedCategory,
147
+ selectedDocumentType,
148
+ selectedApplicant,
149
+ uploadedFiles,
150
+ categoryOptions,
151
+ documentTypeOptions
152
+ ).isValid;
153
+ }
154
+
155
+ /**
156
+ * Checks if save button should be disabled
157
+ */
158
+ isSaveButtonDisabled(
159
+ assignmentType: 'Applicant' | 'Application' | null,
160
+ selectedCategory: string,
161
+ selectedDocumentType: string,
162
+ selectedApplicant: string,
163
+ uploadedFiles: UploadedFile[],
164
+ isSaving: boolean
165
+ ): boolean {
166
+ if (isSaving) {
167
+ return true;
168
+ }
169
+
170
+ // For button state, we only need to check if required fields are filled
171
+ // We don't need to validate if options are loaded
172
+ if (!assignmentType) {
173
+ return true;
174
+ }
175
+
176
+ if (!selectedCategory) {
177
+ return true;
178
+ }
179
+
180
+ if (!selectedDocumentType) {
181
+ return true;
182
+ }
183
+
184
+ if (uploadedFiles.length === 0) {
185
+ return true;
186
+ }
187
+
188
+ // Check if all files are uploaded
189
+ const incompleteFiles = uploadedFiles.filter(file => file.progress !== 100);
190
+ if (incompleteFiles.length > 0) {
191
+ return true;
192
+ }
193
+
194
+ // For Applicant type, check applicant selection
195
+ if (assignmentType === SHARED.APPLICANT && !selectedApplicant) {
196
+ return true;
197
+ }
198
+
199
+ return false; // Button should be enabled
200
+ }
201
+
202
+ /**
203
+ * Validates the complete payload before save
204
+ */
205
+ validatePayload(
206
+ assignmentType: 'Applicant' | 'Application' | null,
207
+ selectedCategory: string,
208
+ selectedDocumentType: string,
209
+ selectedApplicant: string,
210
+ uploadedFiles: UploadedFile[]
211
+ ): { isValid: boolean; message: string } {
212
+ // Check assignment type
213
+ if (!assignmentType) {
214
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_ASSIGNMENT_TYPE };
215
+ }
216
+
217
+ // Check category
218
+ if (!selectedCategory) {
219
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_CATEGORY };
220
+ }
221
+
222
+ // Check document type
223
+ if (!selectedDocumentType) {
224
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_DOCUMENT_TYPE };
225
+ }
226
+
227
+ // Check files
228
+ if (uploadedFiles.length === 0) {
229
+ return { isValid: false, message: SHARED.VALIDATION_UPLOAD_AT_LEAST_ONE };
230
+ }
231
+
232
+ // Check if all files are uploaded
233
+ const incompleteFiles = uploadedFiles.filter(file => file.progress !== 100);
234
+ if (incompleteFiles.length > 0) {
235
+ return { isValid: false, message: SHARED.VALIDATION_WAIT_FOR_UPLOAD };
236
+ }
237
+
238
+ // For Applicant type, check applicant selection
239
+ if (assignmentType === SHARED.APPLICANT && !selectedApplicant) {
240
+ return { isValid: false, message: SHARED.VALIDATION_SELECT_APPLICANT };
241
+ }
242
+
243
+ return { isValid: true, message: SHARED.VALIDATION_ALL_FIELDS_COMPLETED };
244
+ }
245
+
246
+ /**
247
+ * Prepares upload payload
248
+ */
249
+ prepareUploadPayload(
250
+ assignmentType: 'Applicant' | 'Application',
251
+ selectedCategory: string,
252
+ selectedDocumentType: string,
253
+ selectedApplicant: string,
254
+ uploadedFiles: UploadedFile[],
255
+ contextId: string
256
+ ): DocumentUploadPayload {
257
+ const payload: DocumentUploadPayload = {
258
+ source: assignmentType,
259
+ categoryId: selectedCategory,
260
+ documentTypeId: selectedDocumentType,
261
+ contextId,
262
+ documents: uploadedFiles.map(file => ({
263
+ fileName: file.file.name,
264
+ fileSize: file.file.size,
265
+ url: file.url,
266
+ contentType: file.contentType,
267
+ size: file.size,
268
+ uploadedFileId: file.uploadResponse?.id || file.uploadResponse?.fileName
269
+ }))
270
+ };
271
+
272
+ // For Applicant type, include the applicant ID
273
+ if (assignmentType === SHARED.APPLICANT && selectedApplicant) {
274
+ payload.applicantId = selectedApplicant;
275
+ }
276
+
277
+ return payload;
278
+ }
279
+
280
+ /**
281
+ * Saves document upload
282
+ */
283
+ saveDocumentUpload(payload: DocumentUploadPayload): Observable<any> {
284
+ return this.documentHttpService.saveDocumentUpload(payload);
285
+ }
286
+
287
+ /**
288
+ * Formats file size
289
+ */
290
+ formatFileSize(fileSize: number, config: any): string {
291
+ return this.fileFormatService.formatFileSize(fileSize, config);
292
+ }
293
+
294
+ /**
295
+ * Creates uploaded file object
296
+ */
297
+ createUploadedFile(file: File, formattedSize: string): UploadedFile {
298
+ return {
299
+ file,
300
+ formattedSize,
301
+ progress: SHARED.UPLOAD_PROGRESS_10
302
+ };
303
+ }
304
+
305
+ /**
306
+ * Resets form data to initial state
307
+ */
308
+ getInitialFormState() {
309
+ return {
310
+ selectedAssignmentType: null,
311
+ selectedApplicant: null,
312
+ selectedCategory: null,
313
+ selectedDocumentType: null,
314
+ uploadedFiles: [] as UploadedFile[],
315
+ isFormValid: false
316
+ };
317
+ }
318
+
319
+ /**
320
+ * Destroys the service
321
+ */
322
+ destroy(): void {
323
+ this.destroy$.next();
324
+ this.destroy$.complete();
325
+ }
326
+ }
@@ -0,0 +1,82 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Observable, Subject, takeUntil } from 'rxjs';
3
+ import { DocumentUploadBusinessService } from './document-upload-business.service';
4
+ import { DocumentUploadFormService } from './document-upload-form.service';
5
+ import { UserListModel } from '../models/user-list.model';
6
+ import { DocumentCategory } from '../models/document-category.model';
7
+ import { DocumentTypeModel } from '../models/document-type.model';
8
+
9
+ export interface DataLoadingState {
10
+ isLoadingApplicants: boolean;
11
+ isLoadingCategories: boolean;
12
+ isLoadingDocumentTypes: boolean;
13
+ }
14
+
15
+ @Injectable({
16
+ providedIn: 'root'
17
+ })
18
+ export class DocumentUploadDataService {
19
+ private destroy$ = new Subject<void>();
20
+
21
+ constructor(
22
+ private businessService: DocumentUploadBusinessService,
23
+ private formService: DocumentUploadFormService
24
+ ) {}
25
+
26
+ /**
27
+ * Loads applicants and handles the response
28
+ */
29
+ loadApplicants(
30
+ contextId: string,
31
+ onSuccess: (applicants: UserListModel[]) => void,
32
+ onError: (error: any) => void
33
+ ): Observable<UserListModel[]> {
34
+ if (!this.formService.validateContextId(contextId, 'Context ID is required to load applicants.')) {
35
+ return new Observable();
36
+ }
37
+ return this.businessService.loadApplicants(contextId);
38
+ }
39
+
40
+ /**
41
+ * Loads categories and handles the response
42
+ */
43
+ loadCategories(
44
+ assignmentType: string,
45
+ onSuccess: (categories: DocumentCategory[]) => void,
46
+ onError: (error: any) => void
47
+ ): Observable<DocumentCategory[]> {
48
+ if (!assignmentType) {
49
+ return new Observable();
50
+ }
51
+ return this.businessService.loadCategories(assignmentType);
52
+ }
53
+
54
+ /**
55
+ * Loads document types and handles the response
56
+ */
57
+ loadDocumentTypes(
58
+ categoryId: string,
59
+ onSuccess: (documentTypes: DocumentTypeModel[]) => void,
60
+ onError: (error: any) => void
61
+ ): Observable<DocumentTypeModel[]> {
62
+ return this.businessService.loadDocumentTypes(categoryId);
63
+ }
64
+
65
+ /**
66
+ * Handles applicants loaded successfully
67
+ */
68
+ handleApplicantsLoaded(
69
+ applicants: UserListModel[],
70
+ assignmentType: 'Applicant' | 'Application' | null
71
+ ): UserListModel[] {
72
+ return this.businessService.filterApplicants(applicants, assignmentType!);
73
+ }
74
+
75
+ /**
76
+ * Destroys the service
77
+ */
78
+ destroy(): void {
79
+ this.destroy$.next();
80
+ this.destroy$.complete();
81
+ }
82
+ }
@@ -0,0 +1,149 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { MessageService } from 'primeng/api';
3
+ import { UploadedFile } from './document-upload-business.service';
4
+ import { SHARED } from '../../../Shared/constant/SHARED';
5
+
6
+ @Injectable({
7
+ providedIn: 'root'
8
+ })
9
+ export class DocumentUploadFormService {
10
+ constructor(private messageService: MessageService) {}
11
+
12
+ /**
13
+ * Shows error message
14
+ */
15
+ showErrorMessage(summary: string, detail: string): void {
16
+ this.messageService.add({
17
+ severity: 'error',
18
+ summary,
19
+ detail
20
+ });
21
+ }
22
+
23
+ /**
24
+ * Shows warning message
25
+ */
26
+ showWarningMessage(summary: string, detail: string): void {
27
+ this.messageService.add({
28
+ severity: 'warn',
29
+ summary,
30
+ detail
31
+ });
32
+ }
33
+
34
+ /**
35
+ * Shows success message
36
+ */
37
+ showSuccessMessage(summary: string, detail: string): void {
38
+ this.messageService.add({
39
+ severity: 'success',
40
+ summary,
41
+ detail
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Helper method to validate required fields and show appropriate messages
47
+ */
48
+ private validateRequiredFieldsWithMessages(
49
+ assignmentType: 'Applicant' | 'Application' | null,
50
+ selectedApplicant: string,
51
+ selectedCategory: string,
52
+ selectedDocumentType: string,
53
+ uploadedFiles: UploadedFile[]
54
+ ): { isValid: boolean; field: string | null } {
55
+ if (assignmentType === 'Applicant' && !selectedApplicant) {
56
+ return { isValid: false, field: 'applicant' };
57
+ }
58
+
59
+ if (!selectedCategory) {
60
+ return { isValid: false, field: 'category' };
61
+ }
62
+
63
+ if (!selectedDocumentType) {
64
+ return { isValid: false, field: 'documentType' };
65
+ }
66
+
67
+ if (uploadedFiles.length === 0) {
68
+ return { isValid: false, field: 'documents' };
69
+ }
70
+
71
+ return { isValid: true, field: null };
72
+ }
73
+
74
+ /**
75
+ * Validates required fields for upload
76
+ */
77
+ validateRequiredFields(
78
+ assignmentType: 'Applicant' | 'Application' | null,
79
+ selectedApplicant: string,
80
+ selectedCategory: string,
81
+ selectedDocumentType: string,
82
+ uploadedFiles: UploadedFile[]
83
+ ): boolean {
84
+ const validation = this.validateRequiredFieldsWithMessages(
85
+ assignmentType,
86
+ selectedApplicant,
87
+ selectedCategory,
88
+ selectedDocumentType,
89
+ uploadedFiles
90
+ );
91
+
92
+ if (!validation.isValid) {
93
+ this.showValidationMessage(validation.field!);
94
+ }
95
+
96
+ return validation.isValid;
97
+ }
98
+
99
+ /**
100
+ * Shows appropriate validation message based on the field that failed
101
+ */
102
+ private showValidationMessage(field: string): void {
103
+ const messages: Record<string, { summary: string; detail: string }> = {
104
+ applicant: {
105
+ summary: SHARED.VALIDATION_NO_APPLICANT_SELECTED,
106
+ detail: SHARED.VALIDATION_NO_APPLICANT_DETAIL
107
+ },
108
+ category: {
109
+ summary: SHARED.VALIDATION_NO_CATEGORY_SELECTED,
110
+ detail: SHARED.VALIDATION_NO_CATEGORY_DETAIL
111
+ },
112
+ documentType: {
113
+ summary: SHARED.VALIDATION_NO_DOCUMENT_TYPE_SELECTED,
114
+ detail: SHARED.VALIDATION_NO_DOCUMENT_TYPE_DETAIL
115
+ },
116
+ documents: {
117
+ summary: SHARED.VALIDATION_NO_DOCUMENTS_UPLOADED,
118
+ detail: SHARED.VALIDATION_NO_DOCUMENTS_DETAIL
119
+ }
120
+ };
121
+
122
+ const message = messages[field];
123
+ if (message) {
124
+ this.showWarningMessage(message.summary, message.detail);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Validates form completeness
130
+ */
131
+ validateFormCompleteness(): boolean {
132
+ this.showWarningMessage(
133
+ SHARED.VALIDATION_FORM_INCOMPLETE,
134
+ SHARED.VALIDATION_FORM_INCOMPLETE_DETAIL
135
+ );
136
+ return false;
137
+ }
138
+
139
+ /**
140
+ * Validates context ID presence
141
+ */
142
+ validateContextId(contextId: string, message: string): boolean {
143
+ if (!contextId) {
144
+ this.showErrorMessage(SHARED.VALIDATION_MISSING_REQUIRED_DATA, message);
145
+ return false;
146
+ }
147
+ return true;
148
+ }
149
+ }
@@ -0,0 +1,99 @@
1
+ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
2
+ import { DocumentUploadService } from './document-upload.service';
3
+ import { DocumentService } from '../state/document.service';
4
+ import { DocumentStore } from '../state/document.store';
5
+ import { MessageService } from 'primeng/api';
6
+ import { of, throwError } from 'rxjs';
7
+ import { SHARED } from '../../../Shared/constant/SHARED';
8
+
9
+ describe('DocumentUploadService', () => {
10
+ let service: DocumentUploadService;
11
+ let mockDocumentService: jasmine.SpyObj<DocumentService>;
12
+ let mockDocumentStore: jasmine.SpyObj<DocumentStore>;
13
+ let mockMessageService: jasmine.SpyObj<MessageService>;
14
+
15
+ beforeEach(() => {
16
+ mockDocumentService = jasmine.createSpyObj('DocumentService', ['create']);
17
+ mockDocumentStore = jasmine.createSpyObj('DocumentStore', ['setUploadedDocumentFiles', 'setMessage']);
18
+ mockMessageService = jasmine.createSpyObj('MessageService', ['add']);
19
+
20
+ TestBed.configureTestingModule({
21
+ providers: [
22
+ DocumentUploadService,
23
+ { provide: DocumentService, useValue: mockDocumentService },
24
+ { provide: DocumentStore, useValue: mockDocumentStore },
25
+ { provide: MessageService, useValue: mockMessageService }
26
+ ]
27
+ });
28
+
29
+ service = TestBed.inject(DocumentUploadService);
30
+ });
31
+
32
+ it('should be created', () => {
33
+ expect(service).toBeTruthy();
34
+ });
35
+
36
+ it('should set uploadedFile, contextId, docName, and docTypeId when getUploadFileData is called', () => {
37
+ const mockFile = new File(['test content'], 'test.pdf', { type: 'application/pdf' });
38
+ const contextId = '1234';
39
+
40
+ service.getUploadFileData(mockFile, contextId);
41
+
42
+ expect(service.uploadedFile).toBe(mockFile);
43
+ expect(service.contextId).toBe(contextId);
44
+ });
45
+
46
+ it('should set document name and type when getDocumentNameAndType is called', () => {
47
+ const documentName = 'Test Document';
48
+ const documentTypeId = '5678';
49
+
50
+ service.getDocumentNameAndType(documentTypeId);
51
+
52
+ expect(service.docName).toBe(SHARED.EMPTY);
53
+ expect(service.docTypeId).toBe(documentTypeId);
54
+ });
55
+
56
+
57
+
58
+ it('should handle null formData in handleTemplatedUpload', () => {
59
+ const mockFile = new File(['test content'], 'test.pdf', { type: 'application/pdf' });
60
+ const contextId = '1234';
61
+ const documentName = 'Test Document';
62
+ const documentTypeId = '5678';
63
+ service.getUploadFileData(mockFile, contextId);
64
+ service.getDocumentNameAndType(documentTypeId);
65
+ spyOn(service, 'handleCreateFormData').and.returnValue(null);
66
+ service.handleTemplatedUpload();
67
+ expect(mockMessageService.add).toHaveBeenCalledWith({
68
+ severity: 'error',
69
+ summary: 'Form Data Missing',
70
+ detail: 'Required form data is missing. Please ensure the document and all required fields are provided.'
71
+ });
72
+ });
73
+
74
+
75
+ it('should return null from handleCreateFormData if data is incomplete', () => {
76
+ const formData = service.handleCreateFormData();
77
+ expect(formData).toBeNull();
78
+ });
79
+
80
+ it('should call documentService.create and set uploaded files when handleTemplatedUpload is called', () => {
81
+ const mockFile = new File(['test content'], 'test.pdf', { type: 'application/pdf' });
82
+ const contextId = '1234';
83
+ const documentName = 'Test Document';
84
+ const documentTypeId = '5678';
85
+ const formData = new FormData();
86
+ formData.append(SHARED.FILE, mockFile);
87
+
88
+ service.getUploadFileData(mockFile, contextId);
89
+ service.getDocumentNameAndType(documentTypeId);
90
+
91
+ mockDocumentService.create.and.returnValue(of({ fileId: 'abcd1234' }));
92
+
93
+ service.handleTemplatedUpload();
94
+
95
+ expect(mockDocumentService.create).toHaveBeenCalledWith(formData);
96
+ expect(mockDocumentStore.setUploadedDocumentFiles).toHaveBeenCalled();
97
+ });
98
+
99
+ });