@winexist/ngp 0.7.1 → 0.7.2

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 (60) hide show
  1. package/fesm2022/winexist-ngp.mjs +1102 -0
  2. package/fesm2022/winexist-ngp.mjs.map +1 -0
  3. package/index.d.ts +396 -0
  4. package/package.json +16 -2
  5. package/.storybook/main.ts +0 -22
  6. package/.storybook/preview.ts +0 -0
  7. package/.storybook/tsconfig.json +0 -16
  8. package/doctor-storybook.log +0 -13
  9. package/eslint.config.mjs +0 -44
  10. package/jest.config.ts +0 -21
  11. package/migration-storybook.log +0 -108
  12. package/ng-package.json +0 -7
  13. package/project.json +0 -107
  14. package/src/index.ts +0 -21
  15. package/src/lib/classes/crud-abstract.class.ts +0 -325
  16. package/src/lib/components/dataview/table/data-table.component.html +0 -195
  17. package/src/lib/components/dataview/table/data-table.component.scss +0 -0
  18. package/src/lib/components/dataview/table/data-table.component.spec.ts +0 -21
  19. package/src/lib/components/dataview/table/data-table.component.ts +0 -177
  20. package/src/lib/components/empty/empty.component.css +0 -0
  21. package/src/lib/components/empty/empty.component.html +0 -18
  22. package/src/lib/components/empty/empty.component.spec.ts +0 -21
  23. package/src/lib/components/empty/empty.component.ts +0 -14
  24. package/src/lib/components/fg-address/fg-address.component.html +0 -142
  25. package/src/lib/components/fg-address/fg-address.component.scss +0 -0
  26. package/src/lib/components/fg-address/fg-address.component.spec.ts +0 -21
  27. package/src/lib/components/fg-address/fg-address.component.ts +0 -302
  28. package/src/lib/components/file-upload/file-upload.component.css +0 -0
  29. package/src/lib/components/file-upload/file-upload.component.html +0 -41
  30. package/src/lib/components/file-upload/file-upload.component.spec.ts +0 -21
  31. package/src/lib/components/file-upload/file-upload.component.ts +0 -115
  32. package/src/lib/components/form-field-wrapper/form-field-wrapper.component.html +0 -7
  33. package/src/lib/components/form-field-wrapper/form-field-wrapper.component.scss +0 -28
  34. package/src/lib/components/form-field-wrapper/form-field-wrapper.component.spec.ts +0 -21
  35. package/src/lib/components/form-field-wrapper/form-field-wrapper.component.ts +0 -65
  36. package/src/lib/components/select/ng-select/basic/basic-ng-select.component.html +0 -18
  37. package/src/lib/components/select/ng-select/basic/basic-ng-select.component.scss +0 -0
  38. package/src/lib/components/select/ng-select/basic/basic-ng-select.component.spec.ts +0 -21
  39. package/src/lib/components/select/ng-select/basic/basic-ng-select.component.ts +0 -88
  40. package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.html +0 -7
  41. package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.scss +0 -0
  42. package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.spec.ts +0 -21
  43. package/src/lib/components/select/ng-select/dynamic/dynamic-select.component.ts +0 -122
  44. package/src/lib/components.css +0 -0
  45. package/src/lib/components.html +0 -1
  46. package/src/lib/components.spec.ts +0 -21
  47. package/src/lib/components.stories.ts +0 -24
  48. package/src/lib/components.ts +0 -9
  49. package/src/lib/models/address.model.ts +0 -31
  50. package/src/lib/models/common.model.ts +0 -4
  51. package/src/lib/models/paginated.model.ts +0 -14
  52. package/src/lib/models/table-column.model.ts +0 -10
  53. package/src/lib/services/address/address.service.spec.ts +0 -16
  54. package/src/lib/services/address/address.service.ts +0 -24
  55. package/src/lib/types/api-operations.type.ts +0 -22
  56. package/src/test-setup.ts +0 -6
  57. package/tsconfig.json +0 -31
  58. package/tsconfig.lib.json +0 -21
  59. package/tsconfig.lib.prod.json +0 -9
  60. package/tsconfig.spec.json +0 -12
@@ -0,0 +1,1102 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, Component, output, signal, effect, ViewChild, ContentChild, Input, forwardRef, inject, Injectable, computed, Injector, untracked } from '@angular/core';
3
+ import * as i3 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i1 from 'primeng/fileupload';
6
+ import { FileUploadModule } from 'primeng/fileupload';
7
+ import * as i4 from '@angular/forms';
8
+ import { NgControl, FormsModule, NG_VALUE_ACCESSOR, FormBuilder, ReactiveFormsModule, NG_VALIDATORS } from '@angular/forms';
9
+ import * as i1$1 from 'primeng/message';
10
+ import { MessageModule } from 'primeng/message';
11
+ import * as i1$2 from '@ng-select/ng-select';
12
+ import { NgSelectModule } from '@ng-select/ng-select';
13
+ import * as i3$1 from 'primeng/floatlabel';
14
+ import { FloatLabelModule } from 'primeng/floatlabel';
15
+ import * as i5 from 'primeng/progressspinner';
16
+ import { ProgressSpinnerModule } from 'primeng/progressspinner';
17
+ import { RxwebValidators } from '@rxweb/reactive-form-validators';
18
+ import * as i1$3 from 'primeng/inputtext';
19
+ import { InputTextModule } from 'primeng/inputtext';
20
+ import * as i2 from 'primeng/inputnumber';
21
+ import { InputNumberModule } from 'primeng/inputnumber';
22
+ import { HttpClient } from '@angular/common/http';
23
+ import * as i3$2 from 'primeng/api';
24
+ import { ConfirmationService, MessageService } from 'primeng/api';
25
+ import * as i4$1 from 'primeng/button';
26
+ import { ButtonModule } from 'primeng/button';
27
+ import { ConfirmDialogModule } from 'primeng/confirmdialog';
28
+ import { DialogModule } from 'primeng/dialog';
29
+ import * as i6 from 'primeng/popover';
30
+ import { PopoverModule } from 'primeng/popover';
31
+ import * as i5$1 from 'primeng/skeleton';
32
+ import { SkeletonModule } from 'primeng/skeleton';
33
+ import * as i2$1 from 'primeng/table';
34
+ import { TableModule } from 'primeng/table';
35
+ import { ToastModule } from 'primeng/toast';
36
+ import { ToolbarModule } from 'primeng/toolbar';
37
+ import { TooltipModule } from 'primeng/tooltip';
38
+ import { tap } from 'rxjs/operators';
39
+ import { __decorate } from 'tslib';
40
+ import { shareReplay, catchError, of, finalize } from 'rxjs';
41
+ import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
42
+
43
+ class EmptyComponent {
44
+ title = input('Section is empty.', ...(ngDevMode ? [{ debugName: "title" }] : []));
45
+ message = input('No data available.', ...(ngDevMode ? [{ debugName: "message" }] : []));
46
+ imgSrc = input(...(ngDevMode ? [undefined, { debugName: "imgSrc" }] : []));
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
48
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: EmptyComponent, isStandalone: true, selector: "ngp-empty", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, imgSrc: { classPropertyName: "imgSrc", publicName: "imgSrc", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"w-full flex justify-center items-center p-5 h-full\">\n <div class=\"flex items-center gap-3\">\n @if (imgSrc()) {\n <img alt=\"Empty\" [src]=\"imgSrc()\" class=\"w-[80px]\" />\n } @else {\n <div class=\"!rounded-md p-5 !bg-slate-100 mb-6\">\n <span class=\"material-icons !text-gray-400 !text-7xl\"> search_off </span>\n </div>\n }\n\n <div class=\"flex flex-col\">\n <span class=\"!text-gray-900 !text-2xl !font-bold\">{{ title() }}</span>\n @if (message()) {\n <span class=\"!text-gray-400 !text-base\">{{ message() }}</span>\n }\n </div>\n </div>\n</div>", styles: [""] });
49
+ }
50
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EmptyComponent, decorators: [{
51
+ type: Component,
52
+ args: [{ selector: 'ngp-empty', imports: [], template: "<div class=\"w-full flex justify-center items-center p-5 h-full\">\n <div class=\"flex items-center gap-3\">\n @if (imgSrc()) {\n <img alt=\"Empty\" [src]=\"imgSrc()\" class=\"w-[80px]\" />\n } @else {\n <div class=\"!rounded-md p-5 !bg-slate-100 mb-6\">\n <span class=\"material-icons !text-gray-400 !text-7xl\"> search_off </span>\n </div>\n }\n\n <div class=\"flex flex-col\">\n <span class=\"!text-gray-900 !text-2xl !font-bold\">{{ title() }}</span>\n @if (message()) {\n <span class=\"!text-gray-400 !text-base\">{{ message() }}</span>\n }\n </div>\n </div>\n</div>" }]
53
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], imgSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgSrc", required: false }] }] } });
54
+
55
+ class FileUploadComponent {
56
+ fileUploader;
57
+ // Signal-based inputs with defaults
58
+ files = input([], ...(ngDevMode ? [{ debugName: "files" }] : []));
59
+ multiple = input(true, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
60
+ accept = input('.pdf,.png,.jpg,.jpeg,.doc,.docx,.csv,.xls,.xlsx', ...(ngDevMode ? [{ debugName: "accept" }] : []));
61
+ maxFileSize = input(2097152, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : [])); // 2MB in bytes
62
+ placeholder = input('Drag and drop new files here to upload.', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
63
+ showUploadButton = input(false, ...(ngDevMode ? [{ debugName: "showUploadButton" }] : []));
64
+ cancelLabel = input('Clear', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : []));
65
+ // Signal-based outputs
66
+ filesSelected = output();
67
+ filesCleared = output();
68
+ // Internal state
69
+ uploadedFiles = signal([], ...(ngDevMode ? [{ debugName: "uploadedFiles" }] : []));
70
+ constructor() {
71
+ effect(() => {
72
+ const _files = this.files();
73
+ if (_files.length) {
74
+ this.uploadedFiles.set(_files.map((file) => this.addFileType(file)));
75
+ }
76
+ });
77
+ }
78
+ onFileSelect(event) {
79
+ const validFiles = event.currentFiles.filter((file) => file.size <= this.maxFileSize() && this.isValidFileType(file));
80
+ if (validFiles.length) {
81
+ // Add type to files before adding to uploadedFiles
82
+ const typedFiles = validFiles.map((file) => this.addFileType(file));
83
+ if (this.multiple()) {
84
+ this.uploadedFiles.update((files) => Array.from(new Set([...files, ...typedFiles])));
85
+ }
86
+ else {
87
+ this.uploadedFiles.set(typedFiles);
88
+ }
89
+ this.filesSelected.emit(typedFiles);
90
+ }
91
+ }
92
+ onClear() {
93
+ this.uploadedFiles.set([]);
94
+ this.filesCleared.emit();
95
+ }
96
+ removeFile(index) {
97
+ this.uploadedFiles.update((files) => files.filter((_, i) => i !== index));
98
+ this.filesSelected.emit(this.uploadedFiles());
99
+ }
100
+ isValidFileType(file) {
101
+ const acceptedTypes = this.accept().split(',');
102
+ return acceptedTypes.some((type) => file.name.toLowerCase().endsWith(type.trim().toLowerCase()));
103
+ }
104
+ formatFileSize(bytes) {
105
+ if (bytes === 0)
106
+ return '0 Bytes';
107
+ const k = 1024;
108
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
109
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
110
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
111
+ }
112
+ clear() {
113
+ this.uploadedFiles.set([]);
114
+ if (this.fileUploader?.nativeElement?.clear) {
115
+ this.fileUploader.nativeElement.clear();
116
+ }
117
+ }
118
+ // Function to determine file type based on extension
119
+ getFileTypeByExtension(file) {
120
+ const fileName = file.name.toLowerCase();
121
+ const imageExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg', '.webp'];
122
+ const pdfExtension = '.pdf';
123
+ if (imageExtensions.some((ext) => fileName.endsWith(ext))) {
124
+ return 'image';
125
+ }
126
+ else if (fileName.endsWith(pdfExtension)) {
127
+ return 'pdf';
128
+ }
129
+ else {
130
+ return 'other';
131
+ }
132
+ }
133
+ // Function to add type property to file
134
+ addFileType(file) {
135
+ const typedFile = file;
136
+ typedFile.fileType = this.getFileTypeByExtension(file);
137
+ return typedFile;
138
+ }
139
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
140
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FileUploadComponent, isStandalone: true, selector: "ngp-file-upload", inputs: { files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showUploadButton: { classPropertyName: "showUploadButton", publicName: "showUploadButton", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesSelected: "filesSelected", filesCleared: "filesCleared" }, viewQueries: [{ propertyName: "fileUploader", first: true, predicate: ["fileUploader"], descendants: true }], ngImport: i0, template: "<p-fileupload #fileUploader [multiple]=\"multiple()\" [showUploadButton]=\"showUploadButton()\"\n [cancelLabel]=\"cancelLabel()\" [accept]=\"accept()\" auto=\"false\" [maxFileSize]=\"maxFileSize()\" mode=\"advanced\"\n [customUpload]=\"true\" styleClass=\"!bg-gray-50\" (onSelect)=\"onFileSelect($event)\" (onClear)=\"onClear()\">\n <ng-template #content>\n @if (uploadedFiles().length) {\n <ul class=\"space-y-2\">\n @for (file of uploadedFiles(); track $index) {\n <li class=\"flex justify-between gap-4 p-2 bg-gray-100 rounded\">\n <div class=\"flex gap-2\">\n <ng-container [ngTemplateOutlet]=\"iconTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: file.fileType }\"></ng-container>\n <span class=\"text-sm\"> {{ file.name }} - {{ formatFileSize(file.size) }} </span>\n </div>\n <button type=\"button\" (click)=\"removeFile($index)\" class=\"text-red-500 hover:text-red-700 text-sm\">\n <span class=\"material-icons !text-base\"> cancel </span>\n </button>\n </li>\n }\n </ul>\n } @else {\n <div class=\"flex flex-col items-center gap-3\">\n <img src=\"assets/images/file-upload.svg\" alt=\"File Upload\" class=\"w-28 mx-auto\" />\n <span class=\"font-semibold text-center text-gray-400 text-sm\">\n Drag & drop or<br />\n click the \"Choose\" button to add new files\n </span>\n </div>\n }\n </ng-template>\n <ng-template #file></ng-template>\n</p-fileupload>\n\n<ng-template #iconTemplate let-type>\n @if (type === 'image') {\n <span class=\"material-icons\"> image </span>\n } @else if (type === 'pdf') {\n <span class=\"material-icons\"> picture_as_pdf </span>\n } @else {\n <span class=\"material-icons\"> insert_drive_file </span>\n }\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i1.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
141
+ }
142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileUploadComponent, decorators: [{
143
+ type: Component,
144
+ args: [{ selector: 'ngp-file-upload', imports: [FileUploadModule, CommonModule], template: "<p-fileupload #fileUploader [multiple]=\"multiple()\" [showUploadButton]=\"showUploadButton()\"\n [cancelLabel]=\"cancelLabel()\" [accept]=\"accept()\" auto=\"false\" [maxFileSize]=\"maxFileSize()\" mode=\"advanced\"\n [customUpload]=\"true\" styleClass=\"!bg-gray-50\" (onSelect)=\"onFileSelect($event)\" (onClear)=\"onClear()\">\n <ng-template #content>\n @if (uploadedFiles().length) {\n <ul class=\"space-y-2\">\n @for (file of uploadedFiles(); track $index) {\n <li class=\"flex justify-between gap-4 p-2 bg-gray-100 rounded\">\n <div class=\"flex gap-2\">\n <ng-container [ngTemplateOutlet]=\"iconTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: file.fileType }\"></ng-container>\n <span class=\"text-sm\"> {{ file.name }} - {{ formatFileSize(file.size) }} </span>\n </div>\n <button type=\"button\" (click)=\"removeFile($index)\" class=\"text-red-500 hover:text-red-700 text-sm\">\n <span class=\"material-icons !text-base\"> cancel </span>\n </button>\n </li>\n }\n </ul>\n } @else {\n <div class=\"flex flex-col items-center gap-3\">\n <img src=\"assets/images/file-upload.svg\" alt=\"File Upload\" class=\"w-28 mx-auto\" />\n <span class=\"font-semibold text-center text-gray-400 text-sm\">\n Drag & drop or<br />\n click the \"Choose\" button to add new files\n </span>\n </div>\n }\n </ng-template>\n <ng-template #file></ng-template>\n</p-fileupload>\n\n<ng-template #iconTemplate let-type>\n @if (type === 'image') {\n <span class=\"material-icons\"> image </span>\n } @else if (type === 'pdf') {\n <span class=\"material-icons\"> picture_as_pdf </span>\n } @else {\n <span class=\"material-icons\"> insert_drive_file </span>\n }\n</ng-template>" }]
145
+ }], ctorParameters: () => [], propDecorators: { fileUploader: [{
146
+ type: ViewChild,
147
+ args: ['fileUploader']
148
+ }], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showUploadButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUploadButton", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], filesCleared: [{ type: i0.Output, args: ["filesCleared"] }] } });
149
+
150
+ // form-field-wrapper.component.ts
151
+ class FormFieldWrapperComponent {
152
+ validationMessages = {
153
+ required: 'This field is required',
154
+ email: 'Please enter a valid email',
155
+ minlength: 'Input does not meet minimum length',
156
+ maxlength: 'Input exceeds maximum length',
157
+ pattern: 'Input format is invalid',
158
+ endTimeBeforeStartTime: 'End time must not be before start time',
159
+ breakStartBeforeEarliestStart: 'Break start time cannot be before the earliest start time'
160
+ };
161
+ control;
162
+ subscription;
163
+ ngAfterContentInit() {
164
+ if (this.control) {
165
+ this.subscription = this.control.statusChanges?.subscribe(() => { });
166
+ }
167
+ }
168
+ ngOnDestroy() {
169
+ this.subscription?.unsubscribe();
170
+ }
171
+ shouldShowError() {
172
+ return (!!this.control &&
173
+ this.control.invalid === true &&
174
+ (this.control.dirty === true || this.control.touched === true));
175
+ }
176
+ getErrorMessage() {
177
+ if (!this.control?.errors) {
178
+ return '';
179
+ }
180
+ const firstErrorKey = Object.keys(this.control.errors)[0];
181
+ const error = this.control.errors[firstErrorKey];
182
+ if (this.control.errors['message']) {
183
+ return this.control.errors['message'];
184
+ }
185
+ if (error?.message) {
186
+ return error.message;
187
+ }
188
+ return this.validationMessages[firstErrorKey] || `Invalid input: ${firstErrorKey}`;
189
+ }
190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
191
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FormFieldWrapperComponent, isStandalone: true, selector: "ngp-form-field-wrapper", inputs: { validationMessages: "validationMessages" }, queries: [{ propertyName: "control", first: true, predicate: NgControl, descendants: true }], ngImport: i0, template: "<div class=\"form-field-container\">\n <ng-content></ng-content>\n @if (shouldShowError()) {\n <p-message severity=\"error\" variant=\"simple\" size=\"small\" [text]=\"getErrorMessage()\">\n </p-message>\n }\n</div>", styles: [":host{display:block;margin-bottom:1rem}.form-field-container{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ng-invalid.ng-touched,:host ::ng-deep .ng-invalid.ng-dirty{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched input,:host ::ng-deep .ng-invalid.ng-dirty input{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched .ng-select-container,:host ::ng-deep .ng-invalid.ng-dirty .ng-select-container{border-color:#f44336!important;outline-color:#f44336!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MessageModule }, { kind: "component", type: i1$1.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }] });
192
+ }
193
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldWrapperComponent, decorators: [{
194
+ type: Component,
195
+ args: [{ selector: 'ngp-form-field-wrapper', standalone: true, imports: [CommonModule, MessageModule], template: "<div class=\"form-field-container\">\n <ng-content></ng-content>\n @if (shouldShowError()) {\n <p-message severity=\"error\" variant=\"simple\" size=\"small\" [text]=\"getErrorMessage()\">\n </p-message>\n }\n</div>", styles: [":host{display:block;margin-bottom:1rem}.form-field-container{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ng-invalid.ng-touched,:host ::ng-deep .ng-invalid.ng-dirty{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched input,:host ::ng-deep .ng-invalid.ng-dirty input{border-color:#f44336!important;outline-color:#f44336!important}:host ::ng-deep .ng-invalid.ng-touched .ng-select-container,:host ::ng-deep .ng-invalid.ng-dirty .ng-select-container{border-color:#f44336!important;outline-color:#f44336!important}\n"] }]
196
+ }], propDecorators: { validationMessages: [{
197
+ type: Input
198
+ }], control: [{
199
+ type: ContentChild,
200
+ args: [NgControl]
201
+ }] } });
202
+
203
+ class BasicNgSelectComponent {
204
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
205
+ bindLabel = input('', ...(ngDevMode ? [{ debugName: "bindLabel" }] : []));
206
+ bindValue = input('', ...(ngDevMode ? [{ debugName: "bindValue" }] : []));
207
+ placeholder = input('Select an option', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
208
+ clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
209
+ searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
210
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
211
+ label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : []));
212
+ required = input(true, ...(ngDevMode ? [{ debugName: "required" }] : []));
213
+ // Internal state
214
+ value = null;
215
+ disabled = false;
216
+ // ControlValueAccessor callbacks
217
+ onChange = () => { };
218
+ onTouched = () => { };
219
+ // Handle value changes from ng-select
220
+ onValueChange(value) {
221
+ this.value = value;
222
+ this.onChange(value);
223
+ }
224
+ writeValue(val) {
225
+ this.value = val;
226
+ }
227
+ registerOnChange(fn) {
228
+ this.onChange = fn;
229
+ }
230
+ registerOnTouched(fn) {
231
+ this.onTouched = fn;
232
+ }
233
+ setDisabledState(isDisabled) {
234
+ this.disabled = isDisabled;
235
+ }
236
+ // Compare function for ng-select
237
+ compareWith = (item, selected) => {
238
+ const bindValueKey = this.bindValue();
239
+ // If no bindValue is set, compare entire objects
240
+ if (!bindValueKey) {
241
+ return item === selected;
242
+ }
243
+ // Handle null/undefined cases
244
+ if (!item || !selected) {
245
+ return item === selected;
246
+ }
247
+ // If selected is a primitive (just the id), compare with item's property
248
+ if (typeof selected !== 'object') {
249
+ return item[bindValueKey] === selected;
250
+ }
251
+ // If both are objects, compare the bindValue property
252
+ return item[bindValueKey] === selected[bindValueKey];
253
+ };
254
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BasicNgSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
255
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: BasicNgSelectComponent, isStandalone: true, selector: "ngp-basic-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, bindLabel: { classPropertyName: "bindLabel", publicName: "bindLabel", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
256
+ {
257
+ provide: NG_VALUE_ACCESSOR,
258
+ useExisting: forwardRef(() => BasicNgSelectComponent),
259
+ multi: true
260
+ }
261
+ ], ngImport: i0, template: "<ngp-form-field-wrapper>\n <p-floatlabel variant=\"in\">\n <ng-select [(ngModel)]=\"value\" [bindLabel]=\"bindLabel()\" [bindValue]=\"bindValue()\" [items]=\"options()\"\n [compareWith]=\"compareWith\" [clearable]=\"clearable()\" (change)=\"onValueChange($event)\">\n <ng-template ng-loadingspinner-tmp>\n <ng-container [ngTemplateOutlet]=\"spinner\" />\n </ng-template>\n </ng-select>\n\n @if (label()) {\n <label class=\"block mb-2\" [ngClass]=\"{'required-label': required() }\">{{ label() }}</label>\n }\n </p-floatlabel>\n</ngp-form-field-wrapper>\n\n<ng-template #spinner>\n <p-progress-spinner ariaLabel=\"loading\" styleClass=\"text-gray-400\" />\n</ng-template>", styles: [""], dependencies: [{ kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }, { kind: "directive", type: i1$2.NgLoadingSpinnerTemplateDirective, selector: "[ng-loadingspinner-tmp]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "ngp-form-field-wrapper", inputs: ["validationMessages"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i5.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
262
+ }
263
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: BasicNgSelectComponent, decorators: [{
264
+ type: Component,
265
+ args: [{ selector: 'ngp-basic-select', imports: [NgSelectModule, FormsModule, CommonModule, FormFieldWrapperComponent, FloatLabelModule, ProgressSpinnerModule], providers: [
266
+ {
267
+ provide: NG_VALUE_ACCESSOR,
268
+ useExisting: forwardRef(() => BasicNgSelectComponent),
269
+ multi: true
270
+ }
271
+ ], template: "<ngp-form-field-wrapper>\n <p-floatlabel variant=\"in\">\n <ng-select [(ngModel)]=\"value\" [bindLabel]=\"bindLabel()\" [bindValue]=\"bindValue()\" [items]=\"options()\"\n [compareWith]=\"compareWith\" [clearable]=\"clearable()\" (change)=\"onValueChange($event)\">\n <ng-template ng-loadingspinner-tmp>\n <ng-container [ngTemplateOutlet]=\"spinner\" />\n </ng-template>\n </ng-select>\n\n @if (label()) {\n <label class=\"block mb-2\" [ngClass]=\"{'required-label': required() }\">{{ label() }}</label>\n }\n </p-floatlabel>\n</ngp-form-field-wrapper>\n\n<ng-template #spinner>\n <p-progress-spinner ariaLabel=\"loading\" styleClass=\"text-gray-400\" />\n</ng-template>" }]
272
+ }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], bindLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindLabel", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }] } });
273
+
274
+ class AddressService {
275
+ url = `/api/v1/records/address`;
276
+ http = inject(HttpClient);
277
+ getProvinces() {
278
+ return this.http.get(`${this.url}/provinces`);
279
+ }
280
+ getMunicipalities(provinceId) {
281
+ return this.http.get(`${this.url}/municipalities/${provinceId}`);
282
+ }
283
+ getBarangays(muncipalityId, params) {
284
+ return this.http.get(`${this.url}/barangay/${muncipalityId}`, { params });
285
+ }
286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
287
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, providedIn: 'root' });
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddressService, decorators: [{
290
+ type: Injectable,
291
+ args: [{
292
+ providedIn: 'root'
293
+ }]
294
+ }] });
295
+
296
+ class FgAddressComponent {
297
+ showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
298
+ isCreateMode = input(true, ...(ngDevMode ? [{ debugName: "isCreateMode" }] : []));
299
+ isViewMode = input(false, ...(ngDevMode ? [{ debugName: "isViewMode" }] : []));
300
+ addressForm;
301
+ provHttp$;
302
+ cityHttp$;
303
+ barangayHttp$;
304
+ provinceOptions = [];
305
+ cityOptions = [];
306
+ barangayOptions = [];
307
+ isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
308
+ pendingAddress = null;
309
+ isInitializing = false;
310
+ detectedEditMode = false;
311
+ onChange = () => { };
312
+ onTouched = () => { };
313
+ addressService = inject(AddressService);
314
+ fb = inject(FormBuilder);
315
+ constructor() {
316
+ this.addressForm = this.fb.group({
317
+ line1: [null, RxwebValidators.required()],
318
+ line2: [null],
319
+ barangay: [null, RxwebValidators.required()],
320
+ city: [null, RxwebValidators.required()],
321
+ province: [null, RxwebValidators.required()],
322
+ country: ['Philippines', RxwebValidators.required()],
323
+ zipCode: [null, RxwebValidators.required()],
324
+ landmark: [null, RxwebValidators.required()]
325
+ });
326
+ // Use effect to watch for form value changes
327
+ effect(() => {
328
+ if (this.isDisabled()) {
329
+ this.addressForm.disable({ emitEvent: false });
330
+ }
331
+ else {
332
+ this.addressForm.enable({ emitEvent: false });
333
+ }
334
+ });
335
+ // Subscribe to form changes
336
+ this.addressForm.valueChanges.subscribe((value) => {
337
+ this.onChange(value);
338
+ this.onTouched();
339
+ });
340
+ this.loadProvince();
341
+ // Handle province changes - works for both create and edit mode
342
+ this.addressForm.get('province')?.valueChanges.subscribe((prov) => {
343
+ if (prov && !this.isInitializing) {
344
+ this.clearFieldByName('city');
345
+ this.clearFieldByName('barangay');
346
+ this.cityOptions = [];
347
+ this.barangayOptions = [];
348
+ this.loadCityByProvinceId(prov.id);
349
+ }
350
+ });
351
+ // Handle city changes - works for both create and edit mode
352
+ this.addressForm.get('city')?.valueChanges.subscribe((city) => {
353
+ if (city && !this.isInitializing) {
354
+ this.clearFieldByName('barangay');
355
+ this.barangayOptions = [];
356
+ this.loadBarangayByCityId(city.id);
357
+ }
358
+ });
359
+ }
360
+ clearFieldByName(fieldName) {
361
+ this.addressForm.get(fieldName)?.setValue(null, { emitEvent: false });
362
+ }
363
+ loadProvince() {
364
+ this.provHttp$ = this.addressService.getProvinces().subscribe((res) => {
365
+ this.provinceOptions = res;
366
+ // If we have a pending address to load, process it now
367
+ if (this.pendingAddress) {
368
+ this.initializeEditMode(this.pendingAddress);
369
+ }
370
+ });
371
+ }
372
+ loadCityByProvinceId(id) {
373
+ this.cityHttp$ = this.addressService.getMunicipalities(id).subscribe((res) => {
374
+ this.cityOptions = res;
375
+ // Continue initialization if needed
376
+ if (this.isInitializing && this.pendingAddress) {
377
+ this.setCityFromPending();
378
+ }
379
+ });
380
+ }
381
+ loadBarangayByCityId(id) {
382
+ this.barangayHttp$ = this.addressService.getBarangays(id).subscribe((res) => {
383
+ this.barangayOptions = res;
384
+ // Continue initialization if needed
385
+ if (this.isInitializing && this.pendingAddress) {
386
+ this.setBarangayFromPending();
387
+ }
388
+ });
389
+ }
390
+ /**
391
+ * Detects if the address contains data that requires edit mode initialization
392
+ */
393
+ isEditModeAddress(address) {
394
+ // Check if any cascading field (province, city, barangay) is a string (name)
395
+ // This indicates data from backend that needs to be matched with dropdown options
396
+ return ((typeof address.province === 'string' && address.province !== '') ||
397
+ (typeof address.city === 'string' && address.city !== '') ||
398
+ (typeof address.barangay === 'string' && address.barangay !== ''));
399
+ }
400
+ initializeEditMode(address) {
401
+ this.isInitializing = true;
402
+ // Set non-cascading fields first
403
+ this.addressForm.patchValue({
404
+ line1: address.line1,
405
+ line2: address.line2,
406
+ country: address.country || 'Philippines',
407
+ zipCode: address.zipCode,
408
+ landmark: address.landmark
409
+ }, { emitEvent: false });
410
+ // Find and set province
411
+ if (address.province && typeof address.province === 'string') {
412
+ const provinceItem = this.provinceOptions.find((p) => p.name.toLowerCase() === address.province?.toLowerCase());
413
+ if (provinceItem) {
414
+ this.addressForm.get('province')?.setValue(provinceItem, { emitEvent: false });
415
+ this.loadCityByProvinceId(provinceItem.id);
416
+ }
417
+ else {
418
+ this.completeInitialization();
419
+ }
420
+ }
421
+ else {
422
+ this.completeInitialization();
423
+ }
424
+ }
425
+ setCityFromPending() {
426
+ if (!this.pendingAddress?.city || typeof this.pendingAddress.city !== 'string') {
427
+ this.completeInitialization();
428
+ return;
429
+ }
430
+ const cityItem = this.cityOptions.find((c) => c.name.toLowerCase() === this.pendingAddress.city?.toLowerCase());
431
+ if (cityItem) {
432
+ this.addressForm.get('city')?.setValue(cityItem, { emitEvent: false });
433
+ this.loadBarangayByCityId(cityItem.id);
434
+ }
435
+ else {
436
+ this.completeInitialization();
437
+ }
438
+ }
439
+ setBarangayFromPending() {
440
+ if (!this.pendingAddress?.barangay || typeof this.pendingAddress.barangay !== 'string') {
441
+ this.completeInitialization();
442
+ return;
443
+ }
444
+ const barangayItem = this.barangayOptions.find((b) => b.name.toLowerCase() === this.pendingAddress.barangay?.toLowerCase());
445
+ if (barangayItem) {
446
+ this.addressForm.get('barangay')?.setValue(barangayItem, { emitEvent: false });
447
+ }
448
+ this.completeInitialization();
449
+ }
450
+ completeInitialization() {
451
+ this.isInitializing = false;
452
+ this.pendingAddress = null;
453
+ }
454
+ // ControlValueAccessor methods
455
+ writeValue(value) {
456
+ if (value) {
457
+ // Auto-detect if this is edit mode based on the address data structure
458
+ this.detectedEditMode = this.isEditModeAddress(value);
459
+ if (this.detectedEditMode) {
460
+ // Address contains string values (names) - needs initialization
461
+ this.pendingAddress = value;
462
+ // If provinces are already loaded, start initialization
463
+ if (this.provinceOptions.length > 0) {
464
+ this.initializeEditMode(value);
465
+ }
466
+ // Otherwise, it will be triggered when provinces load
467
+ }
468
+ else {
469
+ // Create mode or already has proper objects
470
+ this.addressForm.patchValue(value, { emitEvent: false });
471
+ // Load cascading data if IDs are present
472
+ const province = value.province;
473
+ if (province && typeof province === 'object' && 'id' in province) {
474
+ this.loadCityByProvinceId(province.id);
475
+ }
476
+ const city = value.city;
477
+ if (city && typeof city === 'object' && 'id' in city) {
478
+ this.loadBarangayByCityId(city.id);
479
+ }
480
+ }
481
+ }
482
+ else {
483
+ this.addressForm.reset({ country: 'Philippines' }, { emitEvent: false });
484
+ }
485
+ }
486
+ registerOnChange(fn) {
487
+ this.onChange = fn;
488
+ }
489
+ registerOnTouched(fn) {
490
+ this.onTouched = fn;
491
+ }
492
+ setDisabledState(isDisabled) {
493
+ this.isDisabled?.set(isDisabled);
494
+ if (isDisabled) {
495
+ this.addressForm.disable();
496
+ }
497
+ else {
498
+ this.addressForm.enable();
499
+ }
500
+ }
501
+ validate(control) {
502
+ return this.addressForm?.valid ? null : { invalidAddress: true };
503
+ }
504
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FgAddressComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
505
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FgAddressComponent, isStandalone: true, selector: "ngp-fg-address", inputs: { showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, isCreateMode: { classPropertyName: "isCreateMode", publicName: "isCreateMode", isSignal: true, isRequired: false, transformFunction: null }, isViewMode: { classPropertyName: "isViewMode", publicName: "isViewMode", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
506
+ {
507
+ provide: NG_VALUE_ACCESSOR,
508
+ useExisting: forwardRef(() => FgAddressComponent),
509
+ multi: true
510
+ },
511
+ {
512
+ provide: NG_VALIDATORS,
513
+ useExisting: forwardRef(() => FgAddressComponent),
514
+ multi: true
515
+ }
516
+ ], ngImport: i0, template: "@if (showHeader()) {\n\t<h2 class=\"text-xl font-semibold mb-4\">Address</h2>\n}\n\n@if (isViewMode()) {\n\t@let address = addressForm.value;\n\n\t<div class=\"grid gap-3 p-4\">\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"country\">Country:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.country || 'Philippines' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"province\">Province:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.province?.name || address.province || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"city\">City/Municipality:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.city?.name || address.city || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"barangay\">Barangay:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.barangay?.name || address.barangay || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line1\">Line 1:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line1 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line2\">Line 2:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line2 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"zipCode\">Zip Code:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.zipCode || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"landmark\">Nearest Landmark:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.landmark || '' }}</p>\n\t\t</div>\n\t</div>\n} @else {\n\t<form [formGroup]=\"addressForm\">\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"country\" formControlName=\"country\" class=\"w-full\" />\n\t\t\t\t\t\t<label for=\"country\" class=\"block mb-2 required-label\">Country</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"province\"\n\t\t\t\t\t\t\t[items]=\"provinceOptions\"\n\t\t\t\t\t\t\t[loading]=\"provHttp$ && !provHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"province\" class=\"block mb-2 required-label\">Province</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"city\"\n\t\t\t\t\t\t\t[items]=\"cityOptions\"\n\t\t\t\t\t\t\t[loading]=\"cityHttp$ && !cityHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"city\" class=\"block mb-2 required-label\">City/Municipality</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"barangay\"\n\t\t\t\t\t\t\t[items]=\"barangayOptions\"\n\t\t\t\t\t\t\t[loading]=\"barangayHttp$ && !barangayHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\n\t\t\t\t\t\t<label for=\"barangay\" class=\"block mb-2 required-label\">Barangay</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line1\" class=\"block mb-2 required-label\">Line 1</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line1\" formControlName=\"line1\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line2\" class=\"block mb-2\">Line 2</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line2\" formControlName=\"line2\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<p-inputnumber\n\t\t\t\t\t\t\t[inputId]=\"'zipCode'\"\n\t\t\t\t\t\t\tformControlName=\"zipCode\"\n\t\t\t\t\t\t\tstyleClass=\"w-full\"\n\t\t\t\t\t\t\t[useGrouping]=\"false\" />\n\t\t\t\t\t\t<label for=\"zipCode\" class=\"block mb-2 required-label\">Zip Code</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<label for=\"landmark\" class=\"block mb-2 required-label\">Nearest Landmark</label>\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"landmark\" formControlName=\"landmark\" class=\"w-full\" />\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\t</form>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i1$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i2.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "ngp-form-field-wrapper", inputs: ["validationMessages"] }, { kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }] });
517
+ }
518
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FgAddressComponent, decorators: [{
519
+ type: Component,
520
+ args: [{ selector: 'ngp-fg-address', imports: [
521
+ InputTextModule,
522
+ InputNumberModule,
523
+ FloatLabelModule,
524
+ CommonModule,
525
+ ReactiveFormsModule,
526
+ FormFieldWrapperComponent,
527
+ NgSelectModule
528
+ ], providers: [
529
+ {
530
+ provide: NG_VALUE_ACCESSOR,
531
+ useExisting: forwardRef(() => FgAddressComponent),
532
+ multi: true
533
+ },
534
+ {
535
+ provide: NG_VALIDATORS,
536
+ useExisting: forwardRef(() => FgAddressComponent),
537
+ multi: true
538
+ }
539
+ ], template: "@if (showHeader()) {\n\t<h2 class=\"text-xl font-semibold mb-4\">Address</h2>\n}\n\n@if (isViewMode()) {\n\t@let address = addressForm.value;\n\n\t<div class=\"grid gap-3 p-4\">\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"country\">Country:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.country || 'Philippines' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"province\">Province:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.province?.name || address.province || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"city\">City/Municipality:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.city?.name || address.city || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"barangay\">Barangay:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{\n\t\t\t\taddress.barangay?.name || address.barangay || ''\n\t\t\t}}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line1\">Line 1:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line1 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"line2\">Line 2:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.line2 || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between border-b border-b-slate-200 py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"zipCode\">Zip Code:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.zipCode || '' }}</p>\n\t\t</div>\n\t\t<div class=\"flex items-center justify-between py-3\">\n\t\t\t<label class=\"font-bold px-2 text-slate-400 text-sm\" for=\"landmark\">Nearest Landmark:</label>\n\t\t\t<p class=\"font-bold text-right text-slate-500\">{{ address.landmark || '' }}</p>\n\t\t</div>\n\t</div>\n} @else {\n\t<form [formGroup]=\"addressForm\">\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"country\" formControlName=\"country\" class=\"w-full\" />\n\t\t\t\t\t\t<label for=\"country\" class=\"block mb-2 required-label\">Country</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"province\"\n\t\t\t\t\t\t\t[items]=\"provinceOptions\"\n\t\t\t\t\t\t\t[loading]=\"provHttp$ && !provHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"province\" class=\"block mb-2 required-label\">Province</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"city\"\n\t\t\t\t\t\t\t[items]=\"cityOptions\"\n\t\t\t\t\t\t\t[loading]=\"cityHttp$ && !cityHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\t\t\t\t\t\t<label for=\"city\" class=\"block mb-2 required-label\">City/Municipality</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<ng-select\n\t\t\t\t\t\t\tformControlName=\"barangay\"\n\t\t\t\t\t\t\t[items]=\"barangayOptions\"\n\t\t\t\t\t\t\t[loading]=\"barangayHttp$ && !barangayHttp$.closed\"\n\t\t\t\t\t\t\tbindLabel=\"name\" />\n\n\t\t\t\t\t\t<label for=\"barangay\" class=\"block mb-2 required-label\">Barangay</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line1\" class=\"block mb-2 required-label\">Line 1</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line1\" formControlName=\"line1\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\n\t\t<div>\n\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t<label for=\"line2\" class=\"block mb-2\">Line 2</label>\n\t\t\t\t\t<input pInputText trim=\"blur\" id=\"line2\" formControlName=\"line2\" class=\"w-full\" />\n\t\t\t\t</p-floatlabel>\n\t\t\t</ngp-form-field-wrapper>\n\t\t</div>\n\t\t<div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<p-inputnumber\n\t\t\t\t\t\t\t[inputId]=\"'zipCode'\"\n\t\t\t\t\t\t\tformControlName=\"zipCode\"\n\t\t\t\t\t\t\tstyleClass=\"w-full\"\n\t\t\t\t\t\t\t[useGrouping]=\"false\" />\n\t\t\t\t\t\t<label for=\"zipCode\" class=\"block mb-2 required-label\">Zip Code</label>\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<ngp-form-field-wrapper>\n\t\t\t\t\t<p-floatlabel variant=\"in\">\n\t\t\t\t\t\t<label for=\"landmark\" class=\"block mb-2 required-label\">Nearest Landmark</label>\n\t\t\t\t\t\t<input pInputText trim=\"blur\" id=\"landmark\" formControlName=\"landmark\" class=\"w-full\" />\n\t\t\t\t\t</p-floatlabel>\n\t\t\t\t</ngp-form-field-wrapper>\n\t\t\t</div>\n\t\t</div>\n\t</form>\n}\n" }]
540
+ }], ctorParameters: () => [], propDecorators: { showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], isCreateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCreateMode", required: false }] }], isViewMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isViewMode", required: false }] }] } });
541
+
542
+ class DataTableComponent {
543
+ dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
544
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
545
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
546
+ pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
547
+ totalElements = input(0, ...(ngDevMode ? [{ debugName: "totalElements" }] : []));
548
+ currentPage = input(0, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
549
+ showDefaultActions = input(true, ...(ngDevMode ? [{ debugName: "showDefaultActions" }] : []));
550
+ emptyMessage = input('No data available.', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
551
+ hasDeleteAction = input(true, ...(ngDevMode ? [{ debugName: "hasDeleteAction" }] : []));
552
+ hasEditAction = input(true, ...(ngDevMode ? [{ debugName: "hasEditAction" }] : []));
553
+ canEdit = input(() => true, ...(ngDevMode ? [{ debugName: "canEdit" }] : []));
554
+ hasViewAction = input(true, ...(ngDevMode ? [{ debugName: "hasViewAction" }] : []));
555
+ entityName = input('', ...(ngDevMode ? [{ debugName: "entityName" }] : []));
556
+ isPaginated = input(true, ...(ngDevMode ? [{ debugName: "isPaginated" }] : []));
557
+ showCustomAction = input(false, ...(ngDevMode ? [{ debugName: "showCustomAction" }] : []));
558
+ showRowNumbers = input(false, ...(ngDevMode ? [{ debugName: "showRowNumbers" }] : []));
559
+ rowNumberHeader = input('', ...(ngDevMode ? [{ debugName: "rowNumberHeader" }] : []));
560
+ // Internal signals
561
+ data = signal([], ...(ngDevMode ? [{ debugName: "data" }] : []));
562
+ filteredData = signal([], ...(ngDevMode ? [{ debugName: "filteredData" }] : []));
563
+ dialogVisible = signal(false, ...(ngDevMode ? [{ debugName: "dialogVisible" }] : []));
564
+ dialogTitle = signal('Add Item', ...(ngDevMode ? [{ debugName: "dialogTitle" }] : []));
565
+ editingItem = signal(null, ...(ngDevMode ? [{ debugName: "editingItem" }] : []));
566
+ // Custom event emitters
567
+ add = output();
568
+ edit = output();
569
+ deleteAction = output();
570
+ view = output();
571
+ pageChange = output();
572
+ sortChange = output();
573
+ actions = computed(() => [this.hasViewAction(), this.hasEditAction(), this.hasDeleteAction()], ...(ngDevMode ? [{ debugName: "actions" }] : []));
574
+ actionsLength = computed(() => this.actions().filter((action) => !!action).length, ...(ngDevMode ? [{ debugName: "actionsLength" }] : []));
575
+ actionItems = computed(() => {
576
+ return [
577
+ {
578
+ label: 'View ' + this.entityName(),
579
+ visible: this.hasViewAction(),
580
+ icon: 'pi-search'
581
+ },
582
+ {
583
+ label: 'Update ' + this.entityName(),
584
+ visible: this.hasEditAction(),
585
+ icon: 'pi-pen-to-square',
586
+ shouldShow: (item) => this.canEdit()(item)
587
+ },
588
+ {
589
+ label: 'Delete ' + this.entityName(),
590
+ visible: this.hasDeleteAction(),
591
+ icon: 'pi-trash'
592
+ }
593
+ ];
594
+ }, ...(ngDevMode ? [{ debugName: "actionItems" }] : []));
595
+ // Content children for custom templates
596
+ formTemplate;
597
+ table;
598
+ // Services
599
+ http = inject(HttpClient);
600
+ confirmationService = inject(ConfirmationService);
601
+ messageService = inject(MessageService);
602
+ // Column filters for individual column filtering
603
+ filterValues = {};
604
+ // For custom cell templates
605
+ customTemplates = new Map();
606
+ constructor() {
607
+ // Effect to update filtered data when raw data changes
608
+ effect(() => {
609
+ const sourceData = this.dataSource();
610
+ this.data.set([...sourceData]);
611
+ });
612
+ }
613
+ // Register a custom template for a specific column
614
+ registerTemplate(field, template) {
615
+ this.customTemplates.set(field, template);
616
+ }
617
+ handlePageChange(event) {
618
+ this.pageChange.emit(event);
619
+ }
620
+ handleSort(event) {
621
+ const column = this.columns().find((col) => col.field === event.field);
622
+ const actualSortField = column?.sortField ?? event.field;
623
+ const order = event.order === 1 ? 'ASC' : 'DESC';
624
+ this.sortChange.emit({
625
+ sort: actualSortField,
626
+ order
627
+ });
628
+ }
629
+ resetTableSort() {
630
+ if (this.table) {
631
+ this.table.sortOrder = 0;
632
+ this.table.sortField = null;
633
+ this.table.tableService.onSort(null);
634
+ }
635
+ }
636
+ // Helper to safely get nested property values using dot notation
637
+ getItemValue(item, field, column) {
638
+ if (column && typeof column.render === 'function') {
639
+ return column.render(item);
640
+ }
641
+ return field
642
+ .split('.')
643
+ .reduce((obj, key) => obj?.[key] ?? null, item);
644
+ }
645
+ perFormActionFromPopover(item, actionType) {
646
+ if (actionType.includes('View')) {
647
+ this.view.emit(item);
648
+ }
649
+ else if (actionType.includes('Update')) {
650
+ this.edit.emit(item);
651
+ }
652
+ else if (actionType.includes('Delete')) {
653
+ this.deleteAction.emit(item);
654
+ }
655
+ }
656
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
657
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DataTableComponent, isStandalone: true, selector: "ngp-data-table", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalElements: { classPropertyName: "totalElements", publicName: "totalElements", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, showDefaultActions: { classPropertyName: "showDefaultActions", publicName: "showDefaultActions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, hasDeleteAction: { classPropertyName: "hasDeleteAction", publicName: "hasDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, hasEditAction: { classPropertyName: "hasEditAction", publicName: "hasEditAction", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, hasViewAction: { classPropertyName: "hasViewAction", publicName: "hasViewAction", isSignal: true, isRequired: false, transformFunction: null }, entityName: { classPropertyName: "entityName", publicName: "entityName", isSignal: true, isRequired: false, transformFunction: null }, isPaginated: { classPropertyName: "isPaginated", publicName: "isPaginated", isSignal: true, isRequired: false, transformFunction: null }, showCustomAction: { classPropertyName: "showCustomAction", publicName: "showCustomAction", isSignal: true, isRequired: false, transformFunction: null }, showRowNumbers: { classPropertyName: "showRowNumbers", publicName: "showRowNumbers", isSignal: true, isRequired: false, transformFunction: null }, rowNumberHeader: { classPropertyName: "rowNumberHeader", publicName: "rowNumberHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { add: "add", edit: "edit", deleteAction: "deleteAction", view: "view", pageChange: "pageChange", sortChange: "sortChange" }, providers: [ConfirmationService, MessageService], queries: [{ propertyName: "formTemplate", first: true, predicate: ["formTemplate"], descendants: true }], viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "<div class=\"card\">\n\t<p-table\n\t\t#dt\n\t\t[value]=\"data()\"\n\t\t[paginator]=\"isPaginated()\"\n\t\t[rows]=\"pageSize()\"\n\t\t[rowsPerPageOptions]=\"[5, 10, 25, 50]\"\n\t\t[rowHover]=\"true\"\n\t\t[loading]=\"loading()\"\n\t\t[showLoader]=\"false\"\n\t\t[scrollable]=\"true\"\n\t\tstyleClass=\"p-datatable-sm\"\n\t\t[totalRecords]=\"totalElements()\"\n\t\t[lazy]=\"isPaginated()\"\n\t\t[first]=\"currentPage() * pageSize()\"\n\t\tpaginatorDropdownAppendTo=\"body\"\n\t\t(onPage)=\"handlePageChange($event)\"\n\t\t(onSort)=\"handleSort($event)\">\n\t\t<ng-template pTemplate=\"header\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<th class=\"text-left !font-bold !text-gray-500 !w-1\" scope=\"col\">{{\n\t\t\t\t\t\trowNumberHeader()\n\t\t\t\t\t}}</th>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<th\n\t\t\t\t\t\t[pSortableColumn]=\"column.sortable ? column.field : undefined\"\n\t\t\t\t\t\tclass=\"text-left !font-bold !text-gray-500\"\n\t\t\t\t\t\t[ngClass]=\"{ '!text-center': column.align === 'center' }\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t[style]=\"{ width: column.width || 'auto' }\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t\t@if (column.sortable) {\n\t\t\t\t\t\t\t<p-sortIcon [field]=\"column.field\"></p-sortIcon>\n\t\t\t\t\t\t}\n\t\t\t\t\t</th>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<th class=\"!w-32 !text-center !font-bold !text-gray-500\" scope=\"col\">Actions</th>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"body\" let-item let-rowIndex=\"rowIndex\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<td class=\"!w-1 text-center\">\n\t\t\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td [ngClass]=\"{ '!text-center': column.align === 'center' }\">\n\t\t\t\t\t\t@if (customTemplates && customTemplates.get(column.field)) {\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get(column.field)!\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: column.field }\">\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t{{ getItemValue(item, column.field, column) }}\n\t\t\t\t\t\t}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td class=\"\">\n\t\t\t\t\t\t<div class=\"flex justify-center gap-2\">\n\t\t\t\t\t\t\t@if (showDefaultActions() && actionsLength() < 2 && !showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Inline buttons for less than 2 standard actions and no custom action -->\n\t\t\t\t\t\t\t\t@if (hasViewAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'View'\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"view.emit(item)\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasEditAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"edit.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Update'\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasDeleteAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-danger\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"deleteAction.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Delete'\"></button>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} @else if (!showDefaultActions() && showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Only custom action, no popover needed -->\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<!-- Popover menu for 2+ standard actions or when combining with custom action -->\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\ticon=\"pi pi-ellipsis-h\"\n\t\t\t\t\t\t\t\t\tclass=\"p-button-outlined p-button-secondary\"\n\t\t\t\t\t\t\t\t\t(click)=\"po.toggle($event)\"></button>\n\t\t\t\t\t\t\t\t<p-popover #po styleClass=\"!min-w-40\">\n\t\t\t\t\t\t\t\t\t<span class=\"!font-semibold !text-gray-500 block mb-2\">Actions</span>\n\t\t\t\t\t\t\t\t\t<ul class=\"list-none p-0 m-0 flex flex-col\">\n\t\t\t\t\t\t\t\t\t\t@if (showDefaultActions()) {\n\t\t\t\t\t\t\t\t\t\t\t@for (actionItem of actionItems(); track $index) {\n\t\t\t\t\t\t\t\t\t\t\t\t@if (\n\t\t\t\t\t\t\t\t\t\t\t\t\tactionItem.visible &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t(!actionItem.shouldShow || actionItem.shouldShow(item))\n\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"perFormActionFromPopover(item, actionItem.label)\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pi\" [ngClass]=\"actionItem.icon\"></span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"font-medium\">{{ actionItem.label }}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t<!-- Custom action template in popover -->\n\t\t\t\t\t\t\t\t\t\t@if (showCustomAction() && customTemplates.get('customAction')) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t</p-popover>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template #loadingbody>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"emptymessage\">\n\t\t\t<tr>\n\t\t\t\t<td [attr.colspan]=\"columns().length + 1\" class=\"text-center p-4\">{{ emptyMessage() }}</td>\n\t\t\t</tr>\n\t\t</ng-template>\n\t</p-table>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i3$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2$1.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i2$1.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4$1.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ToastModule }, { kind: "ngmodule", type: ToolbarModule }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i5$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i6.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }] });
658
+ }
659
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataTableComponent, decorators: [{
660
+ type: Component,
661
+ args: [{ selector: 'ngp-data-table', imports: [
662
+ CommonModule,
663
+ FormsModule,
664
+ ReactiveFormsModule,
665
+ TableModule,
666
+ ButtonModule,
667
+ InputTextModule,
668
+ ConfirmDialogModule,
669
+ DialogModule,
670
+ TooltipModule,
671
+ ToastModule,
672
+ ToolbarModule,
673
+ SkeletonModule,
674
+ PopoverModule
675
+ ], providers: [ConfirmationService, MessageService], template: "<div class=\"card\">\n\t<p-table\n\t\t#dt\n\t\t[value]=\"data()\"\n\t\t[paginator]=\"isPaginated()\"\n\t\t[rows]=\"pageSize()\"\n\t\t[rowsPerPageOptions]=\"[5, 10, 25, 50]\"\n\t\t[rowHover]=\"true\"\n\t\t[loading]=\"loading()\"\n\t\t[showLoader]=\"false\"\n\t\t[scrollable]=\"true\"\n\t\tstyleClass=\"p-datatable-sm\"\n\t\t[totalRecords]=\"totalElements()\"\n\t\t[lazy]=\"isPaginated()\"\n\t\t[first]=\"currentPage() * pageSize()\"\n\t\tpaginatorDropdownAppendTo=\"body\"\n\t\t(onPage)=\"handlePageChange($event)\"\n\t\t(onSort)=\"handleSort($event)\">\n\t\t<ng-template pTemplate=\"header\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<th class=\"text-left !font-bold !text-gray-500 !w-1\" scope=\"col\">{{\n\t\t\t\t\t\trowNumberHeader()\n\t\t\t\t\t}}</th>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<th\n\t\t\t\t\t\t[pSortableColumn]=\"column.sortable ? column.field : undefined\"\n\t\t\t\t\t\tclass=\"text-left !font-bold !text-gray-500\"\n\t\t\t\t\t\t[ngClass]=\"{ '!text-center': column.align === 'center' }\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t[style]=\"{ width: column.width || 'auto' }\">\n\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t\t@if (column.sortable) {\n\t\t\t\t\t\t\t<p-sortIcon [field]=\"column.field\"></p-sortIcon>\n\t\t\t\t\t\t}\n\t\t\t\t\t</th>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<th class=\"!w-32 !text-center !font-bold !text-gray-500\" scope=\"col\">Actions</th>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"body\" let-item let-rowIndex=\"rowIndex\">\n\t\t\t<tr>\n\t\t\t\t@if (showRowNumbers()) {\n\t\t\t\t\t<td class=\"!w-1 text-center\">\n\t\t\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td [ngClass]=\"{ '!text-center': column.align === 'center' }\">\n\t\t\t\t\t\t@if (customTemplates && customTemplates.get(column.field)) {\n\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get(column.field)!\"\n\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: column.field }\">\n\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t{{ getItemValue(item, column.field, column) }}\n\t\t\t\t\t\t}\n\t\t\t\t\t</td>\n\t\t\t\t}\n\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td class=\"\">\n\t\t\t\t\t\t<div class=\"flex justify-center gap-2\">\n\t\t\t\t\t\t\t@if (showDefaultActions() && actionsLength() < 2 && !showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Inline buttons for less than 2 standard actions and no custom action -->\n\t\t\t\t\t\t\t\t@if (hasViewAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'View'\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"view.emit(item)\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasEditAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-primary\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"edit.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Update'\"></button>\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t@if (hasDeleteAction()) {\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\t\tclass=\"!p-0 p-button-danger\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"deleteAction.emit(item)\"\n\t\t\t\t\t\t\t\t\t\t[label]=\"'Delete'\"></button>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} @else if (!showDefaultActions() && showCustomAction()) {\n\t\t\t\t\t\t\t\t<!-- Only custom action, no popover needed -->\n\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<!-- Popover menu for 2+ standard actions or when combining with custom action -->\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t[text]=\"true\"\n\t\t\t\t\t\t\t\t\tpButton\n\t\t\t\t\t\t\t\t\ticon=\"pi pi-ellipsis-h\"\n\t\t\t\t\t\t\t\t\tclass=\"p-button-outlined p-button-secondary\"\n\t\t\t\t\t\t\t\t\t(click)=\"po.toggle($event)\"></button>\n\t\t\t\t\t\t\t\t<p-popover #po styleClass=\"!min-w-40\">\n\t\t\t\t\t\t\t\t\t<span class=\"!font-semibold !text-gray-500 block mb-2\">Actions</span>\n\t\t\t\t\t\t\t\t\t<ul class=\"list-none p-0 m-0 flex flex-col\">\n\t\t\t\t\t\t\t\t\t\t@if (showDefaultActions()) {\n\t\t\t\t\t\t\t\t\t\t\t@for (actionItem of actionItems(); track $index) {\n\t\t\t\t\t\t\t\t\t\t\t\t@if (\n\t\t\t\t\t\t\t\t\t\t\t\t\tactionItem.visible &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t(!actionItem.shouldShow || actionItem.shouldShow(item))\n\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclass=\"flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"perFormActionFromPopover(item, actionItem.label)\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pi\" [ngClass]=\"actionItem.icon\"></span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"font-medium\">{{ actionItem.label }}</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t<!-- Custom action template in popover -->\n\t\t\t\t\t\t\t\t\t\t@if (showCustomAction() && customTemplates.get('customAction')) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutlet]=\"customTemplates.get('customAction')!\"\n\t\t\t\t\t\t\t\t\t\t\t\t[ngTemplateOutletContext]=\"{ $implicit: item, field: 'customAction' }\">\n\t\t\t\t\t\t\t\t\t\t\t</ng-container>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t</p-popover>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template #loadingbody>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t@for (column of columns(); track column.field) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t\t@if (showDefaultActions() || showCustomAction()) {\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<p-skeleton />\n\t\t\t\t\t</td>\n\t\t\t\t}\n\t\t\t</tr>\n\t\t</ng-template>\n\n\t\t<ng-template pTemplate=\"emptymessage\">\n\t\t\t<tr>\n\t\t\t\t<td [attr.colspan]=\"columns().length + 1\" class=\"text-center p-4\">{{ emptyMessage() }}</td>\n\t\t\t</tr>\n\t\t</ng-template>\n\t</p-table>\n</div>\n" }]
676
+ }], ctorParameters: () => [], propDecorators: { dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], totalElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalElements", required: false }] }], currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }], showDefaultActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefaultActions", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], hasDeleteAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasDeleteAction", required: false }] }], hasEditAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasEditAction", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], hasViewAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasViewAction", required: false }] }], entityName: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityName", required: false }] }], isPaginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "isPaginated", required: false }] }], showCustomAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCustomAction", required: false }] }], showRowNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRowNumbers", required: false }] }], rowNumberHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowNumberHeader", required: false }] }], add: [{ type: i0.Output, args: ["add"] }], edit: [{ type: i0.Output, args: ["edit"] }], deleteAction: [{ type: i0.Output, args: ["deleteAction"] }], view: [{ type: i0.Output, args: ["view"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], formTemplate: [{
677
+ type: ContentChild,
678
+ args: ['formTemplate']
679
+ }], table: [{
680
+ type: ViewChild,
681
+ args: ['dt']
682
+ }] } });
683
+
684
+ class DynamicNgSelectComponent {
685
+ apiUrl;
686
+ formatOptions;
687
+ bindLabel = 'description';
688
+ bindValue = 'id';
689
+ placeholder = 'Select';
690
+ isRequired = false;
691
+ options = [];
692
+ value;
693
+ disabled = false;
694
+ tableParams = signal({ page: 0, size: 10 }, ...(ngDevMode ? [{ debugName: "tableParams" }] : []));
695
+ onChange = (_) => { }; // eslint-disable-line
696
+ onTouched = () => { }; // eslint-disable-line
697
+ ngOnInit() {
698
+ this.loadOptions();
699
+ }
700
+ loadOptions() {
701
+ if (!this.apiUrl) {
702
+ return;
703
+ }
704
+ this.getOptions();
705
+ }
706
+ getOptions() {
707
+ this.apiUrl(this.tableParams())
708
+ .pipe(tap((items) => {
709
+ const values = this.formatOptions ? this.formatOptions(items.results) : items.results;
710
+ this.options = [...this.options, ...values];
711
+ if (items.hasNextPage) {
712
+ this.tableParams.update((param) => ({ ...param, page: param.page + 1 }));
713
+ this.getOptions();
714
+ }
715
+ }))
716
+ .subscribe();
717
+ }
718
+ writeValue(value) {
719
+ this.value = value;
720
+ }
721
+ registerOnChange(fn) {
722
+ this.onChange = fn;
723
+ }
724
+ registerOnTouched(fn) {
725
+ this.onTouched = fn;
726
+ }
727
+ setDisabledState(isDisabled) {
728
+ this.disabled = isDisabled;
729
+ }
730
+ onValueChange(value) {
731
+ if (!value) {
732
+ this.value = null;
733
+ this.onChange(null);
734
+ }
735
+ else {
736
+ this.value = value[this.bindValue];
737
+ this.onChange(value[this.bindValue]);
738
+ }
739
+ this.onTouched();
740
+ }
741
+ validate(control) {
742
+ if (this.isRequired &&
743
+ (this.value === null || this.value === undefined || this.value === '')) {
744
+ return { required: true };
745
+ }
746
+ return null;
747
+ }
748
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicNgSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
749
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DynamicNgSelectComponent, isStandalone: true, selector: "ngp-dynamic-select", inputs: { apiUrl: "apiUrl", formatOptions: "formatOptions", bindLabel: "bindLabel", bindValue: "bindValue", placeholder: "placeholder", isRequired: "isRequired", options: "options" }, providers: [
750
+ {
751
+ provide: NG_VALUE_ACCESSOR,
752
+ useExisting: forwardRef(() => DynamicNgSelectComponent),
753
+ multi: true
754
+ },
755
+ {
756
+ provide: NG_VALIDATORS,
757
+ useExisting: forwardRef(() => DynamicNgSelectComponent),
758
+ multi: true
759
+ }
760
+ ], ngImport: i0, template: "<p-floatlabel variant=\"in\">\n <ng-select [items]=\"options\" [bindLabel]=\"bindLabel\" [bindValue]=\"bindValue\" [disabled]=\"disabled\"\n [(ngModel)]=\"value\" [clearable]=\"true\" (change)=\"onValueChange($event)\">\n </ng-select>\n\n <label [class.required-label]=\"isRequired\">{{ placeholder }}</label>\n</p-floatlabel>", dependencies: [{ kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i1$2.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i3$1.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
761
+ }
762
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicNgSelectComponent, decorators: [{
763
+ type: Component,
764
+ args: [{ selector: 'ngp-dynamic-select', imports: [NgSelectModule, FormsModule, CommonModule, FloatLabelModule], providers: [
765
+ {
766
+ provide: NG_VALUE_ACCESSOR,
767
+ useExisting: forwardRef(() => DynamicNgSelectComponent),
768
+ multi: true
769
+ },
770
+ {
771
+ provide: NG_VALIDATORS,
772
+ useExisting: forwardRef(() => DynamicNgSelectComponent),
773
+ multi: true
774
+ }
775
+ ], template: "<p-floatlabel variant=\"in\">\n <ng-select [items]=\"options\" [bindLabel]=\"bindLabel\" [bindValue]=\"bindValue\" [disabled]=\"disabled\"\n [(ngModel)]=\"value\" [clearable]=\"true\" (change)=\"onValueChange($event)\">\n </ng-select>\n\n <label [class.required-label]=\"isRequired\">{{ placeholder }}</label>\n</p-floatlabel>" }]
776
+ }], propDecorators: { apiUrl: [{
777
+ type: Input
778
+ }], formatOptions: [{
779
+ type: Input
780
+ }], bindLabel: [{
781
+ type: Input
782
+ }], bindValue: [{
783
+ type: Input
784
+ }], placeholder: [{
785
+ type: Input
786
+ }], isRequired: [{
787
+ type: Input
788
+ }], options: [{
789
+ type: Input
790
+ }] } });
791
+
792
+ class PaginatedRequest {
793
+ page;
794
+ size;
795
+ sort;
796
+ }
797
+
798
+ let CrudAbstractComponent = class CrudAbstractComponent {
799
+ // State signals
800
+ sourceSignal = signal(null, ...(ngDevMode ? [{ debugName: "sourceSignal" }] : []));
801
+ loadingSignal = signal(false, ...(ngDevMode ? [{ debugName: "loadingSignal" }] : []));
802
+ errorSignal = signal(null, ...(ngDevMode ? [{ debugName: "errorSignal" }] : []));
803
+ actionSignal = signal(null, ...(ngDevMode ? [{ debugName: "actionSignal" }] : []));
804
+ firstLoadSignal = signal(true, ...(ngDevMode ? [{ debugName: "firstLoadSignal" }] : []));
805
+ showFormSignal = signal(false, ...(ngDevMode ? [{ debugName: "showFormSignal" }] : []));
806
+ formActionSignal = signal(null, ...(ngDevMode ? [{ debugName: "formActionSignal" }] : []));
807
+ dataSignal = signal(null, ...(ngDevMode ? [{ debugName: "dataSignal" }] : []));
808
+ filters = signal(null, ...(ngDevMode ? [{ debugName: "filters" }] : []));
809
+ tableParams = signal({ page: 0, size: 10 }, ...(ngDevMode ? [{ debugName: "tableParams" }] : []));
810
+ requestParams = computed(() => ({
811
+ ...this.filters(),
812
+ ...this.tableParams()
813
+ }), ...(ngDevMode ? [{ debugName: "requestParams" }] : []));
814
+ // Injections
815
+ injector = inject(Injector);
816
+ // Public interface
817
+ data = this.dataSignal.asReadonly();
818
+ isLoading = this.loadingSignal.asReadonly();
819
+ error = this.errorSignal.asReadonly();
820
+ currentAction = this.actionSignal.asReadonly();
821
+ isFirstLoad = this.firstLoadSignal.asReadonly();
822
+ isFormVisible = this.showFormSignal.asReadonly();
823
+ formAction = this.formActionSignal.asReadonly();
824
+ safeDataSource = computed(() => {
825
+ const rawData = this.dataSignal();
826
+ const isLoading = this.loadingSignal();
827
+ // Default empty response
828
+ const defaultResponse = {
829
+ hasNextPage: false,
830
+ totalElements: 0,
831
+ results: [],
832
+ currentPage: 0,
833
+ pageSize: 10
834
+ };
835
+ if (!rawData || isLoading)
836
+ return defaultResponse;
837
+ const isPaginatedResponse = (obj) => {
838
+ return (obj !== null &&
839
+ typeof obj === 'object' &&
840
+ 'results' in obj &&
841
+ Array.isArray(obj.results) &&
842
+ 'totalElements' in obj &&
843
+ typeof obj.totalElements === 'number');
844
+ };
845
+ // Handler for Paginated Response
846
+ if (typeof rawData === 'object' && isPaginatedResponse(rawData)) {
847
+ return {
848
+ results: [...rawData.results],
849
+ totalElements: rawData.totalElements,
850
+ currentPage: rawData.currentPage,
851
+ pageSize: rawData.pageSize,
852
+ hasNextPage: rawData.hasNextPage
853
+ };
854
+ }
855
+ // Handle array case
856
+ if (Array.isArray(rawData)) {
857
+ return {
858
+ ...defaultResponse,
859
+ totalElements: rawData.length,
860
+ results: [...rawData],
861
+ pageSize: rawData.length // For arrays, we typically return all elements
862
+ };
863
+ }
864
+ // Handle single object case
865
+ return {
866
+ ...defaultResponse,
867
+ totalElements: 1,
868
+ results: [rawData],
869
+ pageSize: 1
870
+ };
871
+ }, ...(ngDevMode ? [{ debugName: "safeDataSource" }] : []));
872
+ /**
873
+ * Provides direct access to raw list data without pagination wrapper
874
+ * Returns an empty array if data is not available or not an array
875
+ */
876
+ rawList = computed(() => {
877
+ const rawData = this.data();
878
+ if (!rawData || this.isLoading()) {
879
+ return [];
880
+ }
881
+ // If it's already an array, return it
882
+ if (Array.isArray(rawData)) {
883
+ return [...rawData];
884
+ }
885
+ // If it's a paginated response with a results property that's an array
886
+ if (typeof rawData === 'object' && 'results' in rawData && Array.isArray(rawData.results)) {
887
+ return [...rawData.results];
888
+ }
889
+ // If it's a single object, return it as an array with one item
890
+ if (typeof rawData === 'object' && !('results' in rawData)) {
891
+ return [rawData];
892
+ }
893
+ // Default fallback
894
+ return [];
895
+ }, ...(ngDevMode ? [{ debugName: "rawList" }] : []));
896
+ // Usage in your component:
897
+ // const items = this.rawList();
898
+ // Current operations state
899
+ currentOperations;
900
+ currentParams;
901
+ // Effect to handle Observable subscriptions
902
+ dataEffect = effect(() => {
903
+ const obs = this.sourceSignal();
904
+ if (!obs) {
905
+ untracked(() => this.dataSignal.set(null));
906
+ return;
907
+ }
908
+ untracked(() => {
909
+ this.loadingSignal.set(true);
910
+ this.errorSignal.set(null);
911
+ const sub = obs
912
+ .pipe(shareReplay(1), catchError((err) => {
913
+ this.errorSignal.set(err);
914
+ return of(null);
915
+ }), finalize(() => this.loadingSignal.set(false)))
916
+ .subscribe((value) => {
917
+ this.dataSignal.set(value);
918
+ });
919
+ return () => sub.unsubscribe();
920
+ });
921
+ }, ...(ngDevMode ? [{ debugName: "dataEffect", injector: this.injector }] : [{ injector: this.injector }]));
922
+ /**
923
+ * Initialize with dynamic service operations
924
+ */
925
+ initService(operations) {
926
+ this.currentOperations = operations;
927
+ }
928
+ /**
929
+ * GET data
930
+ */
931
+ loadData(params) {
932
+ if (!this.currentOperations?.get)
933
+ return;
934
+ this.executeOperation('get', () => this.currentOperations.get(params), params);
935
+ this.firstLoadSignal.set(false);
936
+ }
937
+ /**
938
+ * GET data by ID
939
+ */
940
+ getById(id, params) {
941
+ if (!this.currentOperations?.getById)
942
+ return of(null);
943
+ return this.executeOperation('get', () => this.currentOperations.getById(id, params));
944
+ }
945
+ /**
946
+ * CREATE data
947
+ */
948
+ createData(data) {
949
+ if (!this.currentOperations?.create)
950
+ return of(null);
951
+ return this.executeOperation('create', () => this.currentOperations.create(data));
952
+ }
953
+ /**
954
+ * UPDATE data
955
+ */
956
+ updateData(data) {
957
+ if (!this.currentOperations?.update)
958
+ return of(null);
959
+ return this.executeOperation('update', () => this.currentOperations.update(data));
960
+ }
961
+ /**
962
+ * UPDATE data by ID
963
+ */
964
+ updateById(id, data) {
965
+ if (!this.currentOperations?.updateById)
966
+ return of(null);
967
+ return this.executeOperation('updateById', () => this.currentOperations.updateById(id, data));
968
+ }
969
+ /**
970
+ * DELETE data
971
+ */
972
+ deleteData(id) {
973
+ if (!this.currentOperations?.delete)
974
+ return of(null);
975
+ return this.executeOperation('delete', () => this.currentOperations.delete(id));
976
+ }
977
+ /**
978
+ * UPDATE status
979
+ */
980
+ updateStatus(id, status) {
981
+ if (!this.currentOperations?.updateStatus)
982
+ return of(null);
983
+ return this.executeOperation('update', // You can reuse 'update' action or add a new one like 'updateStatus'
984
+ () => this.currentOperations.updateStatus(id, status));
985
+ }
986
+ /**
987
+ * SHOW/HIDE form
988
+ * @param show Whether to show or hide the form
989
+ */
990
+ showForm(show) {
991
+ this.showFormSignal.set(show);
992
+ }
993
+ /**
994
+ * Update form action (create/edit)
995
+ * @param action The action to set for the form
996
+ */
997
+ updateFormAction(action) {
998
+ this.formActionSignal.set(action);
999
+ }
1000
+ /**
1001
+ * Shared operation execution logic
1002
+ */
1003
+ executeOperation(action, operation, params) {
1004
+ this.errorSignal.set(null);
1005
+ this.loadingSignal.set(true);
1006
+ this.actionSignal.set(action);
1007
+ if (action === 'get') {
1008
+ this.currentParams = params;
1009
+ }
1010
+ const operation$ = operation().pipe(untilDestroyed(this), catchError((err) => {
1011
+ this.errorSignal.set(err);
1012
+ return of(null);
1013
+ }), finalize(() => {
1014
+ this.loadingSignal.set(false);
1015
+ this.actionSignal.set(null);
1016
+ }), shareReplay(1));
1017
+ if (action === 'get') {
1018
+ this.sourceSignal.set(operation$);
1019
+ }
1020
+ else {
1021
+ operation$.subscribe(() => {
1022
+ if (this.currentOperations?.get) {
1023
+ this.refresh();
1024
+ }
1025
+ });
1026
+ }
1027
+ return operation$;
1028
+ }
1029
+ /**
1030
+ * Refresh current data
1031
+ */
1032
+ refresh() {
1033
+ if (this.currentOperations?.get && this.currentParams) {
1034
+ this.loadData(this.currentParams);
1035
+ }
1036
+ }
1037
+ get entityName() {
1038
+ return 'Item';
1039
+ }
1040
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1041
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent });
1042
+ };
1043
+ CrudAbstractComponent = __decorate([
1044
+ UntilDestroy()
1045
+ ], CrudAbstractComponent);
1046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CrudAbstractComponent, decorators: [{
1047
+ type: Injectable
1048
+ }] });
1049
+
1050
+ class HelperService {
1051
+ transformEmployeeResponse = (res) => ({
1052
+ ...res,
1053
+ results: res.results.map((e) => ({
1054
+ ...e,
1055
+ fullName: [e.name.givenName, e.name.middleName, e.name.familyName]
1056
+ .filter((part) => part)
1057
+ .join(' ')
1058
+ .trim()
1059
+ .concat(e?.company?.name ? ` (${e.company.name})` : '')
1060
+ }))
1061
+ });
1062
+ transformPayloadWithAddress = (payload) => {
1063
+ const transformedPayload = { ...payload };
1064
+ if (transformedPayload['address']) {
1065
+ const address = { ...transformedPayload['address'] };
1066
+ // Helper function to extract name from address field
1067
+ const extractName = (field) => {
1068
+ if (!field)
1069
+ return undefined;
1070
+ if (typeof field === 'string')
1071
+ return field;
1072
+ if (typeof field === 'object' && field !== null && 'name' in field) {
1073
+ return field['name'];
1074
+ }
1075
+ return undefined;
1076
+ };
1077
+ address.province = extractName(address.province);
1078
+ address.city = extractName(address.city);
1079
+ address.barangay = extractName(address.barangay);
1080
+ transformedPayload['address'] = address;
1081
+ }
1082
+ return transformedPayload;
1083
+ };
1084
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1085
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, providedIn: 'root' });
1086
+ }
1087
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HelperService, decorators: [{
1088
+ type: Injectable,
1089
+ args: [{
1090
+ providedIn: 'root'
1091
+ }]
1092
+ }] });
1093
+
1094
+ // Components
1095
+ // export * from './lib/components/components';
1096
+
1097
+ /**
1098
+ * Generated bundle index. Do not edit.
1099
+ */
1100
+
1101
+ export { BasicNgSelectComponent, CrudAbstractComponent, DataTableComponent, DynamicNgSelectComponent, EmptyComponent, FgAddressComponent, FileUploadComponent, FormFieldWrapperComponent, HelperService, PaginatedRequest };
1102
+ //# sourceMappingURL=winexist-ngp.mjs.map