@codex-ts/core-lib 1.0.0

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 (76) hide show
  1. package/dist/core-lib/fesm2022/core-lib.mjs +2349 -0
  2. package/dist/core-lib/fesm2022/core-lib.mjs.map +1 -0
  3. package/dist/core-lib/index.d.ts +29 -0
  4. package/dist/core-lib/lib/components/base-form.component.d.ts +62 -0
  5. package/dist/core-lib/lib/components/base-list-page.component.d.ts +132 -0
  6. package/dist/core-lib/lib/components/base-page.component.d.ts +25 -0
  7. package/dist/core-lib/lib/components/base-tabbed-form.component.d.ts +54 -0
  8. package/dist/core-lib/lib/components/formly/core-formly.module.d.ts +7 -0
  9. package/dist/core-lib/lib/components/formly/form-field.wrapper.d.ts +21 -0
  10. package/dist/core-lib/lib/components/formly/formly.constants.d.ts +13 -0
  11. package/dist/core-lib/lib/components/formly/types/checkbox.type.d.ts +12 -0
  12. package/dist/core-lib/lib/components/formly/types/date.type.d.ts +20 -0
  13. package/dist/core-lib/lib/components/formly/types/multiselect.type.d.ts +26 -0
  14. package/dist/core-lib/lib/components/formly/types/numeric-input.type.d.ts +17 -0
  15. package/dist/core-lib/lib/components/formly/types/radio.type.d.ts +13 -0
  16. package/dist/core-lib/lib/components/formly/types/select.type.d.ts +25 -0
  17. package/dist/core-lib/lib/components/formly/types/text-input.type.d.ts +12 -0
  18. package/dist/core-lib/lib/components/formly/types/textarea.type.d.ts +14 -0
  19. package/dist/core-lib/lib/constants/app.constants.d.ts +13 -0
  20. package/dist/core-lib/lib/constants/app.messages.d.ts +36 -0
  21. package/dist/core-lib/lib/enums/component-context.enum.d.ts +6 -0
  22. package/dist/core-lib/lib/enums/tabbed-form-type.enum.d.ts +4 -0
  23. package/dist/core-lib/lib/models/pagination/filter-criteria.interface.d.ts +9 -0
  24. package/dist/core-lib/lib/models/pagination/page-request.interface.d.ts +10 -0
  25. package/dist/core-lib/lib/models/pagination/page.interface.d.ts +9 -0
  26. package/dist/core-lib/lib/models/pagination/sort-criteria.interface.d.ts +4 -0
  27. package/dist/core-lib/lib/pipes/indian-date.pipe.d.ts +12 -0
  28. package/dist/core-lib/lib/services/base-crud.service.d.ts +36 -0
  29. package/dist/core-lib/lib/services/entity-registry.service.d.ts +26 -0
  30. package/dist/core-lib/lib/services/entity.service.d.ts +9 -0
  31. package/dist/core-lib/lib/services/enum-registry.service.d.ts +41 -0
  32. package/dist/core-lib/lib/services/formly-config.service.d.ts +11 -0
  33. package/dist/core-lib/lib/services/http-utility.service.d.ts +130 -0
  34. package/dist/core-lib/lib/services/notification.service.d.ts +13 -0
  35. package/dist/core-lib/lib/services/reference-data-provider.service.d.ts +8 -0
  36. package/dist/core-lib/lib/services/utils.service.d.ts +72 -0
  37. package/ng-package.json +7 -0
  38. package/package.json +63 -0
  39. package/src/index.ts +44 -0
  40. package/src/lib/components/base-form.component.ts +328 -0
  41. package/src/lib/components/base-list-page.component.ts +327 -0
  42. package/src/lib/components/base-page.component.ts +33 -0
  43. package/src/lib/components/base-tabbed-form.component.ts +345 -0
  44. package/src/lib/components/formly/core-formly.module.ts +34 -0
  45. package/src/lib/components/formly/field.interface.ts +15 -0
  46. package/src/lib/components/formly/form-field.wrapper.ts +94 -0
  47. package/src/lib/components/formly/formly.constants.ts +14 -0
  48. package/src/lib/components/formly/primeng-formly.module.ts +77 -0
  49. package/src/lib/components/formly/types/checkbox.type.ts +43 -0
  50. package/src/lib/components/formly/types/date.type.ts +88 -0
  51. package/src/lib/components/formly/types/multiselect.type.ts +61 -0
  52. package/src/lib/components/formly/types/numeric-input.type.ts +45 -0
  53. package/src/lib/components/formly/types/radio.type.ts +47 -0
  54. package/src/lib/components/formly/types/select.type.ts +54 -0
  55. package/src/lib/components/formly/types/text-input.type.ts +33 -0
  56. package/src/lib/components/formly/types/textarea.type.ts +37 -0
  57. package/src/lib/constants/app.constants.ts +15 -0
  58. package/src/lib/constants/app.messages.ts +36 -0
  59. package/src/lib/enums/component-context.enum.ts +6 -0
  60. package/src/lib/enums/tabbed-form-type.enum.ts +4 -0
  61. package/src/lib/models/pagination/filter-criteria.interface.ts +19 -0
  62. package/src/lib/models/pagination/page-request.interface.ts +13 -0
  63. package/src/lib/models/pagination/page.interface.ts +9 -0
  64. package/src/lib/models/pagination/sort-criteria.interface.ts +4 -0
  65. package/src/lib/pipes/indian-date.pipe.ts +46 -0
  66. package/src/lib/services/base-crud.service.ts +81 -0
  67. package/src/lib/services/entity-registry.service.ts +51 -0
  68. package/src/lib/services/entity.service.ts +10 -0
  69. package/src/lib/services/enum-registry.service.ts +66 -0
  70. package/src/lib/services/formly-config.service.ts +50 -0
  71. package/src/lib/services/http-utility.service.example.ts +253 -0
  72. package/src/lib/services/http-utility.service.md +175 -0
  73. package/src/lib/services/http-utility.service.ts +389 -0
  74. package/src/lib/services/notification.service.ts +35 -0
  75. package/src/lib/services/reference-data-provider.service.ts +28 -0
  76. package/src/lib/services/utils.service.ts +154 -0
@@ -0,0 +1,2349 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, Directive, Input, Component, ViewChild, Pipe, NgModule } from '@angular/core';
3
+ import { BehaviorSubject, finalize, Observable, forkJoin, throwError, map, take, of, isObservable } from 'rxjs';
4
+ import * as i1 from 'primeng/api';
5
+ import * as i1$1 from '@angular/common/http';
6
+ import { HttpParams } from '@angular/common/http';
7
+ import { retry, timeout, catchError, finalize as finalize$1 } from 'rxjs/operators';
8
+ import * as i1$4 from '@angular/forms';
9
+ import { FormGroup, ReactiveFormsModule } from '@angular/forms';
10
+ import * as i1$2 from '@angular/router';
11
+ import * as i1$3 from '@angular/common';
12
+ import { CommonModule, formatDate } from '@angular/common';
13
+ import * as i2 from '@ngx-formly/core';
14
+ import { FieldType, FormlyModule, FieldWrapper } from '@ngx-formly/core';
15
+ import * as i3 from 'primeng/inputtext';
16
+ import { InputTextModule } from 'primeng/inputtext';
17
+ import * as i4 from 'primeng/select';
18
+ import { SelectModule } from 'primeng/select';
19
+ import * as i4$1 from 'primeng/radiobutton';
20
+ import { RadioButtonModule } from 'primeng/radiobutton';
21
+ import * as i3$1 from 'primeng/inputnumber';
22
+ import { InputNumberModule } from 'primeng/inputnumber';
23
+ import * as i4$2 from 'primeng/multiselect';
24
+ import { MultiSelectModule } from 'primeng/multiselect';
25
+ import * as i3$2 from 'primeng/datepicker';
26
+ import { DatePickerModule } from 'primeng/datepicker';
27
+ import * as i3$3 from 'primeng/checkbox';
28
+ import { CheckboxModule } from 'primeng/checkbox';
29
+ import * as i3$4 from 'primeng/inputtextarea';
30
+ import { Textarea } from 'primeng/inputtextarea';
31
+ import * as i2$1 from 'primeng/tooltip';
32
+ import { TooltipModule } from 'primeng/tooltip';
33
+
34
+ /**
35
+ * A utility service that provides common reusable functionality
36
+ * such as UUID validation and error message display
37
+ */
38
+ class UtilsService {
39
+ /**
40
+ * Validates if a string is a valid UUID
41
+ * @param uuid The string to validate
42
+ * @returns boolean indicating if the string is a valid UUID
43
+ */
44
+ isValidUUID(uuid) {
45
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
46
+ return uuidRegex.test(uuid);
47
+ }
48
+ /**
49
+ * Shows an error message using PrimeNG's MessageService
50
+ * @param message The error message to display
51
+ * @param messageService The MessageService instance to use
52
+ */
53
+ showError(message, messageService) {
54
+ if (messageService) {
55
+ messageService.add({
56
+ severity: 'error',
57
+ summary: 'Error',
58
+ detail: message,
59
+ life: 3000
60
+ });
61
+ }
62
+ }
63
+ /**
64
+ * Shows a success message using PrimeNG's MessageService
65
+ * @param message The success message to display
66
+ * @param messageService The MessageService instance to use
67
+ */
68
+ showSuccess(message, messageService) {
69
+ if (messageService) {
70
+ messageService.add({
71
+ severity: 'success',
72
+ summary: 'Success',
73
+ detail: message,
74
+ life: 3000
75
+ });
76
+ }
77
+ }
78
+ /**
79
+ * Gets the display value for an enum key or array of enum keys
80
+ * @param enumType The enum type
81
+ * @param key The enum key or array of enum keys
82
+ * @returns The display value for the enum key or comma-separated list of display values for array of keys
83
+ */
84
+ getEnumValue(enumType, key) {
85
+ if (!key)
86
+ return '';
87
+ if (Array.isArray(key)) {
88
+ // Handle array of keys - map each to its display value and join with comma
89
+ return key.map(k => enumType[k] || k).join(', ');
90
+ }
91
+ // Handle single key
92
+ return enumType[key] || key;
93
+ }
94
+ /**
95
+ * Gets all values from an enum type for use in formly select fields
96
+ * @param enumType The enum type to get values from
97
+ * @returns Array of {label, value} pairs for formly select options
98
+ */
99
+ getEnumValues(enumType) {
100
+ return Object.entries(enumType)
101
+ .filter(([key]) => isNaN(Number(key))) // Filter out reverse mappings
102
+ .map(([key, value]) => ({
103
+ value: key, // enum key as the value
104
+ label: value // enum value as the label
105
+ }));
106
+ }
107
+ /**
108
+ * Converts a camelCase string to Title Case with spaces
109
+ * @param camelCase The camelCase string to convert
110
+ * @returns The Title Case string
111
+ */
112
+ camelCaseToTitleCase(camelCase) {
113
+ if (!camelCase)
114
+ return '';
115
+ const spacedString = camelCase.replace(/([a-z])([A-Z])/g, '$1 $2');
116
+ return spacedString.charAt(0).toUpperCase() + spacedString.slice(1);
117
+ }
118
+ /**
119
+ * Converts a string to kebab-case
120
+ * @param input The string to convert
121
+ * @returns The kebab-case string
122
+ */
123
+ toKebabCase(input) {
124
+ return input
125
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
126
+ .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2')
127
+ .toLowerCase();
128
+ }
129
+ /**
130
+ * Converts a string to camelCase.
131
+ * Example: "loan-application" becomes "loanApplication"
132
+ * @param input The string to convert
133
+ * @returns The camelCase string
134
+ */
135
+ toCamelCase(input) {
136
+ if (!input)
137
+ return '';
138
+ // Split by non-alphanumeric chars
139
+ const words = input.split(/[^a-zA-Z0-9]/);
140
+ const result = [words[0].toLowerCase()];
141
+ // Capitalize first letter of remaining words
142
+ for (let i = 1; i < words.length; i++) {
143
+ const word = words[i];
144
+ if (word) {
145
+ result.push(word.charAt(0).toUpperCase() + word.substring(1).toLowerCase());
146
+ }
147
+ }
148
+ return result.join('');
149
+ }
150
+ /**
151
+ * Removes double forward slashes from an endpoint string while preserving the protocol
152
+ * e.g. "http://localhost:8080//api//v1//users" -> "http://localhost:8080/api/v1/users"
153
+ * @param endpoint The endpoint string to clean
154
+ * @returns The cleaned endpoint string without double slashes
155
+ */
156
+ removeDoubleSlashes(endpoint) {
157
+ if (!endpoint)
158
+ return '';
159
+ // Split the URL into protocol and the rest to preserve protocol slashes
160
+ const [protocol, ...rest] = endpoint.split('://');
161
+ if (!rest.length) {
162
+ // If no protocol is present, just clean the entire string
163
+ return endpoint.replace(/\/+/g, '/');
164
+ }
165
+ // Clean the path part (after protocol) and reconstruct the URL
166
+ const cleanPath = rest.join('://').replace(/\/+/g, '/');
167
+ return `${protocol}://${cleanPath}`;
168
+ }
169
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
170
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UtilsService, providedIn: 'root' });
171
+ }
172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: UtilsService, decorators: [{
173
+ type: Injectable,
174
+ args: [{
175
+ providedIn: 'root'
176
+ }]
177
+ }] });
178
+
179
+ class EnumRegistryService {
180
+ utilsService;
181
+ enumMap = new Map();
182
+ constructor(utilsService) {
183
+ this.utilsService = utilsService;
184
+ }
185
+ /**
186
+ * Initialize global enums
187
+ */
188
+ static registerGlobalEnums(enums) {
189
+ return {
190
+ provide: EnumRegistryService,
191
+ useFactory: (utilsService) => {
192
+ const service = new EnumRegistryService(utilsService);
193
+ Object.entries(enums).forEach(([name, enumType]) => {
194
+ service.register(name, enumType);
195
+ });
196
+ return service;
197
+ },
198
+ deps: [UtilsService]
199
+ };
200
+ }
201
+ /**
202
+ * Register an enum type with the service
203
+ * @param name Name to register the enum under
204
+ * @param enumType The enum type to register
205
+ */
206
+ register(name, enumType) {
207
+ this.enumMap.set(name, enumType);
208
+ }
209
+ /**
210
+ * Get formly-compatible options array for a registered enum
211
+ * @param name Name of the registered enum
212
+ * @returns Array of {label, value} pairs suitable for formly select fields
213
+ */
214
+ getEnumValues(name) {
215
+ const enumType = this.enumMap.get(name);
216
+ if (!enumType) {
217
+ console.warn(`Enum type "${name}" not found in registry`);
218
+ return [];
219
+ }
220
+ return this.utilsService.getEnumValues(enumType);
221
+ }
222
+ /**
223
+ * Check if an enum type is registered
224
+ * @param name Name of the enum to check
225
+ */
226
+ hasEnum(name) {
227
+ return this.enumMap.has(name);
228
+ }
229
+ /**
230
+ * Clear all registered enums
231
+ */
232
+ clear() {
233
+ this.enumMap.clear();
234
+ }
235
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EnumRegistryService, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable });
236
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EnumRegistryService, providedIn: 'root' });
237
+ }
238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EnumRegistryService, decorators: [{
239
+ type: Injectable,
240
+ args: [{
241
+ providedIn: 'root'
242
+ }]
243
+ }], ctorParameters: () => [{ type: UtilsService }] });
244
+
245
+ class FormlyConfigService {
246
+ enumRegistry;
247
+ constructor(enumRegistry) {
248
+ this.enumRegistry = enumRegistry;
249
+ }
250
+ getFormConfig(fields, mode, dynamicOptions) {
251
+ const commonConfig = {
252
+ props: {
253
+ disabled: mode === 'view'
254
+ }
255
+ };
256
+ return fields.map((field) => {
257
+ // Apply dynamic options from child component
258
+ if (dynamicOptions && field.key && typeof field.key === 'string') {
259
+ const fieldOptions = dynamicOptions[field.key];
260
+ if (fieldOptions) {
261
+ field.props = {
262
+ ...field.props,
263
+ ...fieldOptions
264
+ };
265
+ }
266
+ }
267
+ // Handle field groups recursively
268
+ if (field.fieldGroup) {
269
+ field.fieldGroup = this.getFormConfig(field.fieldGroup, mode, dynamicOptions);
270
+ }
271
+ return {
272
+ ...field,
273
+ ...commonConfig,
274
+ props: {
275
+ ...field.props,
276
+ ...commonConfig.props
277
+ }
278
+ };
279
+ });
280
+ }
281
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormlyConfigService, deps: [{ token: EnumRegistryService }], target: i0.ɵɵFactoryTarget.Injectable });
282
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormlyConfigService, providedIn: 'root' });
283
+ }
284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormlyConfigService, decorators: [{
285
+ type: Injectable,
286
+ args: [{
287
+ providedIn: 'root'
288
+ }]
289
+ }], ctorParameters: () => [{ type: EnumRegistryService }] });
290
+
291
+ class NotificationService {
292
+ messageService;
293
+ messageSubject = new BehaviorSubject(null);
294
+ message$ = this.messageSubject.asObservable();
295
+ constructor(messageService) {
296
+ this.messageService = messageService;
297
+ }
298
+ showSuccess(message) {
299
+ const msgObj = {
300
+ severity: 'success',
301
+ summary: 'Success',
302
+ detail: message,
303
+ life: 3000
304
+ };
305
+ this.messageSubject.next(msgObj);
306
+ }
307
+ showError(message) {
308
+ const msgObj = {
309
+ severity: 'error',
310
+ summary: 'Error',
311
+ detail: message,
312
+ life: 3000
313
+ };
314
+ this.messageSubject.next(msgObj);
315
+ }
316
+ clearMessage() {
317
+ this.messageSubject.next(null);
318
+ }
319
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NotificationService, deps: [{ token: i1.MessageService }], target: i0.ɵɵFactoryTarget.Injectable });
320
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NotificationService });
321
+ }
322
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NotificationService, decorators: [{
323
+ type: Injectable
324
+ }], ctorParameters: () => [{ type: i1.MessageService }] });
325
+
326
+ /**
327
+ * A general-purpose HTTP utility service that provides enhanced HTTP operations
328
+ * beyond the standard Angular HttpClient. This service includes features such as:
329
+ * - Loading state management
330
+ * - Standardized error handling
331
+ * - Request timeouts and retries
332
+ * - File upload capabilities
333
+ * - Batch request handling
334
+ */
335
+ class HttpUtilityService {
336
+ http;
337
+ messageService;
338
+ loading = new BehaviorSubject(false);
339
+ loading$ = this.loading.asObservable();
340
+ constructor(http, messageService) {
341
+ this.http = http;
342
+ this.messageService = messageService;
343
+ }
344
+ /**
345
+ * Perform a GET request with enhanced options
346
+ * @param url The endpoint URL
347
+ * @param options Additional request options
348
+ * @returns An observable of the response
349
+ */
350
+ get(url, options) {
351
+ this.loading.next(true);
352
+ let request$ = this.http.get(url, {
353
+ params: options?.params,
354
+ headers: options?.headers,
355
+ responseType: options?.responseType,
356
+ withCredentials: options?.withCredentials
357
+ });
358
+ if (options?.retries) {
359
+ request$ = request$.pipe(retry(options.retries));
360
+ }
361
+ if (options?.timeoutMs) {
362
+ request$ = request$.pipe(timeout(options.timeoutMs));
363
+ }
364
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
365
+ }
366
+ /**
367
+ * Perform a POST request with enhanced options
368
+ * @param url The endpoint URL
369
+ * @param body The request payload
370
+ * @param options Additional request options
371
+ * @returns An observable of the response
372
+ */
373
+ post(url, body, options) {
374
+ this.loading.next(true);
375
+ let request$ = this.http.post(url, body, {
376
+ params: options?.params,
377
+ headers: options?.headers,
378
+ responseType: options?.responseType,
379
+ withCredentials: options?.withCredentials
380
+ });
381
+ if (options?.retries) {
382
+ request$ = request$.pipe(retry(options.retries));
383
+ }
384
+ if (options?.timeoutMs) {
385
+ request$ = request$.pipe(timeout(options.timeoutMs));
386
+ }
387
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
388
+ }
389
+ /**
390
+ * Perform a PUT request with enhanced options
391
+ * @param url The endpoint URL
392
+ * @param body The request payload
393
+ * @param options Additional request options
394
+ * @returns An observable of the response
395
+ */
396
+ put(url, body, options) {
397
+ this.loading.next(true);
398
+ let request$ = this.http.put(url, body, {
399
+ params: options?.params,
400
+ headers: options?.headers,
401
+ responseType: options?.responseType,
402
+ withCredentials: options?.withCredentials
403
+ });
404
+ if (options?.retries) {
405
+ request$ = request$.pipe(retry(options.retries));
406
+ }
407
+ if (options?.timeoutMs) {
408
+ request$ = request$.pipe(timeout(options.timeoutMs));
409
+ }
410
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
411
+ }
412
+ /**
413
+ * Perform a DELETE request with enhanced options
414
+ * @param url The endpoint URL
415
+ * @param options Additional request options
416
+ * @returns An observable of the response
417
+ */
418
+ delete(url, options) {
419
+ this.loading.next(true);
420
+ let request$ = this.http.delete(url, {
421
+ params: options?.params,
422
+ headers: options?.headers,
423
+ responseType: options?.responseType,
424
+ withCredentials: options?.withCredentials
425
+ });
426
+ if (options?.retries) {
427
+ request$ = request$.pipe(retry(options.retries));
428
+ }
429
+ if (options?.timeoutMs) {
430
+ request$ = request$.pipe(timeout(options.timeoutMs));
431
+ }
432
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
433
+ }
434
+ /**
435
+ * Upload a file with optional additional data
436
+ * @param url The upload endpoint URL
437
+ * @param file The file to upload
438
+ * @param additionalData Additional form data to include
439
+ * @param options Additional request options
440
+ * @returns An observable of the response
441
+ */
442
+ uploadFile(url, file, additionalData, options) {
443
+ this.loading.next(true);
444
+ const formData = new FormData();
445
+ formData.append('file', file, file.name);
446
+ if (additionalData) {
447
+ Object.keys(additionalData).forEach(key => {
448
+ formData.append(key, additionalData[key]);
449
+ });
450
+ }
451
+ let httpOptions = {
452
+ headers: options?.headers,
453
+ withCredentials: options?.withCredentials
454
+ };
455
+ // If progress tracking is requested
456
+ if (options?.onProgress) {
457
+ httpOptions.reportProgress = true;
458
+ httpOptions.observe = 'events';
459
+ }
460
+ // Create the request
461
+ let request$ = this.http.post(url, formData, httpOptions);
462
+ // Add retries if specified
463
+ if (options?.retries) {
464
+ request$ = request$.pipe(retry(options.retries));
465
+ }
466
+ // Add timeout if specified
467
+ if (options?.timeoutMs) {
468
+ request$ = request$.pipe(timeout(options.timeoutMs));
469
+ }
470
+ // Track progress if a callback is provided
471
+ if (options?.onProgress) {
472
+ return new Observable(observer => {
473
+ request$.subscribe({
474
+ next: (event) => {
475
+ if (event.type === 1 && event.total) { // HttpEventType.UploadProgress
476
+ const percentDone = Math.round(100 * event.loaded / event.total);
477
+ options.onProgress(percentDone);
478
+ }
479
+ else if (event.type === 4) { // HttpEventType.Response
480
+ observer.next(event.body);
481
+ observer.complete();
482
+ }
483
+ },
484
+ error: (error) => {
485
+ observer.error(this.handleError(error));
486
+ this.loading.next(false);
487
+ },
488
+ complete: () => {
489
+ this.loading.next(false);
490
+ }
491
+ });
492
+ });
493
+ }
494
+ // Standard request without progress tracking
495
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
496
+ }
497
+ /**
498
+ * Execute multiple HTTP requests in parallel
499
+ * @param requests Array of HTTP request observables
500
+ * @returns An observable that emits when all requests complete
501
+ */
502
+ batchRequests(requests) {
503
+ this.loading.next(true);
504
+ return forkJoin(requests).pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
505
+ }
506
+ /**
507
+ * Download a file from the server
508
+ * @param url The file URL
509
+ * @param filename Optional filename to save as
510
+ * @param options Additional request options
511
+ */
512
+ downloadFile(url, filename, options) {
513
+ this.loading.next(true);
514
+ let request$ = this.http.get(url, {
515
+ params: options?.params,
516
+ headers: options?.headers,
517
+ responseType: 'blob',
518
+ withCredentials: options?.withCredentials
519
+ });
520
+ if (options?.timeoutMs) {
521
+ request$ = request$.pipe(timeout(options.timeoutMs));
522
+ }
523
+ return request$.pipe(catchError(this.handleError.bind(this)), finalize(() => this.loading.next(false)));
524
+ }
525
+ /**
526
+ * Create parameter string from an object
527
+ * @param params Object containing parameters
528
+ * @returns HttpParams object
529
+ */
530
+ createParams(params) {
531
+ let httpParams = new HttpParams();
532
+ Object.keys(params).forEach(key => {
533
+ const value = params[key];
534
+ if (value !== undefined && value !== null) {
535
+ httpParams = httpParams.append(key, value.toString());
536
+ }
537
+ });
538
+ return httpParams;
539
+ }
540
+ /**
541
+ * Standardized error handler for HTTP requests
542
+ * @param error The HTTP error
543
+ * @returns An observable that errors with the processed error object
544
+ */
545
+ handleError(error) {
546
+ console.error('An HTTP error occurred:', error);
547
+ let errorMessage = 'An error occurred';
548
+ let errorCode;
549
+ if (error.error instanceof ErrorEvent) {
550
+ // Client-side error
551
+ errorMessage = error.error.message;
552
+ }
553
+ else {
554
+ // Server-side error
555
+ errorCode = error.status.toString();
556
+ switch (error.status) {
557
+ case 400:
558
+ errorMessage = error.error?.message || 'Bad request';
559
+ break;
560
+ case 401:
561
+ errorMessage = 'Unauthorized';
562
+ break;
563
+ case 403:
564
+ errorMessage = 'Access denied';
565
+ break;
566
+ case 404:
567
+ errorMessage = 'Resource not found';
568
+ break;
569
+ case 408:
570
+ errorMessage = 'Request timeout';
571
+ break;
572
+ case 500:
573
+ errorMessage = 'Server error';
574
+ break;
575
+ case 503:
576
+ errorMessage = 'Service unavailable';
577
+ break;
578
+ default:
579
+ errorMessage = error.error?.message || `Error ${error.status}`;
580
+ break;
581
+ }
582
+ }
583
+ this.showError(errorMessage);
584
+ return throwError(() => ({
585
+ error,
586
+ message: errorMessage,
587
+ code: errorCode
588
+ }));
589
+ }
590
+ /**
591
+ * Display an error message using the message service
592
+ * @param message Error message to display
593
+ */
594
+ showError(message) {
595
+ if (this.messageService) {
596
+ this.messageService.add({
597
+ severity: 'error',
598
+ summary: 'Error',
599
+ detail: message,
600
+ life: 3000
601
+ });
602
+ }
603
+ }
604
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HttpUtilityService, deps: [{ token: i1$1.HttpClient }, { token: i1.MessageService }], target: i0.ɵɵFactoryTarget.Injectable });
605
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HttpUtilityService, providedIn: 'root' });
606
+ }
607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: HttpUtilityService, decorators: [{
608
+ type: Injectable,
609
+ args: [{
610
+ providedIn: 'root'
611
+ }]
612
+ }], ctorParameters: () => [{ type: i1$1.HttpClient }, { type: i1.MessageService }] });
613
+
614
+ class ReferenceDataProviderService {
615
+ endpoints = {};
616
+ // Method to set/update endpoints
617
+ setEndpoints(endpoints) {
618
+ this.endpoints = { ...this.endpoints, ...endpoints };
619
+ }
620
+ getReferenceEndpoint(entityName) {
621
+ console.log('getReferenceEndpoint', entityName, this.endpoints);
622
+ let endpoint = this.endpoints[entityName];
623
+ if (endpoint != null && endpoint.length > 0) {
624
+ if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
625
+ return endpoint; // Absolute URL
626
+ }
627
+ else {
628
+ // Relative URL, assume it's within the application's base context
629
+ return endpoint;
630
+ }
631
+ }
632
+ return null;
633
+ }
634
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReferenceDataProviderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
635
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReferenceDataProviderService, providedIn: 'root' });
636
+ }
637
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: ReferenceDataProviderService, decorators: [{
638
+ type: Injectable,
639
+ args: [{
640
+ providedIn: 'root'
641
+ }]
642
+ }] });
643
+
644
+ class EntityRegistryService {
645
+ httpUtility;
646
+ dataProvider;
647
+ constructor(httpUtility, dataProvider) {
648
+ this.httpUtility = httpUtility;
649
+ this.dataProvider = dataProvider;
650
+ }
651
+ /**
652
+ * Gets reference options for an entity, suitable for select/dropdown components
653
+ * @param entityName The name of the entity (e.g., 'customers', 'departments')
654
+ * @returns Observable of options array with label/value pairs
655
+ */
656
+ getEntityOptions(entityName) {
657
+ console.log('getEntityOptions', entityName);
658
+ const url = this.dataProvider.getReferenceEndpoint(entityName);
659
+ if (!url) {
660
+ console.warn(`No endpoint configured for entity: ${entityName}`);
661
+ return new Observable(subscriber => {
662
+ subscriber.next([]);
663
+ subscriber.complete();
664
+ });
665
+ }
666
+ return this.httpUtility.get(url, {
667
+ retries: 1,
668
+ timeoutMs: 10000,
669
+ }).pipe(map((items) => items?.map((item) => ({
670
+ label: item.displayLabel,
671
+ value: item.key,
672
+ data: item.data,
673
+ })) || []));
674
+ }
675
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EntityRegistryService, deps: [{ token: HttpUtilityService }, { token: ReferenceDataProviderService }], target: i0.ɵɵFactoryTarget.Injectable });
676
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EntityRegistryService, providedIn: 'root' });
677
+ }
678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: EntityRegistryService, decorators: [{
679
+ type: Injectable,
680
+ args: [{
681
+ providedIn: 'root'
682
+ }]
683
+ }], ctorParameters: () => [{ type: HttpUtilityService }, { type: ReferenceDataProviderService }] });
684
+
685
+ class BaseCrudService {
686
+ httpUtility;
687
+ utilsService;
688
+ resourcePath;
689
+ backendBaseUrl;
690
+ messageService;
691
+ // Use the loading state from HttpUtilityService
692
+ get loading$() {
693
+ return this.httpUtility.loading$;
694
+ }
695
+ apiUrl;
696
+ /**
697
+ * Creates an instance of BaseCrudService.
698
+ * @param httpUtility - Service for making HTTP requests
699
+ * @param utilsService - Utility service for common operations
700
+ * @param resourcePath - API resource path (e.g., 'customers', 'products')
701
+ * @param backendBaseUrl - Base URL for the backend API
702
+ * @param messageService - Optional service for showing messages
703
+ */
704
+ constructor(httpUtility, utilsService, resourcePath, backendBaseUrl, messageService) {
705
+ this.httpUtility = httpUtility;
706
+ this.utilsService = utilsService;
707
+ this.resourcePath = resourcePath;
708
+ this.backendBaseUrl = backendBaseUrl;
709
+ this.messageService = messageService;
710
+ this.apiUrl = this.joinUrls(backendBaseUrl, resourcePath);
711
+ }
712
+ /**
713
+ * Joins URL parts ensuring no double slashes
714
+ */
715
+ joinUrls(...parts) {
716
+ return parts.map(part => part.replace(/^\/+|\/+$/g, '')).join('/');
717
+ }
718
+ getAll(pageRequest) {
719
+ if (pageRequest) {
720
+ return this.httpUtility.post(`${this.apiUrl}/page`, pageRequest);
721
+ }
722
+ else {
723
+ return this.httpUtility.get(this.apiUrl);
724
+ }
725
+ }
726
+ getById(uuid) {
727
+ if (!this.utilsService.isValidUUID(uuid)) {
728
+ this.utilsService.showError('Invalid UUID format', this.messageService);
729
+ return throwError(() => new Error('Invalid UUID format'));
730
+ }
731
+ return this.httpUtility.get(`${this.apiUrl}/${uuid}`);
732
+ }
733
+ create(entity) {
734
+ return this.httpUtility.post(this.apiUrl, entity);
735
+ }
736
+ update(uuid, entity) {
737
+ if (!this.utilsService.isValidUUID(uuid)) {
738
+ this.utilsService.showError('Invalid UUID format', this.messageService);
739
+ return throwError(() => new Error('Invalid UUID format'));
740
+ }
741
+ return this.httpUtility.put(`${this.apiUrl}/${uuid}`, entity);
742
+ }
743
+ delete(uuid) {
744
+ if (!this.utilsService.isValidUUID(uuid)) {
745
+ this.utilsService.showError('Invalid UUID format', this.messageService);
746
+ return throwError(() => new Error('Invalid UUID format'));
747
+ }
748
+ return this.httpUtility.delete(`${this.apiUrl}/${uuid}`);
749
+ }
750
+ }
751
+
752
+ var ComponentContext;
753
+ (function (ComponentContext) {
754
+ ComponentContext["STANDALONE"] = "STANDALONE";
755
+ ComponentContext["TABBED"] = "TABBED";
756
+ ComponentContext["MODAL"] = "MODAL";
757
+ ComponentContext["EMBEDDED"] = "EMBEDDED";
758
+ })(ComponentContext || (ComponentContext = {}));
759
+
760
+ var TabbedFormType;
761
+ (function (TabbedFormType) {
762
+ TabbedFormType["STANDARD"] = "STANDARD";
763
+ TabbedFormType["LIST"] = "LIST";
764
+ })(TabbedFormType || (TabbedFormType = {}));
765
+
766
+ /**
767
+ * Base component for all page components in the application.
768
+ * Provides common functionality like loading state and message display.
769
+ */
770
+ class BasePageComponent {
771
+ utilsService;
772
+ notificationService;
773
+ loading = false;
774
+ constructor(utilsService, notificationService) {
775
+ this.utilsService = utilsService;
776
+ this.notificationService = notificationService;
777
+ }
778
+ /**
779
+ * Display an error message to the user
780
+ * @param detail The error message to display
781
+ */
782
+ showError(detail) {
783
+ this.notificationService.showError(detail);
784
+ }
785
+ /**
786
+ * Display a success message to the user
787
+ * @param detail The success message to display
788
+ */
789
+ showSuccess(detail) {
790
+ this.notificationService.showSuccess(detail);
791
+ }
792
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BasePageComponent, deps: [{ token: UtilsService }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Directive });
793
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: BasePageComponent, isStandalone: true, ngImport: i0 });
794
+ }
795
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BasePageComponent, decorators: [{
796
+ type: Directive
797
+ }], ctorParameters: () => [{ type: UtilsService }, { type: NotificationService }] });
798
+
799
+ const AppMessages = {
800
+ COMMON: {
801
+ ERROR: {
802
+ GENERAL: 'An error occurred',
803
+ INVALID_INPUT: 'Invalid input provided',
804
+ REQUIRED_FIELD: 'This field is required'
805
+ },
806
+ SUCCESS: {
807
+ SAVE: 'saved successfully',
808
+ UPDATE: 'updated successfully',
809
+ DELETE: 'deleted successfully'
810
+ }
811
+ },
812
+ FORM: {
813
+ ERROR: {
814
+ INIT: 'Failed to initialize form',
815
+ SAVE: 'Failed to save',
816
+ LOAD: 'Failed to load',
817
+ VALIDATION: 'Please fill in all required fields correctly'
818
+ },
819
+ SUCCESS: {
820
+ SAVE: 'saved successfully'
821
+ }
822
+ },
823
+ LIST: {
824
+ ERROR: {
825
+ LOAD: 'Failed to load',
826
+ DELETE: 'Failed to delete',
827
+ NAVIGATION: 'Navigation failed',
828
+ INVALID_ID: 'Cannot perform action without ID'
829
+ },
830
+ SUCCESS: {
831
+ DELETE: 'deleted successfully'
832
+ }
833
+ }
834
+ };
835
+
836
+ class AppConstants {
837
+ static FORM = {
838
+ MODE: 'mode',
839
+ UUID: 'uuid',
840
+ NEW: 'new'
841
+ };
842
+ static PAGE_MODE = {
843
+ CREATE: 'create',
844
+ EDIT: 'edit',
845
+ VIEW: 'view'
846
+ };
847
+ }
848
+
849
+ class BaseFormComponent extends BasePageComponent {
850
+ route;
851
+ router;
852
+ notificationService;
853
+ utilsService;
854
+ formlyConfigService;
855
+ form = new FormGroup({});
856
+ fields = [];
857
+ isNew = true;
858
+ mode = AppConstants.PAGE_MODE.CREATE;
859
+ currentFormData = {};
860
+ originalFormData = null;
861
+ hasChanges = false;
862
+ context = ComponentContext.STANDALONE;
863
+ constructor(route, router, notificationService, utilsService, formlyConfigService) {
864
+ super(utilsService, notificationService);
865
+ this.route = route;
866
+ this.router = router;
867
+ this.notificationService = notificationService;
868
+ this.utilsService = utilsService;
869
+ this.formlyConfigService = formlyConfigService;
870
+ }
871
+ ngOnInit() {
872
+ try {
873
+ this.fields = this.getFormlyFieldConfig();
874
+ this.form.valueChanges.subscribe(() => {
875
+ console.log('[BaseFormComponent] Form value changed:', this.form.value);
876
+ this.currentFormData = { ...this.form.value };
877
+ this.hasChanges = this.hasFormChanges(this.currentFormData);
878
+ });
879
+ // Use queryParams instead of params
880
+ this.route.queryParams.pipe(take(1)).subscribe({
881
+ next: params => this.initializeForm(params),
882
+ error: error => {
883
+ console.error('Error initializing form:', error);
884
+ this.showError(AppMessages.FORM.ERROR.INIT);
885
+ }
886
+ });
887
+ }
888
+ catch (error) {
889
+ console.error('Error in ngOnInit:', error);
890
+ this.showError(AppMessages.FORM.ERROR.INIT);
891
+ }
892
+ }
893
+ initializeFormData() {
894
+ console.log('[BaseFormComponent] Initializing form data');
895
+ console.log('[BaseFormComponent] Current mode:', this.mode);
896
+ if (this.mode === AppConstants.PAGE_MODE.CREATE) {
897
+ console.log('[BaseFormComponent] Create mode, using defaults');
898
+ return;
899
+ }
900
+ const state = {
901
+ ...this.router.getCurrentNavigation()?.extras?.state,
902
+ ...window.history.state,
903
+ ...this.route.snapshot.data
904
+ };
905
+ console.log('[BaseFormComponent] Combined state:', state);
906
+ console.log('[BaseFormComponent] Final state being used:', state);
907
+ if (state && 'formData' in state) {
908
+ console.log('[BaseFormComponent] Found form data in state:', state['formData']);
909
+ this.patchFormData(state['formData']);
910
+ }
911
+ else {
912
+ console.log('[BaseFormComponent] No form data, loading from UUID');
913
+ this.loadFromUuid();
914
+ }
915
+ }
916
+ loadFromUuid() {
917
+ this.route.queryParams.pipe(take(1)).subscribe(params => {
918
+ const uuid = params[AppConstants.FORM.UUID];
919
+ if (!uuid) {
920
+ throw new Error(`UUID is required for ${this.mode} mode when no formData is provided`);
921
+ }
922
+ this.loadEntity(uuid);
923
+ });
924
+ }
925
+ initializeForm(params) {
926
+ console.log('[BaseFormComponent] Initializing form with params:', params);
927
+ const routeMode = params[AppConstants.FORM.MODE];
928
+ this.initializeFormMode(routeMode);
929
+ this.setupFormState();
930
+ // Check for context in router state
931
+ const state = window.history.state;
932
+ if (state?.context) {
933
+ this.context = state.context;
934
+ console.log('[BaseFormComponent] Context set from router state:', this.context);
935
+ }
936
+ this.initializeFormData();
937
+ }
938
+ patchFormData(data) {
939
+ console.log('[BaseFormComponent] Patching form data:', data);
940
+ if (data) {
941
+ if (!this.fields || this.fields.length === 0) {
942
+ console.warn('[BaseFormComponent] Fields not initialized yet, reinitializing');
943
+ this.fields = this.getFormlyFieldConfig();
944
+ }
945
+ this.currentFormData = { ...data };
946
+ this.originalFormData = data;
947
+ this.isNew = false;
948
+ console.log('[BaseFormComponent] Form data updated:', this.currentFormData);
949
+ console.log('[BaseFormComponent] Fields available:', this.fields);
950
+ setTimeout(() => {
951
+ if (!this.form.valid) {
952
+ console.warn('[BaseFormComponent] Form validation issues after data patch');
953
+ }
954
+ console.log('[BaseFormComponent] Form state after sync:', {
955
+ valid: this.form.valid,
956
+ values: this.form.value,
957
+ currentData: this.currentFormData
958
+ });
959
+ }, 100);
960
+ }
961
+ }
962
+ initializeFormMode(routeMode) {
963
+ if (!routeMode) {
964
+ this.mode = AppConstants.PAGE_MODE.CREATE;
965
+ }
966
+ else if (this.isValidPageMode(routeMode)) {
967
+ this.mode = routeMode;
968
+ }
969
+ else {
970
+ throw new Error(`Invalid page mode: ${routeMode}`);
971
+ }
972
+ }
973
+ setupFormState() {
974
+ console.log('[BaseFormComponent] Setting up form state, mode:', this.mode);
975
+ this.fields = this.getFormlyFieldConfig();
976
+ if (this.mode === AppConstants.PAGE_MODE.CREATE) {
977
+ console.log('[BaseFormComponent] Create mode setup');
978
+ this.isNew = true;
979
+ this.loading = false;
980
+ this.originalFormData = null;
981
+ }
982
+ if (this.mode === AppConstants.PAGE_MODE.VIEW) {
983
+ console.log('[BaseFormComponent] View mode setup');
984
+ this.form.disable();
985
+ }
986
+ }
987
+ getFormlyFieldConfig() {
988
+ return this.formlyConfigService.getFormConfig(this.getJsonFields(), this.mode, this.getDropdownOptions());
989
+ }
990
+ onSubmitRoute() {
991
+ return [`/${this.getEntityName().toLowerCase()}s`];
992
+ }
993
+ getEntityOperations() {
994
+ const entityService = this.getEntityService();
995
+ return {
996
+ create: (data) => entityService.create(data),
997
+ update: (uuid, data) => entityService.update(uuid, { ...data, uuid }),
998
+ getById: (uuid) => entityService.getById(uuid)
999
+ };
1000
+ }
1001
+ onSubmit() {
1002
+ console.log('[BaseFormComponent] Form submission:', {
1003
+ formValid: this.form.valid,
1004
+ formData: this.currentFormData,
1005
+ formState: this.form.value
1006
+ });
1007
+ if (!this.currentFormData || Object.keys(this.currentFormData).length === 0) {
1008
+ this.notificationService.showError('No data to save');
1009
+ return;
1010
+ }
1011
+ if (this.form.valid) {
1012
+ if (this.isNew) {
1013
+ console.log('[BaseFormComponent] Saving new entity');
1014
+ this.saveEntity();
1015
+ return;
1016
+ }
1017
+ const hasChanges = this.hasFormChanges(this.currentFormData);
1018
+ console.log('[BaseFormComponent] Change detection:', {
1019
+ hasChanges,
1020
+ currentData: this.currentFormData,
1021
+ originalData: this.originalFormData
1022
+ });
1023
+ if (!hasChanges) {
1024
+ this.notificationService.showSuccess('No changes to save');
1025
+ return;
1026
+ }
1027
+ console.log('[BaseFormComponent] Saving changes');
1028
+ this.saveEntity();
1029
+ }
1030
+ else {
1031
+ console.warn('[BaseFormComponent] Form validation failed:', this.form.errors);
1032
+ this.notificationService.showError('Please check form errors');
1033
+ }
1034
+ }
1035
+ hasFormChanges(currentData) {
1036
+ if (!this.originalFormData || this.isNew) {
1037
+ return true;
1038
+ }
1039
+ console.log('[BaseFormComponent] Checking for changes:', {
1040
+ currentData,
1041
+ originalData: this.originalFormData
1042
+ });
1043
+ const hasChanges = Object.keys(currentData).some(key => {
1044
+ const currentValue = currentData[key];
1045
+ const originalValue = this.originalFormData[key];
1046
+ const changed = currentValue !== originalValue;
1047
+ if (changed) {
1048
+ console.log(`[BaseFormComponent] Field '${key}' changed:`, {
1049
+ from: originalValue,
1050
+ to: currentValue
1051
+ });
1052
+ }
1053
+ return changed;
1054
+ });
1055
+ console.log('[BaseFormComponent] Changes detected:', hasChanges);
1056
+ return hasChanges;
1057
+ }
1058
+ saveEntity() {
1059
+ this.loading = true;
1060
+ const formData = this.currentFormData;
1061
+ const entityName = this.getEntityName();
1062
+ const entityOperations = this.getEntityOperations();
1063
+ const request$ = this.isNew
1064
+ ? entityOperations.create(formData)
1065
+ : entityOperations.update(this.originalFormData.uuid, formData);
1066
+ request$.subscribe({
1067
+ next: () => {
1068
+ this.loading = false;
1069
+ this.notificationService.showSuccess(`${entityName} ${AppMessages.FORM.SUCCESS.SAVE}`);
1070
+ this.router.navigate(this.onSubmitRoute());
1071
+ },
1072
+ error: (error) => {
1073
+ const errorMessage = error.error?.message || `${AppMessages.FORM.ERROR.SAVE} ${entityName}`;
1074
+ this.showError(errorMessage);
1075
+ this.loading = false;
1076
+ }
1077
+ });
1078
+ }
1079
+ loadEntity(uuid) {
1080
+ this.loading = true;
1081
+ this.isNew = false;
1082
+ const entityName = this.getEntityName();
1083
+ this.getEntityOperations().getById(uuid).subscribe({
1084
+ next: (data) => {
1085
+ this.originalFormData = data;
1086
+ this.currentFormData = { ...data };
1087
+ this.loading = false;
1088
+ console.log('[BaseFormComponent] Original data loaded:', this.originalFormData);
1089
+ console.log('[BaseFormComponent] Form data updated:', this.currentFormData);
1090
+ },
1091
+ error: () => {
1092
+ this.showError(`${AppMessages.FORM.ERROR.LOAD} ${entityName}`);
1093
+ this.loading = false;
1094
+ }
1095
+ });
1096
+ }
1097
+ isValidPageMode(mode) {
1098
+ return Object.values(AppConstants.PAGE_MODE).includes(mode);
1099
+ }
1100
+ getDropdownOptions() {
1101
+ return {};
1102
+ }
1103
+ /**
1104
+ * Checks if the component is running in a specific context
1105
+ * @param contextType The context type to check against
1106
+ */
1107
+ isInContext(contextType) {
1108
+ return this.context === contextType;
1109
+ }
1110
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseFormComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1$2.Router }, { token: NotificationService }, { token: UtilsService }, { token: FormlyConfigService }], target: i0.ɵɵFactoryTarget.Component });
1111
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: BaseFormComponent, isStandalone: true, selector: "ng-component", inputs: { context: "context" }, usesInheritance: true, ngImport: i0, template: '', isInline: true });
1112
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseFormComponent });
1113
+ }
1114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseFormComponent, decorators: [{
1115
+ type: Injectable
1116
+ }, {
1117
+ type: Component,
1118
+ args: [{
1119
+ template: ''
1120
+ }]
1121
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1$2.Router }, { type: NotificationService }, { type: UtilsService }, { type: FormlyConfigService }], propDecorators: { context: [{
1122
+ type: Input
1123
+ }] } });
1124
+
1125
+ /**
1126
+ * Base component for all list page components in the application.
1127
+ * Provides common functionality for list operations like loading data,
1128
+ * pagination, sorting, and CRUD operations.
1129
+ */
1130
+ class BaseListPageComponent extends BasePageComponent {
1131
+ router;
1132
+ notificationService;
1133
+ utilsService;
1134
+ confirmationService;
1135
+ table;
1136
+ items = [];
1137
+ actionLoading = false;
1138
+ rows = 10;
1139
+ totalRecords = 0;
1140
+ filters = [];
1141
+ subscriptions = [];
1142
+ constructor(router, notificationService, utilsService, confirmationService) {
1143
+ super(utilsService, notificationService);
1144
+ this.router = router;
1145
+ this.notificationService = notificationService;
1146
+ this.utilsService = utilsService;
1147
+ this.confirmationService = confirmationService;
1148
+ }
1149
+ /**
1150
+ * Initialize the component, subscribe to loading state if available,
1151
+ * and load initial data.
1152
+ */
1153
+ ngOnInit() {
1154
+ // Subscribe to loading state if available
1155
+ const loadingObservable = this.getLoadingObservable();
1156
+ if (loadingObservable) {
1157
+ this.subscriptions.push(loadingObservable.subscribe(isLoading => this.loading = isLoading));
1158
+ }
1159
+ this.loadData();
1160
+ }
1161
+ /**
1162
+ * Clean up any subscriptions when the component is destroyed
1163
+ */
1164
+ ngOnDestroy() {
1165
+ this.subscriptions.forEach(sub => sub.unsubscribe());
1166
+ }
1167
+ /**
1168
+ * Handle search event from the UI
1169
+ * @param event The search event
1170
+ */
1171
+ onSearch(event) {
1172
+ const element = event.target;
1173
+ if (this.table) {
1174
+ this.table.filterGlobal(element.value, 'contains');
1175
+ }
1176
+ }
1177
+ /**
1178
+ * Load data with pagination and sorting
1179
+ * @param event The lazy load event from PrimeNG table
1180
+ */
1181
+ /**
1182
+ * Convert PrimeNG filter format to backend format
1183
+ * @param filters The PrimeNG filters object
1184
+ * @returns Converted filters object for backend
1185
+ */
1186
+ /**
1187
+ * Convert PrimeNG filter format to backend format
1188
+ * @param filters The PrimeNG filters object
1189
+ * @returns Converted filters object for backend
1190
+ */
1191
+ /**
1192
+ * Convert PrimeNG filters to backend format with proper operator mapping
1193
+ */
1194
+ convertFilters(filters) {
1195
+ const backendFilters = [];
1196
+ if (!filters)
1197
+ return backendFilters;
1198
+ console.log('Raw PrimeNG filters:', filters);
1199
+ Object.entries(filters).forEach(([key, filterMeta]) => {
1200
+ console.log(`Processing filter for ${key}:`, filterMeta);
1201
+ // Handle array of filter metadata (multiple filters for same column)
1202
+ if (Array.isArray(filterMeta)) {
1203
+ const validFilters = filterMeta
1204
+ .filter(meta => meta.value !== null && meta.value !== undefined && meta.value !== '')
1205
+ .map(meta => ({
1206
+ field: key,
1207
+ value: this.transformFilterValue(String(meta.value)),
1208
+ operator: this.transformOperator(meta.matchMode)
1209
+ }));
1210
+ backendFilters.push(...validFilters);
1211
+ }
1212
+ // Handle single filter metadata
1213
+ else if (filterMeta?.value !== null && filterMeta?.value !== undefined && filterMeta?.value !== '') {
1214
+ backendFilters.push({
1215
+ field: key,
1216
+ value: this.transformFilterValue(String(filterMeta.value)),
1217
+ operator: this.transformOperator(filterMeta.matchMode)
1218
+ });
1219
+ }
1220
+ });
1221
+ console.log('Converted filters:', backendFilters);
1222
+ return backendFilters;
1223
+ }
1224
+ /**
1225
+ * Transform filter value based on backend requirements - all values must be strings
1226
+ */
1227
+ transformFilterValue(value) {
1228
+ if (value === null || value === undefined) {
1229
+ return '';
1230
+ }
1231
+ if (typeof value === 'string') {
1232
+ return value.trim();
1233
+ }
1234
+ if (Array.isArray(value)) {
1235
+ return value.join(',');
1236
+ }
1237
+ if (value instanceof Date) {
1238
+ return value.toISOString();
1239
+ }
1240
+ if (typeof value === 'number' || typeof value === 'boolean') {
1241
+ return value.toString();
1242
+ }
1243
+ return String(value);
1244
+ }
1245
+ /**
1246
+ * Map PrimeNG operators to backend operators
1247
+ */
1248
+ transformOperator(operator) {
1249
+ const operatorMap = {
1250
+ 'contains': 'CONTAINS',
1251
+ 'startsWith': 'STARTS_WITH',
1252
+ 'endsWith': 'ENDS_WITH',
1253
+ 'equals': 'EQUALS',
1254
+ 'notEquals': 'NOT_EQUALS',
1255
+ 'gt': 'GREATER_THAN',
1256
+ 'gte': 'GREATER_THAN_EQUALS',
1257
+ 'lt': 'LESS_THAN',
1258
+ 'lte': 'LESS_THAN_EQUALS'
1259
+ };
1260
+ return operatorMap[operator] || 'EQUALS'; // Default to EQUALS if operator not found
1261
+ }
1262
+ loadData(event) {
1263
+ console.log('LoadData called with event:', event);
1264
+ this.loading = true;
1265
+ // Create page request with default values
1266
+ const pageRequest = {
1267
+ page: 0,
1268
+ size: 10,
1269
+ sorts: [],
1270
+ filters: []
1271
+ };
1272
+ if (event) {
1273
+ // Handle pagination
1274
+ if (event.first !== undefined && event.rows) {
1275
+ pageRequest.page = Math.floor(event.first / event.rows);
1276
+ pageRequest.size = event.rows;
1277
+ }
1278
+ // Handle sorting
1279
+ if (event.sortField) {
1280
+ pageRequest.sorts = [{
1281
+ field: Array.isArray(event.sortField) ? event.sortField[0] : event.sortField,
1282
+ direction: event.sortOrder === 1 ? 'asc' : 'desc'
1283
+ }];
1284
+ }
1285
+ // Handle filtering
1286
+ if (event.filters) {
1287
+ const convertedFilters = this.convertFilters(event.filters);
1288
+ console.log('Converted filters:', convertedFilters);
1289
+ pageRequest.filters = convertedFilters;
1290
+ }
1291
+ }
1292
+ console.log('Sending page request:', pageRequest);
1293
+ this.getEntityService().getAll(pageRequest)
1294
+ .pipe(finalize$1(() => this.loading = false))
1295
+ .subscribe({
1296
+ next: (response) => {
1297
+ this.items = [...response.content];
1298
+ this.totalRecords = response.page.totalElements;
1299
+ },
1300
+ error: (error) => {
1301
+ console.error('Failed to load data:', error);
1302
+ this.showError(`${AppMessages.LIST.ERROR.LOAD} ${this.getEntityName()}`);
1303
+ }
1304
+ });
1305
+ }
1306
+ /**
1307
+ * Navigate to create a new entity
1308
+ */
1309
+ onCreate() {
1310
+ this.navigateTo([this.getFormRoute(), AppConstants.PAGE_MODE.CREATE]);
1311
+ }
1312
+ /**
1313
+ * Navigate to view an entity
1314
+ * @param item The entity to view
1315
+ */
1316
+ onView(item) {
1317
+ if (!this.validateItemUuid(item, 'view'))
1318
+ return;
1319
+ this.navigateTo([this.getFormRoute(), AppConstants.PAGE_MODE.VIEW], { uuid: item.uuid });
1320
+ }
1321
+ /**
1322
+ * Navigate to edit an entity
1323
+ * @param item The entity to edit
1324
+ */
1325
+ onEdit(item) {
1326
+ if (!this.validateItemUuid(item, 'edit'))
1327
+ return;
1328
+ this.navigateTo([this.getFormRoute(), AppConstants.PAGE_MODE.EDIT], { uuid: item.uuid });
1329
+ }
1330
+ /**
1331
+ * Navigate to a route with error handling
1332
+ * @param path The route path
1333
+ * @param matrixParams Optional matrix parameters
1334
+ */
1335
+ navigateTo(path, matrixParams) {
1336
+ this.router.navigate(path, { queryParams: matrixParams })
1337
+ .catch(error => {
1338
+ console.error('Navigation error:', error);
1339
+ this.showError(AppMessages.LIST.ERROR.NAVIGATION);
1340
+ });
1341
+ }
1342
+ /**
1343
+ * Delete an entity with confirmation
1344
+ * @param item The entity to delete
1345
+ */
1346
+ onDelete(item) {
1347
+ if (!this.validateItemUuid(item, 'delete'))
1348
+ return;
1349
+ this.confirmationService.confirm({
1350
+ message: `Are you sure you want to delete this ${this.getEntityName()}?`,
1351
+ header: 'Confirm Deletion',
1352
+ icon: 'pi pi-exclamation-triangle',
1353
+ accept: () => {
1354
+ this.actionLoading = true;
1355
+ this.getEntityService().delete(item.uuid)
1356
+ .pipe(finalize$1(() => this.actionLoading = false))
1357
+ .subscribe({
1358
+ next: () => {
1359
+ this.showSuccess(`${this.getEntityName()} ${AppMessages.LIST.SUCCESS.DELETE}`);
1360
+ this.loadData();
1361
+ },
1362
+ error: (error) => {
1363
+ console.error('Delete failed:', error);
1364
+ this.showError(`${AppMessages.LIST.ERROR.DELETE} ${this.getEntityName()}`);
1365
+ }
1366
+ });
1367
+ }
1368
+ });
1369
+ }
1370
+ /**
1371
+ * Validate that an entity has a UUID
1372
+ * @param item The entity to validate
1373
+ * @param action The action being performed
1374
+ * @returns true if valid, false otherwise
1375
+ */
1376
+ validateItemUuid(item, action) {
1377
+ if (!item?.uuid) {
1378
+ this.showError(`${AppMessages.LIST.ERROR.INVALID_ID} ${action}`);
1379
+ return false;
1380
+ }
1381
+ return true;
1382
+ }
1383
+ /**
1384
+ * Get an observable for loading state from the entity service
1385
+ * @returns An observable of loading state if available, null otherwise
1386
+ */
1387
+ getLoadingObservable() {
1388
+ const service = this.getEntityService();
1389
+ return service.loading$ || null;
1390
+ }
1391
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseListPageComponent, deps: [{ token: i1$2.Router }, { token: NotificationService }, { token: UtilsService }, { token: i1.ConfirmationService }], target: i0.ɵɵFactoryTarget.Directive });
1392
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.4", type: BaseListPageComponent, isStandalone: true, viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], usesInheritance: true, ngImport: i0 });
1393
+ }
1394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseListPageComponent, decorators: [{
1395
+ type: Directive
1396
+ }], ctorParameters: () => [{ type: i1$2.Router }, { type: NotificationService }, { type: UtilsService }, { type: i1.ConfirmationService }], propDecorators: { table: [{
1397
+ type: ViewChild,
1398
+ args: ['dt']
1399
+ }] } });
1400
+
1401
+ class BaseTabbedFormComponent extends BasePageComponent {
1402
+ route;
1403
+ router;
1404
+ notificationService;
1405
+ utilsService;
1406
+ // Tab specific properties
1407
+ activeTab = '';
1408
+ tabs = [];
1409
+ formType = '';
1410
+ // Form properties
1411
+ isNew = true;
1412
+ mode = AppConstants.PAGE_MODE.CREATE;
1413
+ currentFormData;
1414
+ originalFormData = null;
1415
+ hasChanges = false;
1416
+ debug(message, ...args) {
1417
+ // Only log in development
1418
+ if (process.env['NODE_ENV'] !== 'production') {
1419
+ console.log(`[BaseTabbedFormComponent] ${message}`, ...args);
1420
+ }
1421
+ }
1422
+ constructor(route, router, notificationService, utilsService) {
1423
+ super(utilsService, notificationService);
1424
+ this.route = route;
1425
+ this.router = router;
1426
+ this.notificationService = notificationService;
1427
+ this.utilsService = utilsService;
1428
+ }
1429
+ ngOnInit() {
1430
+ try {
1431
+ // Initialize tabs
1432
+ this.tabs = this.getTabs();
1433
+ this.activeTab = this.tabs[0]?.value || '';
1434
+ // Initialize form using query params
1435
+ this.route.queryParams.pipe(take(1)).subscribe({
1436
+ next: params => this.initializeForm(params),
1437
+ error: error => {
1438
+ console.error('Error initializing form:', error);
1439
+ this.showError(AppMessages.FORM.ERROR.INIT);
1440
+ }
1441
+ });
1442
+ }
1443
+ catch (error) {
1444
+ console.error('Error in ngOnInit:', error);
1445
+ this.showError(AppMessages.FORM.ERROR.INIT);
1446
+ }
1447
+ }
1448
+ initializeFormData() {
1449
+ this.debug('Initializing form data');
1450
+ this.debug('Current mode:', this.mode);
1451
+ if (this.mode === AppConstants.PAGE_MODE.CREATE) {
1452
+ this.debug('Create mode, using defaults');
1453
+ this.loadDefaultTab();
1454
+ return;
1455
+ }
1456
+ const state = {
1457
+ ...this.router.getCurrentNavigation()?.extras?.state,
1458
+ ...window.history.state
1459
+ };
1460
+ this.debug('Combined state:', state);
1461
+ if (state?.formData) {
1462
+ this.debug('Found form data in state:', state.formData);
1463
+ this.patchFormData(state.formData);
1464
+ this.loadDefaultTab();
1465
+ }
1466
+ else {
1467
+ this.debug('No form data, loading from UUID');
1468
+ this.loadFromUuid();
1469
+ }
1470
+ }
1471
+ loadFromUuid() {
1472
+ // Flatten nested subscriptions using RxJS operators
1473
+ this.route.queryParams.pipe(take(1), map((params) => {
1474
+ const uuid = params[AppConstants.FORM.UUID];
1475
+ if (!uuid) {
1476
+ throw new Error(`UUID is required for ${this.mode} mode when no formData is provided`);
1477
+ }
1478
+ return uuid;
1479
+ })).subscribe({
1480
+ next: (uuid) => this.loadEntity(uuid),
1481
+ error: (error) => {
1482
+ console.error('Error loading UUID:', error);
1483
+ this.showError(`${AppMessages.FORM.ERROR.LOAD} UUID`);
1484
+ }
1485
+ });
1486
+ }
1487
+ initializeForm(params) {
1488
+ // Remove debug logging for production
1489
+ const routeMode = params[AppConstants.FORM.MODE];
1490
+ try {
1491
+ this.initializeFormMode(routeMode);
1492
+ this.setupFormState();
1493
+ if (this.formType === TabbedFormType.LIST) {
1494
+ this.initializeListForm(params);
1495
+ }
1496
+ else {
1497
+ this.initializeFormData();
1498
+ }
1499
+ }
1500
+ catch (error) {
1501
+ console.error('Error initializing form:', error);
1502
+ this.showError(`${AppMessages.FORM.ERROR.INIT}: ${error instanceof Error ? error.message : 'Unknown error'}`);
1503
+ }
1504
+ }
1505
+ patchFormData(data) {
1506
+ if (data) {
1507
+ this.currentFormData = { ...data };
1508
+ this.originalFormData = { ...data }; // Create a deep copy to avoid reference issues
1509
+ this.isNew = false;
1510
+ }
1511
+ }
1512
+ initializeFormMode(routeMode) {
1513
+ if (!routeMode) {
1514
+ this.mode = AppConstants.PAGE_MODE.CREATE;
1515
+ return;
1516
+ }
1517
+ // Validate mode more explicitly
1518
+ if (!this.isValidPageMode(routeMode)) {
1519
+ const validModes = Object.values(AppConstants.PAGE_MODE).join(', ');
1520
+ throw new Error(`Invalid page mode: ${routeMode}. Valid modes are: ${validModes}`);
1521
+ }
1522
+ this.mode = routeMode;
1523
+ }
1524
+ setupFormState() {
1525
+ this.debug('Setting up form state, mode:', this.mode);
1526
+ if (this.mode === AppConstants.PAGE_MODE.CREATE) {
1527
+ this.debug('Create mode setup');
1528
+ this.isNew = true;
1529
+ this.loading = false;
1530
+ this.originalFormData = null;
1531
+ }
1532
+ }
1533
+ loadEntity(uuid) {
1534
+ this.loading = true;
1535
+ this.isNew = false;
1536
+ const entityName = this.getEntityName();
1537
+ this.getEntityService().getById(uuid).subscribe({
1538
+ next: (data) => {
1539
+ this.originalFormData = data;
1540
+ this.currentFormData = { ...data };
1541
+ this.loading = false;
1542
+ this.debug('Original data loaded:', this.originalFormData);
1543
+ this.debug('Form data updated:', this.currentFormData);
1544
+ this.loadDefaultTab();
1545
+ },
1546
+ error: (error) => {
1547
+ this.debug('Error loading entity:', error);
1548
+ this.showError(`${AppMessages.FORM.ERROR.LOAD} ${entityName}`);
1549
+ this.loading = false;
1550
+ }
1551
+ });
1552
+ }
1553
+ findTabByValue(value) {
1554
+ return this.tabs.find(tab => tab.value === value);
1555
+ }
1556
+ loadDefaultTab() {
1557
+ this.debug('Loading default tab');
1558
+ const defaultTab = this.tabs.find(tab => tab.isParentModel) || this.tabs[0];
1559
+ if (!defaultTab)
1560
+ return;
1561
+ if (this.formType === TabbedFormType.LIST) {
1562
+ const state = this.router.getCurrentNavigation()?.extras?.state || window.history.state;
1563
+ const formDataList = state?.formDataList || [];
1564
+ const selectedData = formDataList.find((data) => data.uuid === defaultTab.value);
1565
+ this.router.navigate([defaultTab.value], {
1566
+ relativeTo: this.route,
1567
+ state: {
1568
+ formData: selectedData,
1569
+ formDataList: formDataList,
1570
+ context: ComponentContext.TABBED
1571
+ }
1572
+ });
1573
+ }
1574
+ else {
1575
+ this.router.navigate([defaultTab.value], {
1576
+ relativeTo: this.route,
1577
+ queryParamsHandling: 'preserve', // Keep existing query params (mode & uuid)
1578
+ state: {
1579
+ formData: this.currentFormData,
1580
+ context: ComponentContext.TABBED
1581
+ }
1582
+ });
1583
+ }
1584
+ }
1585
+ getTabFormData(tabConfig) {
1586
+ if (!tabConfig)
1587
+ return null;
1588
+ if (tabConfig.isParentModel) {
1589
+ return this.currentFormData;
1590
+ }
1591
+ const fieldName = this.utilsService.toCamelCase(tabConfig.value);
1592
+ // Use type assertion since we know this is a valid field
1593
+ return this.currentFormData[fieldName];
1594
+ }
1595
+ initializeListForm(params) {
1596
+ const state = this.router.getCurrentNavigation()?.extras?.state || window.history.state;
1597
+ const formDataList = state?.formDataList;
1598
+ if (!formDataList?.length) {
1599
+ throw new Error('formDataList is required in state for LIST type');
1600
+ }
1601
+ // Create tabs from list in state
1602
+ this.tabs = formDataList.map((data) => ({
1603
+ value: data.uuid,
1604
+ title: this.getTabTitle(data),
1605
+ isParentModel: true
1606
+ }));
1607
+ // Select tab based on UUID in params or first tab
1608
+ const uuid = params[AppConstants.FORM.UUID];
1609
+ this.activeTab = uuid && this.tabs.find(t => t.value === uuid)
1610
+ ? uuid
1611
+ : this.tabs[0].value;
1612
+ // Set current form data from list
1613
+ const selectedData = formDataList.find((d) => d.uuid === this.activeTab);
1614
+ this.currentFormData = selectedData;
1615
+ this.originalFormData = selectedData;
1616
+ }
1617
+ onTabChange(value) {
1618
+ const tabConfig = this.findTabByValue(value);
1619
+ if (!tabConfig) {
1620
+ console.warn(`Tab not found: ${value}`);
1621
+ return;
1622
+ }
1623
+ this.activeTab = tabConfig.value;
1624
+ if (this.formType === TabbedFormType.LIST) {
1625
+ const state = this.router.getCurrentNavigation()?.extras?.state || window.history.state;
1626
+ const formDataList = state?.formDataList || [];
1627
+ const selectedData = formDataList.find((data) => data.uuid === value);
1628
+ // Update current form data
1629
+ this.currentFormData = selectedData;
1630
+ this.originalFormData = selectedData;
1631
+ this.router.navigate([value], {
1632
+ relativeTo: this.route,
1633
+ state: {
1634
+ formData: selectedData,
1635
+ formDataList: formDataList,
1636
+ context: ComponentContext.TABBED
1637
+ }
1638
+ });
1639
+ }
1640
+ else {
1641
+ const formData = this.getTabFormData(tabConfig);
1642
+ this.router.navigate([this.activeTab], {
1643
+ relativeTo: this.route,
1644
+ queryParamsHandling: 'preserve',
1645
+ state: {
1646
+ formData,
1647
+ context: ComponentContext.TABBED
1648
+ }
1649
+ });
1650
+ }
1651
+ }
1652
+ hasFormChanges(currentData) {
1653
+ // For new forms or no original data, consider it changed
1654
+ if (this.isNew || !this.originalFormData) {
1655
+ return true;
1656
+ }
1657
+ // Deep comparison of objects
1658
+ return !this.isEqual(currentData, this.originalFormData);
1659
+ }
1660
+ isEqual(obj1, obj2) {
1661
+ if (obj1 === obj2)
1662
+ return true;
1663
+ if (typeof obj1 !== 'object' || obj1 === null ||
1664
+ typeof obj2 !== 'object' || obj2 === null)
1665
+ return false;
1666
+ const keys1 = Object.keys(obj1);
1667
+ const keys2 = Object.keys(obj2);
1668
+ if (keys1.length !== keys2.length)
1669
+ return false;
1670
+ return keys1.every(key => Object.prototype.hasOwnProperty.call(obj2, key) &&
1671
+ this.isEqual(obj1[key], obj2[key]));
1672
+ }
1673
+ isValidPageMode(mode) {
1674
+ return Object.values(AppConstants.PAGE_MODE).includes(mode);
1675
+ }
1676
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseTabbedFormComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1$2.Router }, { token: NotificationService }, { token: UtilsService }], target: i0.ɵɵFactoryTarget.Component });
1677
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: BaseTabbedFormComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: '', isInline: true });
1678
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseTabbedFormComponent });
1679
+ }
1680
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: BaseTabbedFormComponent, decorators: [{
1681
+ type: Injectable
1682
+ }, {
1683
+ type: Component,
1684
+ args: [{
1685
+ template: ''
1686
+ }]
1687
+ }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1$2.Router }, { type: NotificationService }, { type: UtilsService }] });
1688
+
1689
+ class IndianDatePipe {
1690
+ datePipe;
1691
+ constructor(datePipe) {
1692
+ this.datePipe = datePipe;
1693
+ }
1694
+ transform(value, format = 'default') {
1695
+ if (!value)
1696
+ return null;
1697
+ // First validate dd-MM-yyyy format
1698
+ const dateRegex = /^(0[1-9]|[12][0-9]|3[01])-(0[1-9]|1[0-2])-\d{4}$/;
1699
+ if (!dateRegex.test(value)) {
1700
+ throw new Error(`Invalid date format: ${value}. Expected format: dd-MM-yyyy`);
1701
+ }
1702
+ // Validate real date
1703
+ const [day, month, year] = value.split('-').map(Number);
1704
+ const date = new Date(year, month - 1, day);
1705
+ if (date.getFullYear() !== year ||
1706
+ date.getMonth() !== month - 1 ||
1707
+ date.getDate() !== day) {
1708
+ throw new Error(`Invalid date: ${value}`);
1709
+ }
1710
+ // Apply requested format
1711
+ switch (format) {
1712
+ case 'short':
1713
+ // Pad with leading zeros for consistent format
1714
+ const paddedDay = day.toString().padStart(2, '0');
1715
+ const paddedMonth = month.toString().padStart(2, '0');
1716
+ return `${paddedDay}-${paddedMonth}-${year}`; // 10-03-2025
1717
+ case 'medium':
1718
+ return this.datePipe.transform(date, 'dd MMM yyyy'); // 10 Jan 2019
1719
+ default:
1720
+ return value; // original dd-MM-yyyy
1721
+ }
1722
+ }
1723
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: IndianDatePipe, deps: [{ token: i1$3.DatePipe }], target: i0.ɵɵFactoryTarget.Pipe });
1724
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: IndianDatePipe, isStandalone: true, name: "indianDate" });
1725
+ }
1726
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: IndianDatePipe, decorators: [{
1727
+ type: Pipe,
1728
+ args: [{
1729
+ name: 'indianDate',
1730
+ standalone: true
1731
+ }]
1732
+ }], ctorParameters: () => [{ type: i1$3.DatePipe }] });
1733
+
1734
+ class TextInputType extends FieldType {
1735
+ defaultOptions = {
1736
+ props: {
1737
+ type: 'text',
1738
+ placeholder: ''
1739
+ }
1740
+ };
1741
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextInputType, deps: null, target: i0.ɵɵFactoryTarget.Component });
1742
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TextInputType, isStandalone: true, selector: "formly-field-text-input", usesInheritance: true, ngImport: i0, template: `
1743
+ <input pInputText
1744
+ [type]="props['type'] || 'text'"
1745
+ [formControl]="$any(formControl)"
1746
+ [formlyAttributes]="field"
1747
+ [placeholder]="props['placeholder'] || ''"
1748
+ [attr.aria-label]="props['label'] || props['placeholder'] || ''"
1749
+ class="w-full"/>
1750
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] });
1751
+ }
1752
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextInputType, decorators: [{
1753
+ type: Component,
1754
+ args: [{
1755
+ selector: 'formly-field-text-input',
1756
+ standalone: true,
1757
+ imports: [
1758
+ CommonModule,
1759
+ ReactiveFormsModule,
1760
+ FormlyModule,
1761
+ InputTextModule
1762
+ ],
1763
+ template: `
1764
+ <input pInputText
1765
+ [type]="props['type'] || 'text'"
1766
+ [formControl]="$any(formControl)"
1767
+ [formlyAttributes]="field"
1768
+ [placeholder]="props['placeholder'] || ''"
1769
+ [attr.aria-label]="props['label'] || props['placeholder'] || ''"
1770
+ class="w-full"/>
1771
+ `
1772
+ }]
1773
+ }] });
1774
+
1775
+ class SelectType extends FieldType {
1776
+ get options$() {
1777
+ const options = this.props['options'];
1778
+ return isObservable(options) ? options : of(options || []);
1779
+ }
1780
+ defaultOptions = {
1781
+ props: {
1782
+ options: [],
1783
+ optionLabel: 'label',
1784
+ optionValue: 'value',
1785
+ placeholder: 'Select',
1786
+ showClear: false,
1787
+ filter: false,
1788
+ virtualScroll: false
1789
+ }
1790
+ };
1791
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectType, deps: null, target: i0.ɵɵFactoryTarget.Component });
1792
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: SelectType, isStandalone: true, selector: "formly-field-select", usesInheritance: true, ngImport: i0, template: `
1793
+ <ng-container *ngIf="options$ | async as options">
1794
+ <p-select
1795
+ [formControl]="$any(formControl)"
1796
+ [formlyAttributes]="field"
1797
+ [options]="options"
1798
+ [virtualScroll]="false"
1799
+ [showClear]="false"
1800
+ [placeholder]="props['placeholder'] || 'Select'"
1801
+ styleClass="w-full">
1802
+ </p-select>
1803
+ </ng-container>
1804
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }] });
1805
+ }
1806
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: SelectType, decorators: [{
1807
+ type: Component,
1808
+ args: [{
1809
+ selector: 'formly-field-select',
1810
+ standalone: true,
1811
+ imports: [
1812
+ CommonModule,
1813
+ ReactiveFormsModule,
1814
+ FormlyModule,
1815
+ SelectModule
1816
+ ],
1817
+ template: `
1818
+ <ng-container *ngIf="options$ | async as options">
1819
+ <p-select
1820
+ [formControl]="$any(formControl)"
1821
+ [formlyAttributes]="field"
1822
+ [options]="options"
1823
+ [virtualScroll]="false"
1824
+ [showClear]="false"
1825
+ [placeholder]="props['placeholder'] || 'Select'"
1826
+ styleClass="w-full">
1827
+ </p-select>
1828
+ </ng-container>
1829
+ `
1830
+ }]
1831
+ }] });
1832
+
1833
+ class RadioType extends FieldType {
1834
+ get options$() {
1835
+ const options = this.props['options'];
1836
+ return isObservable(options) ? options : of(options || []);
1837
+ }
1838
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioType, deps: null, target: i0.ɵɵFactoryTarget.Component });
1839
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: RadioType, isStandalone: true, selector: "formly-field-radio", usesInheritance: true, ngImport: i0, template: `
1840
+ <div class="flex flex-column gap-1">
1841
+ <ng-container *ngIf="options$ | async as options">
1842
+ <div *ngFor="let option of options; let i = index" class="flex align-items-center gap-2">
1843
+ <p-radioButton
1844
+ [name]="field.name || ''"
1845
+ [value]="option.value"
1846
+ [formControl]="$any(formControl)"
1847
+ [formlyAttributes]="field"
1848
+ [size]="'small'"
1849
+ [inputId]="field.key + '_' + i">
1850
+ </p-radioButton>
1851
+ <label [for]="field.key + '_' + i" class="p-radio-label cursor-pointer">
1852
+ {{option.label}}
1853
+ </label>
1854
+ </div>
1855
+ </ng-container>
1856
+ </div>
1857
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i4$1.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }] });
1858
+ }
1859
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: RadioType, decorators: [{
1860
+ type: Component,
1861
+ args: [{
1862
+ selector: 'formly-field-radio',
1863
+ standalone: true,
1864
+ imports: [
1865
+ CommonModule,
1866
+ ReactiveFormsModule,
1867
+ FormlyModule,
1868
+ RadioButtonModule
1869
+ ],
1870
+ template: `
1871
+ <div class="flex flex-column gap-1">
1872
+ <ng-container *ngIf="options$ | async as options">
1873
+ <div *ngFor="let option of options; let i = index" class="flex align-items-center gap-2">
1874
+ <p-radioButton
1875
+ [name]="field.name || ''"
1876
+ [value]="option.value"
1877
+ [formControl]="$any(formControl)"
1878
+ [formlyAttributes]="field"
1879
+ [size]="'small'"
1880
+ [inputId]="field.key + '_' + i">
1881
+ </p-radioButton>
1882
+ <label [for]="field.key + '_' + i" class="p-radio-label cursor-pointer">
1883
+ {{option.label}}
1884
+ </label>
1885
+ </div>
1886
+ </ng-container>
1887
+ </div>
1888
+ `
1889
+ }]
1890
+ }] });
1891
+
1892
+ class NumericInputType extends FieldType {
1893
+ defaultOptions = {
1894
+ props: {
1895
+ min: undefined,
1896
+ max: undefined,
1897
+ minFractionDigits: 0,
1898
+ maxFractionDigits: 0,
1899
+ prefix: '',
1900
+ suffix: '',
1901
+ useGrouping: true
1902
+ }
1903
+ };
1904
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NumericInputType, deps: null, target: i0.ɵɵFactoryTarget.Component });
1905
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: NumericInputType, isStandalone: true, selector: "formly-field-numeric-input", usesInheritance: true, ngImport: i0, template: `
1906
+ <p-inputNumber
1907
+ [formControl]="$any(formControl)"
1908
+ [formlyAttributes]="field"
1909
+ [placeholder]="props['placeholder'] || ''"
1910
+ [min]="props['min'] || 0"
1911
+ [max]="props['max']"
1912
+ [minFractionDigits]="props['minFractionDigits'] || 0"
1913
+ [maxFractionDigits]="props['maxFractionDigits'] || 0"
1914
+ [prefix]="props['prefix'] || ''"
1915
+ [suffix]="props['suffix'] || ''"
1916
+ [useGrouping]="props['useGrouping'] ?? true"
1917
+ [showButtons]="true"
1918
+ class="w-full">
1919
+ </p-inputNumber>
1920
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i3$1.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }] });
1921
+ }
1922
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: NumericInputType, decorators: [{
1923
+ type: Component,
1924
+ args: [{
1925
+ selector: 'formly-field-numeric-input',
1926
+ standalone: true,
1927
+ imports: [
1928
+ CommonModule,
1929
+ ReactiveFormsModule,
1930
+ FormlyModule,
1931
+ InputNumberModule
1932
+ ],
1933
+ template: `
1934
+ <p-inputNumber
1935
+ [formControl]="$any(formControl)"
1936
+ [formlyAttributes]="field"
1937
+ [placeholder]="props['placeholder'] || ''"
1938
+ [min]="props['min'] || 0"
1939
+ [max]="props['max']"
1940
+ [minFractionDigits]="props['minFractionDigits'] || 0"
1941
+ [maxFractionDigits]="props['maxFractionDigits'] || 0"
1942
+ [prefix]="props['prefix'] || ''"
1943
+ [suffix]="props['suffix'] || ''"
1944
+ [useGrouping]="props['useGrouping'] ?? true"
1945
+ [showButtons]="true"
1946
+ class="w-full">
1947
+ </p-inputNumber>
1948
+ `
1949
+ }]
1950
+ }] });
1951
+
1952
+ class MultiselectType extends FieldType {
1953
+ get options$() {
1954
+ const options = this.props['options'];
1955
+ return isObservable(options) ? options : of(options || []);
1956
+ }
1957
+ defaultOptions = {
1958
+ props: {
1959
+ options: [],
1960
+ optionLabel: 'label',
1961
+ optionValue: 'value',
1962
+ placeholder: 'Select',
1963
+ filter: false,
1964
+ maxSelectedLabels: 3,
1965
+ showToggleAll: true,
1966
+ virtualScroll: false
1967
+ }
1968
+ };
1969
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiselectType, deps: null, target: i0.ɵɵFactoryTarget.Component });
1970
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: MultiselectType, isStandalone: true, selector: "formly-field-multiselect", usesInheritance: true, ngImport: i0, template: `
1971
+ <ng-container *ngIf="options$ | async as options">
1972
+ <p-multiSelect
1973
+ [formControl]="$any(formControl)"
1974
+ [formlyAttributes]="field"
1975
+ [options]="options"
1976
+ [optionLabel]="props['optionLabel'] || 'label'"
1977
+ [optionValue]="props['optionValue'] || 'value'"
1978
+ [placeholder]="props['placeholder'] || 'Select'"
1979
+ [filter]="props['filter'] || true"
1980
+ [filterBy]="props['filterBy'] || 'label'"
1981
+ [maxSelectedLabels]="props['maxSelectedLabels'] || 2"
1982
+ [showToggleAll]="props['showToggleAll'] || true"
1983
+ [virtualScroll]="props['virtualScroll'] || false"
1984
+ [display]="props['display'] || 'chip'"
1985
+ styleClass="w-full">
1986
+ </p-multiSelect>
1987
+ </ng-container>
1988
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i4$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }] });
1989
+ }
1990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: MultiselectType, decorators: [{
1991
+ type: Component,
1992
+ args: [{
1993
+ selector: 'formly-field-multiselect',
1994
+ standalone: true,
1995
+ imports: [
1996
+ CommonModule,
1997
+ ReactiveFormsModule,
1998
+ FormlyModule,
1999
+ MultiSelectModule
2000
+ ],
2001
+ template: `
2002
+ <ng-container *ngIf="options$ | async as options">
2003
+ <p-multiSelect
2004
+ [formControl]="$any(formControl)"
2005
+ [formlyAttributes]="field"
2006
+ [options]="options"
2007
+ [optionLabel]="props['optionLabel'] || 'label'"
2008
+ [optionValue]="props['optionValue'] || 'value'"
2009
+ [placeholder]="props['placeholder'] || 'Select'"
2010
+ [filter]="props['filter'] || true"
2011
+ [filterBy]="props['filterBy'] || 'label'"
2012
+ [maxSelectedLabels]="props['maxSelectedLabels'] || 2"
2013
+ [showToggleAll]="props['showToggleAll'] || true"
2014
+ [virtualScroll]="props['virtualScroll'] || false"
2015
+ [display]="props['display'] || 'chip'"
2016
+ styleClass="w-full">
2017
+ </p-multiSelect>
2018
+ </ng-container>
2019
+ `
2020
+ }]
2021
+ }] });
2022
+
2023
+ class DateType extends FieldType {
2024
+ defaultOptions = {
2025
+ props: {
2026
+ dateFormat: 'dd-mm-yy',
2027
+ showTime: false,
2028
+ touchUI: false,
2029
+ placeholder: '',
2030
+ showButtonBar: true,
2031
+ }
2032
+ };
2033
+ onDateSelect(event) {
2034
+ this.formatAndSetDate(event);
2035
+ }
2036
+ onDateInput(event) {
2037
+ const inputValue = event.target.value.trim();
2038
+ if (this.isValidDateInput(inputValue, this.props['dateFormat'] || 'dd-mm-yy')) {
2039
+ const parsedDate = this.parseDate(inputValue, this.props['dateFormat'] || 'dd-mm-yy');
2040
+ if (parsedDate) {
2041
+ this.formatAndSetDate(parsedDate);
2042
+ }
2043
+ }
2044
+ else {
2045
+ this.formControl?.setErrors({ invalidDate: true });
2046
+ }
2047
+ }
2048
+ formatAndSetDate(date) {
2049
+ if (this.formControl) {
2050
+ const formattedDate = formatDate(date, 'dd-MM-yyyy', 'en-US');
2051
+ this.formControl.setValue(formattedDate);
2052
+ }
2053
+ }
2054
+ parseDate(value, format) {
2055
+ const parts = value.split(/[-/]/); // Split by common delimiters
2056
+ if (parts.length === 3) {
2057
+ const [day, month, year] = format === 'dd-mm-yy'
2058
+ ? [parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10)]
2059
+ : [parseInt(parts[1], 10), parseInt(parts[0], 10) - 1, parseInt(parts[2], 10)];
2060
+ return new Date(year, month, day);
2061
+ }
2062
+ return null;
2063
+ }
2064
+ isValidDateInput(value, format) {
2065
+ const dateRegex = format === 'dd-mm-yy'
2066
+ ? /^\d{2}-\d{2}-\d{4}$/
2067
+ : /^\d{2}\/\d{2}\/\d{4}$/;
2068
+ return dateRegex.test(value);
2069
+ }
2070
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DateType, deps: null, target: i0.ɵɵFactoryTarget.Component });
2071
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: DateType, isStandalone: true, selector: "formly-field-date", usesInheritance: true, ngImport: i0, template: `
2072
+ <p-datepicker
2073
+ [formControl]="$any(formControl)"
2074
+ [formlyAttributes]="field"
2075
+ [showIcon]="true"
2076
+ [dateFormat]="props['dateFormat'] || 'dd-mm-yy'"
2077
+ [showTime]="props['showTime'] || false"
2078
+ [touchUI]="props['touchUI'] || false"
2079
+ [placeholder]="props['placeholder'] || ''"
2080
+ [minDate]="props['minDate']"
2081
+ [maxDate]="props['maxDate']"
2082
+ [showOnFocus]="false"
2083
+ [todayButtonStyleClass]="'p-button-secondary'"
2084
+ [clearButtonStyleClass]="'p-button-secondary'"
2085
+ styleClass="w-full"
2086
+ (onSelect)="onDateSelect($event)"
2087
+ (onInput)="onDateInput($event)">
2088
+ </p-datepicker>
2089
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i3$2.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }] });
2090
+ }
2091
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: DateType, decorators: [{
2092
+ type: Component,
2093
+ args: [{
2094
+ selector: 'formly-field-date',
2095
+ standalone: true,
2096
+ imports: [
2097
+ CommonModule,
2098
+ ReactiveFormsModule,
2099
+ FormlyModule,
2100
+ DatePickerModule
2101
+ ],
2102
+ template: `
2103
+ <p-datepicker
2104
+ [formControl]="$any(formControl)"
2105
+ [formlyAttributes]="field"
2106
+ [showIcon]="true"
2107
+ [dateFormat]="props['dateFormat'] || 'dd-mm-yy'"
2108
+ [showTime]="props['showTime'] || false"
2109
+ [touchUI]="props['touchUI'] || false"
2110
+ [placeholder]="props['placeholder'] || ''"
2111
+ [minDate]="props['minDate']"
2112
+ [maxDate]="props['maxDate']"
2113
+ [showOnFocus]="false"
2114
+ [todayButtonStyleClass]="'p-button-secondary'"
2115
+ [clearButtonStyleClass]="'p-button-secondary'"
2116
+ styleClass="w-full"
2117
+ (onSelect)="onDateSelect($event)"
2118
+ (onInput)="onDateInput($event)">
2119
+ </p-datepicker>
2120
+ `
2121
+ }]
2122
+ }] });
2123
+
2124
+ class CheckboxType extends FieldType {
2125
+ defaultOptions = {
2126
+ props: {
2127
+ trueValue: true,
2128
+ falseValue: false
2129
+ }
2130
+ };
2131
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxType, deps: null, target: i0.ɵɵFactoryTarget.Component });
2132
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: CheckboxType, isStandalone: true, selector: "formly-field-checkbox", usesInheritance: true, ngImport: i0, template: `
2133
+ <div class="checkbox-container">
2134
+ <p-checkbox
2135
+ [formControl]="$any(formControl)"
2136
+ [formlyAttributes]="field"
2137
+ [binary]="!props['options']"
2138
+ [trueValue]="props['trueValue']"
2139
+ [falseValue]="props['falseValue']">
2140
+ {{props['checkboxLabel'] || ''}}
2141
+ </p-checkbox>
2142
+ </div>
2143
+ `, isInline: true, styles: [".checkbox-container{display:flex;align-items:center;height:40px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i3$3.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }] });
2144
+ }
2145
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CheckboxType, decorators: [{
2146
+ type: Component,
2147
+ args: [{ selector: 'formly-field-checkbox', standalone: true, imports: [
2148
+ CommonModule,
2149
+ ReactiveFormsModule,
2150
+ FormlyModule,
2151
+ CheckboxModule
2152
+ ], template: `
2153
+ <div class="checkbox-container">
2154
+ <p-checkbox
2155
+ [formControl]="$any(formControl)"
2156
+ [formlyAttributes]="field"
2157
+ [binary]="!props['options']"
2158
+ [trueValue]="props['trueValue']"
2159
+ [falseValue]="props['falseValue']">
2160
+ {{props['checkboxLabel'] || ''}}
2161
+ </p-checkbox>
2162
+ </div>
2163
+ `, styles: [".checkbox-container{display:flex;align-items:center;height:40px}\n"] }]
2164
+ }] });
2165
+
2166
+ class TextareaType extends FieldType {
2167
+ defaultOptions = {
2168
+ props: {
2169
+ rows: 3,
2170
+ cols: undefined,
2171
+ autoResize: true,
2172
+ placeholder: ''
2173
+ }
2174
+ };
2175
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextareaType, deps: null, target: i0.ɵɵFactoryTarget.Component });
2176
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: TextareaType, isStandalone: true, selector: "formly-field-textarea", usesInheritance: true, ngImport: i0, template: `
2177
+ <textarea pInputTextarea
2178
+ [formControl]="$any(formControl)"
2179
+ [formlyAttributes]="field"
2180
+ [rows]="props['rows'] || 3"
2181
+ [cols]="props['cols']"
2182
+ [autoResize]="props['autoResize']"
2183
+ [placeholder]="props['placeholder'] || ''"
2184
+ class="w-full">
2185
+ </textarea>
2186
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormlyModule }, { kind: "directive", type: i2.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }, { kind: "ngmodule", type: Textarea }, { kind: "directive", type: i3$4.InputTextarea, selector: "[pInputTextarea]", inputs: ["autoResize", "variant", "fluid"], outputs: ["onResize"] }] });
2187
+ }
2188
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: TextareaType, decorators: [{
2189
+ type: Component,
2190
+ args: [{
2191
+ selector: 'formly-field-textarea',
2192
+ standalone: true,
2193
+ imports: [
2194
+ CommonModule,
2195
+ ReactiveFormsModule,
2196
+ FormlyModule,
2197
+ Textarea
2198
+ ],
2199
+ template: `
2200
+ <textarea pInputTextarea
2201
+ [formControl]="$any(formControl)"
2202
+ [formlyAttributes]="field"
2203
+ [rows]="props['rows'] || 3"
2204
+ [cols]="props['cols']"
2205
+ [autoResize]="props['autoResize']"
2206
+ [placeholder]="props['placeholder'] || ''"
2207
+ class="w-full">
2208
+ </textarea>
2209
+ `
2210
+ }]
2211
+ }] });
2212
+
2213
+ class FormFieldWrapper extends FieldWrapper {
2214
+ get errorMessage() {
2215
+ if (!this.field.formControl?.errors) {
2216
+ return '';
2217
+ }
2218
+ const firstErrorKey = Object.keys(this.field.formControl.errors)[0];
2219
+ return this.props.validation?.messages?.[firstErrorKey] || 'This field is required';
2220
+ }
2221
+ get showError() {
2222
+ if (!this.field.formControl) {
2223
+ return false;
2224
+ }
2225
+ const { touched, dirty, invalid } = this.field.formControl;
2226
+ return invalid && (touched || dirty);
2227
+ }
2228
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormFieldWrapper, deps: null, target: i0.ɵɵFactoryTarget.Component });
2229
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.4", type: FormFieldWrapper, isStandalone: true, selector: "formly-wrapper-form-field", usesInheritance: true, ngImport: i0, template: `
2230
+ <div class="field mb-4">
2231
+ <label *ngIf="props.label" [for]="id" class="font-medium">
2232
+ {{ props.label }}
2233
+ <span class="required-star" *ngIf="props.required">*</span>
2234
+ <i *ngIf="props.tooltip"
2235
+ class="pi pi-info-circle ml-2"
2236
+ [pTooltip]="props.tooltip">
2237
+ </i>
2238
+ </label>
2239
+
2240
+ <div [class.p-input-error]="showError">
2241
+ <ng-container #fieldComponent></ng-container>
2242
+ </div>
2243
+
2244
+ <small *ngIf="props.description" class="block mt-1">
2245
+ {{ props.description }}
2246
+ </small>
2247
+
2248
+ <small *ngIf="showError" class="p-error block">
2249
+ <i class="pi pi-exclamation-circle mr-2"></i>
2250
+ {{ errorMessage }}
2251
+ </small>
2252
+ </div>
2253
+ `, isInline: true, styles: [":is() .required-star{color:var(--red-500);margin-left:.25rem}:is() .p-input-error :where(input,.p-inputtext){border-color:var(--red-500)}:is() .p-input-error :where(input:enabled:focus,.p-inputtext:enabled:focus){border-color:var(--red-500);box-shadow:0 0 0 1px var(--red-500)}:is() .p-error{color:var(--red-500);margin-top:.5rem}:is() small{color:var(--text-color-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] });
2254
+ }
2255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: FormFieldWrapper, decorators: [{
2256
+ type: Component,
2257
+ args: [{ selector: 'formly-wrapper-form-field', standalone: true, imports: [CommonModule, TooltipModule], template: `
2258
+ <div class="field mb-4">
2259
+ <label *ngIf="props.label" [for]="id" class="font-medium">
2260
+ {{ props.label }}
2261
+ <span class="required-star" *ngIf="props.required">*</span>
2262
+ <i *ngIf="props.tooltip"
2263
+ class="pi pi-info-circle ml-2"
2264
+ [pTooltip]="props.tooltip">
2265
+ </i>
2266
+ </label>
2267
+
2268
+ <div [class.p-input-error]="showError">
2269
+ <ng-container #fieldComponent></ng-container>
2270
+ </div>
2271
+
2272
+ <small *ngIf="props.description" class="block mt-1">
2273
+ {{ props.description }}
2274
+ </small>
2275
+
2276
+ <small *ngIf="showError" class="p-error block">
2277
+ <i class="pi pi-exclamation-circle mr-2"></i>
2278
+ {{ errorMessage }}
2279
+ </small>
2280
+ </div>
2281
+ `, styles: [":is() .required-star{color:var(--red-500);margin-left:.25rem}:is() .p-input-error :where(input,.p-inputtext){border-color:var(--red-500)}:is() .p-input-error :where(input:enabled:focus,.p-inputtext:enabled:focus){border-color:var(--red-500);box-shadow:0 0 0 1px var(--red-500)}:is() .p-error{color:var(--red-500);margin-top:.5rem}:is() small{color:var(--text-color-secondary)}\n"] }]
2282
+ }] });
2283
+
2284
+ const FORMLY_TYPES = {
2285
+ TEXT: 'text',
2286
+ NUMBER: 'number',
2287
+ DATE: 'date',
2288
+ CHECKBOX: 'checkbox',
2289
+ RADIO: 'radio',
2290
+ SELECT: 'select',
2291
+ MULTISELECT: 'multiselect',
2292
+ TEXTAREA: 'textarea'
2293
+ };
2294
+ const FORMLY_WRAPPERS = {
2295
+ FORM_FIELD: 'form-field'
2296
+ };
2297
+
2298
+ class CoreFormlyModule {
2299
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoreFormlyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2300
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.4", ngImport: i0, type: CoreFormlyModule, imports: [i2.FormlyModule], exports: [FormlyModule] });
2301
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoreFormlyModule, imports: [FormlyModule.forRoot({
2302
+ types: [
2303
+ { name: FORMLY_TYPES.TEXT, component: TextInputType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2304
+ { name: FORMLY_TYPES.NUMBER, component: NumericInputType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2305
+ { name: FORMLY_TYPES.DATE, component: DateType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2306
+ { name: FORMLY_TYPES.CHECKBOX, component: CheckboxType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2307
+ { name: FORMLY_TYPES.RADIO, component: RadioType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2308
+ { name: FORMLY_TYPES.SELECT, component: SelectType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2309
+ { name: FORMLY_TYPES.MULTISELECT, component: MultiselectType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2310
+ { name: FORMLY_TYPES.TEXTAREA, component: TextareaType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] }, // Added textarea type
2311
+ ],
2312
+ wrappers: [
2313
+ { name: FORMLY_WRAPPERS.FORM_FIELD, component: FormFieldWrapper }
2314
+ ]
2315
+ }), FormlyModule] });
2316
+ }
2317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.4", ngImport: i0, type: CoreFormlyModule, decorators: [{
2318
+ type: NgModule,
2319
+ args: [{
2320
+ imports: [
2321
+ FormlyModule.forRoot({
2322
+ types: [
2323
+ { name: FORMLY_TYPES.TEXT, component: TextInputType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2324
+ { name: FORMLY_TYPES.NUMBER, component: NumericInputType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2325
+ { name: FORMLY_TYPES.DATE, component: DateType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2326
+ { name: FORMLY_TYPES.CHECKBOX, component: CheckboxType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2327
+ { name: FORMLY_TYPES.RADIO, component: RadioType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2328
+ { name: FORMLY_TYPES.SELECT, component: SelectType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2329
+ { name: FORMLY_TYPES.MULTISELECT, component: MultiselectType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] },
2330
+ { name: FORMLY_TYPES.TEXTAREA, component: TextareaType, wrappers: [FORMLY_WRAPPERS.FORM_FIELD] }, // Added textarea type
2331
+ ],
2332
+ wrappers: [
2333
+ { name: FORMLY_WRAPPERS.FORM_FIELD, component: FormFieldWrapper }
2334
+ ]
2335
+ })
2336
+ ],
2337
+ exports: [FormlyModule]
2338
+ }]
2339
+ }] });
2340
+
2341
+ // Config
2342
+ // Services
2343
+
2344
+ /**
2345
+ * Generated bundle index. Do not edit.
2346
+ */
2347
+
2348
+ export { AppConstants, AppMessages, BaseCrudService, BaseFormComponent, BaseListPageComponent, BasePageComponent, BaseTabbedFormComponent, CheckboxType, ComponentContext, CoreFormlyModule, DateType, EntityRegistryService, EnumRegistryService, FormFieldWrapper, FormlyConfigService, HttpUtilityService, IndianDatePipe, MultiselectType, NotificationService, NumericInputType, RadioType, ReferenceDataProviderService, SelectType, TabbedFormType, TextInputType, UtilsService };
2349
+ //# sourceMappingURL=core-lib.mjs.map