@elite.framework/ng.ui.core 1.0.3 → 1.0.5

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.
@@ -0,0 +1,3 @@
1
+ # @elite.framework/ng.ui.core/excel-import
2
+
3
+ Secondary entry point of `@elite.framework/ng.ui.core`. It can be used by importing from `@elite.framework/ng.ui.core/excel-import`.
@@ -0,0 +1,69 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnDestroy, EventEmitter } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import * as _elite_framework_ng_core_tokens from '@elite.framework/ng.core/tokens';
5
+ import { FormGroup } from '@angular/forms';
6
+ import { FormlyFieldConfig } from '@ngx-formly/core';
7
+ import { DynamicDialogRef, DynamicDialogConfig } from 'primeng/dynamicdialog';
8
+
9
+ declare class ExcelImportModule {
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<ExcelImportModule, never>;
11
+ static ɵmod: i0.ɵɵNgModuleDeclaration<ExcelImportModule, never, [typeof i1.CommonModule], never>;
12
+ static ɵinj: i0.ɵɵInjectorDeclaration<ExcelImportModule>;
13
+ }
14
+
15
+ interface ExcelImportConfig {
16
+ templateUrl: string;
17
+ apiUrl: string;
18
+ apiName: string;
19
+ mappingFields: FormlyFieldConfig[];
20
+ acceptedFileTypes?: string;
21
+ maxFileSize?: number;
22
+ steps?: {
23
+ label: string;
24
+ }[];
25
+ }
26
+ declare class ExcelImportComponent implements OnDestroy {
27
+ ref: DynamicDialogRef;
28
+ dialogConfig: DynamicDialogConfig;
29
+ config: ExcelImportConfig;
30
+ importComplete: EventEmitter<any>;
31
+ importError: EventEmitter<Error>;
32
+ form: FormGroup;
33
+ model: any;
34
+ loading: boolean;
35
+ uploadedFileName: string | null;
36
+ uploadError: string | null;
37
+ excelHeaders: string[];
38
+ private destroy$;
39
+ private restService;
40
+ private messageService;
41
+ private translateService;
42
+ private fb;
43
+ env: _elite_framework_ng_core_tokens.EnvironmentConfig;
44
+ steps: {
45
+ label: any;
46
+ }[];
47
+ activeStep: number;
48
+ mappingFields: FormlyFieldConfig[];
49
+ constructor(ref: DynamicDialogRef, dialogConfig: DynamicDialogConfig);
50
+ ngOnInit(): void;
51
+ nextStep(): void;
52
+ prevStep(): void;
53
+ canProceed(): boolean;
54
+ getModelValue(field: FormlyFieldConfig, model: any): any;
55
+ private fileContent;
56
+ onFileUpload(event: any): void;
57
+ private arrayBufferToBase64;
58
+ private getFileExtension;
59
+ onSubmit(): void;
60
+ private clearFileUpload;
61
+ private initializeForm;
62
+ onCancel(): void;
63
+ ngOnDestroy(): void;
64
+ static ɵfac: i0.ɵɵFactoryDeclaration<ExcelImportComponent, never>;
65
+ static ɵcmp: i0.ɵɵComponentDeclaration<ExcelImportComponent, "app-excel-import", never, { "config": { "alias": "config"; "required": false; }; }, { "importComplete": "importComplete"; "importError": "importError"; }, never, never, true, never>;
66
+ }
67
+
68
+ export { ExcelImportComponent, ExcelImportModule };
69
+ export type { ExcelImportConfig };
@@ -0,0 +1,568 @@
1
+ import * as i0 from '@angular/core';
2
+ import { NgModule, EventEmitter, inject, Output, Input, Component } from '@angular/core';
3
+ import * as i2 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i3 from '@angular/forms';
6
+ import { FormBuilder, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
7
+ import { RestService } from '@elite.framework/ng.core/services';
8
+ import { FormlyForm } from '@ngx-formly/core';
9
+ import * as i8 from '@ngx-translate/core';
10
+ import { TranslateService, TranslateModule } from '@ngx-translate/core';
11
+ import * as i4 from 'primeng/button';
12
+ import { ButtonModule } from 'primeng/button';
13
+ import * as i1 from 'primeng/dynamicdialog';
14
+ import { Subject, takeUntil } from 'rxjs';
15
+ import * as i5 from 'primeng/fileupload';
16
+ import { FileUploadModule } from 'primeng/fileupload';
17
+ import * as i6 from 'primeng/steps';
18
+ import { StepsModule } from 'primeng/steps';
19
+ import { MessageService } from 'primeng/api';
20
+ import * as i7 from 'primeng/toast';
21
+ import { ToastModule } from 'primeng/toast';
22
+ import { read, utils } from 'xlsx';
23
+ import { ENVIRONMENT } from '@elite.framework/ng.core/tokens';
24
+
25
+ class ExcelImportModule {
26
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
27
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportModule, imports: [CommonModule] });
28
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportModule, imports: [CommonModule] });
29
+ }
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportModule, decorators: [{
31
+ type: NgModule,
32
+ args: [{
33
+ imports: [CommonModule],
34
+ }]
35
+ }] });
36
+
37
+ class ExcelImportComponent {
38
+ ref;
39
+ dialogConfig;
40
+ config;
41
+ importComplete = new EventEmitter();
42
+ importError = new EventEmitter();
43
+ form;
44
+ model = {};
45
+ loading = false;
46
+ uploadedFileName = null;
47
+ uploadError = null;
48
+ excelHeaders = [];
49
+ destroy$ = new Subject();
50
+ restService = inject(RestService);
51
+ messageService = inject(MessageService);
52
+ translateService = inject(TranslateService);
53
+ fb = inject(FormBuilder);
54
+ env = inject(ENVIRONMENT);
55
+ steps = [
56
+ { label: this.translateService.instant('uploadFile') },
57
+ { label: this.translateService.instant('columnMapping') },
58
+ { label: this.translateService.instant('review') },
59
+ ];
60
+ activeStep = 0;
61
+ mappingFields = [];
62
+ constructor(ref, dialogConfig) {
63
+ this.ref = ref;
64
+ this.dialogConfig = dialogConfig;
65
+ this.form = this.fb.group({});
66
+ // Initialize from dialog config if provided
67
+ if (this.dialogConfig?.data?.config) {
68
+ this.config = this.dialogConfig.data.config;
69
+ }
70
+ }
71
+ ngOnInit() {
72
+ if (!this.config) {
73
+ throw new Error('ExcelImportConfig is required');
74
+ }
75
+ this.mappingFields = this.config.mappingFields.map(field => ({
76
+ ...field,
77
+ props: {
78
+ ...field.props,
79
+ options: []
80
+ }
81
+ }));
82
+ this.steps = this.config.steps || this.steps;
83
+ }
84
+ nextStep() {
85
+ if (this.activeStep < 2)
86
+ this.activeStep++;
87
+ }
88
+ prevStep() {
89
+ if (this.activeStep > 0)
90
+ this.activeStep--;
91
+ }
92
+ canProceed() {
93
+ switch (this.activeStep) {
94
+ case 0:
95
+ return !!this.uploadedFileName;
96
+ case 1:
97
+ return this.form.valid;
98
+ case 2:
99
+ return true;
100
+ default:
101
+ return false;
102
+ }
103
+ }
104
+ getModelValue(field, model) {
105
+ if (!field.key)
106
+ return null;
107
+ if (Array.isArray(field.key)) {
108
+ // Walk through nested keys like ['address', 'street']
109
+ return field.key.reduce((acc, k) => (acc ? acc[k] : undefined), model);
110
+ }
111
+ return model[field.key];
112
+ }
113
+ // Add this property to store the file content
114
+ fileContent = null;
115
+ // Update the onFileUpload method to store the file content
116
+ onFileUpload(event) {
117
+ this.uploadError = null;
118
+ const file = event.files[0];
119
+ if (!file) {
120
+ this.uploadError = 'noFileSelected';
121
+ return;
122
+ }
123
+ // Validate file type
124
+ const validExtensions = ['.xlsx', '.xls', '.csv'];
125
+ const fileExtension = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));
126
+ if (!validExtensions.includes(fileExtension)) {
127
+ this.uploadError = 'invalidFileType';
128
+ this.clearFileUpload(event);
129
+ return;
130
+ }
131
+ this.uploadedFileName = file.name;
132
+ const reader = new FileReader();
133
+ reader.onload = (e) => {
134
+ try {
135
+ const arrayBuffer = e.target?.result;
136
+ this.fileContent = arrayBuffer; // Store the file content
137
+ const data = new Uint8Array(arrayBuffer);
138
+ const workbook = read(data, { type: 'array' });
139
+ if (workbook.SheetNames.length === 0) {
140
+ this.uploadError = 'noSheetsFound';
141
+ this.clearFileUpload(event);
142
+ return;
143
+ }
144
+ const sheetName = workbook.SheetNames[0];
145
+ const worksheet = workbook.Sheets[sheetName];
146
+ const rows = utils.sheet_to_json(worksheet, { header: 1 });
147
+ if (rows.length === 0) {
148
+ this.uploadError = 'noDataFound';
149
+ this.clearFileUpload(event);
150
+ return;
151
+ }
152
+ this.excelHeaders = rows[0];
153
+ // Update mapping fields with header options
154
+ this.mappingFields.forEach(field => {
155
+ if (field.props) {
156
+ field.props.options = this.excelHeaders.map(h => ({
157
+ value: h,
158
+ label: h,
159
+ }));
160
+ }
161
+ });
162
+ // Initialize form with default values if not set
163
+ this.initializeForm();
164
+ }
165
+ catch (error) {
166
+ console.error('Error processing Excel file:', error);
167
+ this.uploadError = 'fileProcessingError';
168
+ this.clearFileUpload(event);
169
+ }
170
+ };
171
+ reader.onerror = (error) => {
172
+ console.error('File reading error:', error);
173
+ this.uploadError = 'fileReadError';
174
+ this.clearFileUpload(event);
175
+ };
176
+ reader.readAsArrayBuffer(file);
177
+ }
178
+ // Add this method to convert ArrayBuffer to base64
179
+ arrayBufferToBase64(buffer) {
180
+ const bytes = new Uint8Array(buffer);
181
+ let binary = '';
182
+ const len = bytes.byteLength;
183
+ for (let i = 0; i < len; i++) {
184
+ binary += String.fromCharCode(bytes[i]);
185
+ }
186
+ return window.btoa(binary);
187
+ }
188
+ // Add this method to get file extension
189
+ getFileExtension(filename) {
190
+ const index = filename.lastIndexOf('.');
191
+ return index !== -1 ? filename.slice(index) : '';
192
+ }
193
+ // Updated onSubmit method
194
+ onSubmit() {
195
+ if (this.form.invalid || !this.uploadedFileName || !this.fileContent) {
196
+ this.form.markAllAsTouched();
197
+ if (!this.fileContent) {
198
+ this.messageService.add({
199
+ severity: 'error',
200
+ summary: 'Error',
201
+ detail: 'File content is missing. Please upload the file again.'
202
+ });
203
+ }
204
+ return;
205
+ }
206
+ this.loading = true;
207
+ // Convert file content to base64
208
+ let fileBase64;
209
+ try {
210
+ if (this.fileContent instanceof ArrayBuffer) {
211
+ fileBase64 = this.arrayBufferToBase64(this.fileContent);
212
+ }
213
+ else if (typeof this.fileContent === 'string') {
214
+ // If it's already a string (base64), use it directly
215
+ fileBase64 = this.fileContent;
216
+ }
217
+ else {
218
+ throw new Error('Unsupported file content type');
219
+ }
220
+ }
221
+ catch (error) {
222
+ this.loading = false;
223
+ console.error('Error converting file to base64:', error);
224
+ this.messageService.add({
225
+ severity: 'error',
226
+ summary: 'Error',
227
+ detail: 'Failed to process file content'
228
+ });
229
+ return;
230
+ }
231
+ const requestBody = {
232
+ fileName: this.uploadedFileName,
233
+ fileExtension: this.getFileExtension(this.uploadedFileName),
234
+ fileContent: fileBase64,
235
+ mappings: this.form.value,
236
+ headers: this.excelHeaders,
237
+ fileSize: this.fileContent instanceof ArrayBuffer ? this.fileContent.byteLength : 0
238
+ };
239
+ this.restService
240
+ .request({
241
+ method: 'POST',
242
+ url: this.config.apiUrl,
243
+ body: requestBody,
244
+ headers: {
245
+ 'Content-Type': 'application/json'
246
+ }
247
+ }, { apiName: this.config.apiName })
248
+ .pipe(takeUntil(this.destroy$))
249
+ .subscribe({
250
+ next: (response) => {
251
+ this.loading = false;
252
+ this.messageService.add({
253
+ severity: 'success',
254
+ summary: 'Success',
255
+ detail: 'File imported successfully'
256
+ });
257
+ this.importComplete.emit(response);
258
+ this.ref.close(response);
259
+ },
260
+ error: (err) => {
261
+ this.loading = false;
262
+ console.error('Import error:', err);
263
+ this.messageService.add({
264
+ severity: 'error',
265
+ summary: 'Error',
266
+ detail: 'Failed to import file'
267
+ });
268
+ this.importError.emit(err);
269
+ },
270
+ });
271
+ }
272
+ // Update clearFileUpload to also clear file content
273
+ clearFileUpload(event) {
274
+ if (event.options && typeof event.options.clear === 'function') {
275
+ event.options.clear();
276
+ }
277
+ this.uploadedFileName = null;
278
+ this.fileContent = null;
279
+ }
280
+ initializeForm() {
281
+ const formConfig = {};
282
+ this.mappingFields.forEach(field => {
283
+ if (field.key) {
284
+ // Set default value to first header if available
285
+ formConfig[field.key] = [this.excelHeaders[0] || '', Validators.required];
286
+ }
287
+ });
288
+ this.form = this.fb.group(formConfig);
289
+ }
290
+ onCancel() {
291
+ if (!this.loading) {
292
+ this.ref.close(false);
293
+ }
294
+ }
295
+ ngOnDestroy() {
296
+ this.destroy$.next();
297
+ this.destroy$.complete();
298
+ }
299
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportComponent, deps: [{ token: i1.DynamicDialogRef }, { token: i1.DynamicDialogConfig }], target: i0.ɵɵFactoryTarget.Component });
300
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.8", type: ExcelImportComponent, isStandalone: true, selector: "app-excel-import", inputs: { config: "config" }, outputs: { importComplete: "importComplete", importError: "importError" }, providers: [MessageService], ngImport: i0, template: `
301
+ <p-toast></p-toast>
302
+ <div class="p-4 space-y-4">
303
+ <p-steps [model]="steps" [(activeIndex)]="activeStep" class="mb-4"></p-steps>
304
+
305
+ <form [formGroup]="form" (ngSubmit)="onSubmit()">
306
+ <ng-container [ngSwitch]="activeStep">
307
+ <!-- Step 1: Upload File -->
308
+ <div *ngSwitchCase="0" class="p-4">
309
+ <!-- Download template link -->
310
+
311
+
312
+ <!-- File upload -->
313
+ <p-fileUpload
314
+ name="excelFile"
315
+ mode="basic"
316
+ chooseIcon="pi pi-upload"
317
+ chooseLabel="{{ 'chooseFile' | translate }}"
318
+ (onSelect)="onFileUpload($event)"
319
+ [accept]="config.acceptedFileTypes || '.xls,.xlsx,.csv'"
320
+ [maxFileSize]="config.maxFileSize || 10000000"
321
+ [showUploadButton]="false"
322
+ [showCancelButton]="false"
323
+ >
324
+ </p-fileUpload>
325
+
326
+ <!-- Upload status -->
327
+ <p *ngIf="uploadedFileName" class="mt-2 text-green-600">
328
+ {{ uploadedFileName }}
329
+ </p>
330
+ <p *ngIf="uploadError" class="mt-2 text-red-600">
331
+ {{ uploadError }}
332
+ </p>
333
+ </div>
334
+ <p>
335
+ <a
336
+ [href]="env.apiUrl+config.templateUrl"
337
+ download
338
+ class="text-blue-600 hover:underline flex items-center gap-1"
339
+ >
340
+ <i class="pi pi-download"></i>
341
+ {{ 'downloadTemplate' | translate }}
342
+ </a>
343
+ </p>
344
+
345
+
346
+ <!-- Step 2: Column Mapping -->
347
+ <div *ngSwitchCase="1" class="p-4">
348
+ <formly-form [form]="form" [fields]="mappingFields" [model]="model"></formly-form>
349
+ </div>
350
+
351
+ <!-- Step 3: Review -->
352
+ <div *ngSwitchCase="2" class="p-4">
353
+ <p class="text-gray-700 mb-4">
354
+ {{ 'importReviewMessage' | translate }}
355
+ </p>
356
+ <div class="bg-gray-100 p-3 rounded">
357
+ <p><strong>{{ 'fileName' | translate }}:</strong> {{ uploadedFileName }}</p>
358
+ <p><strong>{{ 'selectedMappings' | translate }}:</strong></p>
359
+ <ul class="list-disc list-inside ml-4">
360
+ <li *ngFor="let field of mappingFields">
361
+ {{ field.props?.label }}: {{ getModelValue(field, model) }}
362
+ </li>
363
+ </ul>
364
+ </div>
365
+ </div>
366
+ </ng-container>
367
+
368
+ <!-- Footer Buttons -->
369
+ <div class="flex justify-between mt-6 pt-4 border-t">
370
+ <div>
371
+ <button
372
+ pButton
373
+ type="button"
374
+ [label]="'back' | translate"
375
+ icon="pi pi-arrow-left"
376
+ (click)="prevStep()"
377
+ [disabled]="activeStep === 0 || loading"
378
+ class="p-button-text"
379
+ ></button>
380
+ </div>
381
+
382
+ <div class="flex gap-2">
383
+ <button
384
+ pButton
385
+ type="button"
386
+ [label]="'next' | translate"
387
+ icon="pi pi-arrow-right"
388
+ iconPos="right"
389
+ (click)="nextStep()"
390
+ *ngIf="activeStep < 2"
391
+ [disabled]="!canProceed() || loading"
392
+ ></button>
393
+
394
+ <button
395
+ pButton
396
+ type="submit"
397
+ [label]="loading ? ('uploading' | translate) : ('save' | translate)"
398
+ icon="pi pi-check"
399
+ *ngIf="activeStep === 2"
400
+ [disabled]="loading"
401
+ [loading]="loading"
402
+ class="p-button-primary"
403
+ ></button>
404
+
405
+ <button
406
+ pButton
407
+ type="button"
408
+ [label]="'cancel' | translate"
409
+ severity="secondary"
410
+ (click)="onCancel()"
411
+ [disabled]="loading"
412
+ ></button>
413
+ </div>
414
+ </div>
415
+ </form>
416
+ </div>
417
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i5.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: StepsModule }, { kind: "component", type: i6.Steps, selector: "p-steps", inputs: ["activeIndex", "model", "readonly", "style", "styleClass", "exact"], outputs: ["activeIndexChange"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i7.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }] });
418
+ }
419
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: ExcelImportComponent, decorators: [{
420
+ type: Component,
421
+ args: [{
422
+ selector: 'app-excel-import',
423
+ standalone: true,
424
+ providers: [MessageService],
425
+ template: `
426
+ <p-toast></p-toast>
427
+ <div class="p-4 space-y-4">
428
+ <p-steps [model]="steps" [(activeIndex)]="activeStep" class="mb-4"></p-steps>
429
+
430
+ <form [formGroup]="form" (ngSubmit)="onSubmit()">
431
+ <ng-container [ngSwitch]="activeStep">
432
+ <!-- Step 1: Upload File -->
433
+ <div *ngSwitchCase="0" class="p-4">
434
+ <!-- Download template link -->
435
+
436
+
437
+ <!-- File upload -->
438
+ <p-fileUpload
439
+ name="excelFile"
440
+ mode="basic"
441
+ chooseIcon="pi pi-upload"
442
+ chooseLabel="{{ 'chooseFile' | translate }}"
443
+ (onSelect)="onFileUpload($event)"
444
+ [accept]="config.acceptedFileTypes || '.xls,.xlsx,.csv'"
445
+ [maxFileSize]="config.maxFileSize || 10000000"
446
+ [showUploadButton]="false"
447
+ [showCancelButton]="false"
448
+ >
449
+ </p-fileUpload>
450
+
451
+ <!-- Upload status -->
452
+ <p *ngIf="uploadedFileName" class="mt-2 text-green-600">
453
+ {{ uploadedFileName }}
454
+ </p>
455
+ <p *ngIf="uploadError" class="mt-2 text-red-600">
456
+ {{ uploadError }}
457
+ </p>
458
+ </div>
459
+ <p>
460
+ <a
461
+ [href]="env.apiUrl+config.templateUrl"
462
+ download
463
+ class="text-blue-600 hover:underline flex items-center gap-1"
464
+ >
465
+ <i class="pi pi-download"></i>
466
+ {{ 'downloadTemplate' | translate }}
467
+ </a>
468
+ </p>
469
+
470
+
471
+ <!-- Step 2: Column Mapping -->
472
+ <div *ngSwitchCase="1" class="p-4">
473
+ <formly-form [form]="form" [fields]="mappingFields" [model]="model"></formly-form>
474
+ </div>
475
+
476
+ <!-- Step 3: Review -->
477
+ <div *ngSwitchCase="2" class="p-4">
478
+ <p class="text-gray-700 mb-4">
479
+ {{ 'importReviewMessage' | translate }}
480
+ </p>
481
+ <div class="bg-gray-100 p-3 rounded">
482
+ <p><strong>{{ 'fileName' | translate }}:</strong> {{ uploadedFileName }}</p>
483
+ <p><strong>{{ 'selectedMappings' | translate }}:</strong></p>
484
+ <ul class="list-disc list-inside ml-4">
485
+ <li *ngFor="let field of mappingFields">
486
+ {{ field.props?.label }}: {{ getModelValue(field, model) }}
487
+ </li>
488
+ </ul>
489
+ </div>
490
+ </div>
491
+ </ng-container>
492
+
493
+ <!-- Footer Buttons -->
494
+ <div class="flex justify-between mt-6 pt-4 border-t">
495
+ <div>
496
+ <button
497
+ pButton
498
+ type="button"
499
+ [label]="'back' | translate"
500
+ icon="pi pi-arrow-left"
501
+ (click)="prevStep()"
502
+ [disabled]="activeStep === 0 || loading"
503
+ class="p-button-text"
504
+ ></button>
505
+ </div>
506
+
507
+ <div class="flex gap-2">
508
+ <button
509
+ pButton
510
+ type="button"
511
+ [label]="'next' | translate"
512
+ icon="pi pi-arrow-right"
513
+ iconPos="right"
514
+ (click)="nextStep()"
515
+ *ngIf="activeStep < 2"
516
+ [disabled]="!canProceed() || loading"
517
+ ></button>
518
+
519
+ <button
520
+ pButton
521
+ type="submit"
522
+ [label]="loading ? ('uploading' | translate) : ('save' | translate)"
523
+ icon="pi pi-check"
524
+ *ngIf="activeStep === 2"
525
+ [disabled]="loading"
526
+ [loading]="loading"
527
+ class="p-button-primary"
528
+ ></button>
529
+
530
+ <button
531
+ pButton
532
+ type="button"
533
+ [label]="'cancel' | translate"
534
+ severity="secondary"
535
+ (click)="onCancel()"
536
+ [disabled]="loading"
537
+ ></button>
538
+ </div>
539
+ </div>
540
+ </form>
541
+ </div>
542
+ `,
543
+ imports: [
544
+ CommonModule,
545
+ ReactiveFormsModule,
546
+ FormsModule,
547
+ FormlyForm,
548
+ TranslateModule,
549
+ ButtonModule,
550
+ FileUploadModule,
551
+ StepsModule,
552
+ ToastModule
553
+ ],
554
+ }]
555
+ }], ctorParameters: () => [{ type: i1.DynamicDialogRef }, { type: i1.DynamicDialogConfig }], propDecorators: { config: [{
556
+ type: Input
557
+ }], importComplete: [{
558
+ type: Output
559
+ }], importError: [{
560
+ type: Output
561
+ }] } });
562
+
563
+ /**
564
+ * Generated bundle index. Do not edit.
565
+ */
566
+
567
+ export { ExcelImportComponent, ExcelImportModule };
568
+ //# sourceMappingURL=elite.framework-ng.ui.core-excel-import.mjs.map