@flusys/ng-email 1.0.0-rc

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 @@
1
+ {"version":3,"file":"flusys-ng-email-email-config-form.component-BK195yNS.mjs","sources":["../../../projects/ng-email/pages/config/email-config-form.component.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n signal,\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport { AngularModule, PrimeModule } from '@flusys/ng-shared';\nimport { MessageService } from 'primeng/api';\nimport { EmailProviderEnum } from '../../enums/email-provider.enum';\nimport { IEmailConfig } from '../../interfaces/email-config.interface';\nimport { EmailConfigApiService } from '../../services/email-config-api.service';\n\n/**\n * Email configuration form component (create/edit)\n */\n@Component({\n selector: 'lib-email-config-form',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule],\n providers: [MessageService],\n template: `\n <div class=\"card\">\n <!-- Header -->\n <div class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\">\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold m-0\">\n {{ isEditMode() ? 'Edit Configuration' : 'New Configuration' }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n Company: {{ currentCompanyName() }}\n </p>\n }\n </div>\n </div>\n\n <!-- Form Fields -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Common Fields -->\n <div class=\"field\">\n <label for=\"name\" class=\"block font-medium mb-2\"\n >Configuration Name *</label\n >\n <input\n pInputText\n id=\"name\"\n [ngModel]=\"formModel.name\"\n (ngModelChange)=\"updateFormModel('name', $event)\"\n class=\"w-full\"\n placeholder=\"e.g., Production SMTP\"\n />\n </div>\n\n <div class=\"field\">\n <label for=\"provider\" class=\"block font-medium mb-2\"\n >Email Provider *</label\n >\n <p-select\n id=\"provider\"\n [options]=\"providerOptions\"\n [ngModel]=\"formModel.provider\"\n (ngModelChange)=\"updateFormModel('provider', $event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select provider\"\n class=\"w-full\"\n />\n </div>\n\n <div class=\"field\">\n <label for=\"fromEmail\" class=\"block font-medium mb-2\"\n >From Email</label\n >\n <input\n pInputText\n id=\"fromEmail\"\n [ngModel]=\"formModel.fromEmail\"\n (ngModelChange)=\"updateFormModel('fromEmail', $event)\"\n class=\"w-full\"\n placeholder=\"noreply@example.com\"\n />\n </div>\n\n <div class=\"field\">\n <label for=\"fromName\" class=\"block font-medium mb-2\"\n >From Name</label\n >\n <input\n pInputText\n id=\"fromName\"\n [ngModel]=\"formModel.fromName\"\n (ngModelChange)=\"updateFormModel('fromName', $event)\"\n class=\"w-full\"\n placeholder=\"FLUSYS\"\n />\n </div>\n\n <div class=\"field flex items-center gap-2\">\n <p-toggleswitch [ngModel]=\"formModel.isActive\" (ngModelChange)=\"updateFormModel('isActive', $event)\" />\n <label>Active</label>\n </div>\n\n <div class=\"field flex items-center gap-2\">\n <p-toggleswitch [ngModel]=\"formModel.isDefault\" (ngModelChange)=\"updateFormModel('isDefault', $event)\" />\n <label>Set as Default</label>\n </div>\n </div>\n\n <!-- SMTP Fields -->\n @if (formModel.provider === providerEnum.SMTP) {\n <div class=\"border-t border-surface mt-4 pt-4\">\n <h3 class=\"font-semibold mb-4\">SMTP Settings</h3>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field\">\n <label for=\"smtpHost\" class=\"block font-medium mb-2\"\n >SMTP Host *</label\n >\n <input\n pInputText\n id=\"smtpHost\"\n [ngModel]=\"formModel.smtpHost\"\n (ngModelChange)=\"updateFormModel('smtpHost', $event)\"\n class=\"w-full\"\n placeholder=\"smtp.gmail.com\"\n />\n </div>\n <div class=\"field\">\n <label for=\"smtpPort\" class=\"block font-medium mb-2\"\n >Port *</label\n >\n <p-inputNumber\n id=\"smtpPort\"\n [ngModel]=\"formModel.smtpPort\"\n (ngModelChange)=\"updateFormModel('smtpPort', $event)\"\n [useGrouping]=\"false\"\n class=\"w-full\"\n placeholder=\"587\"\n />\n </div>\n <div class=\"field\">\n <label for=\"smtpUser\" class=\"block font-medium mb-2\"\n >Username *</label\n >\n <input\n pInputText\n id=\"smtpUser\"\n [ngModel]=\"formModel.smtpUser\"\n (ngModelChange)=\"updateFormModel('smtpUser', $event)\"\n class=\"w-full\"\n placeholder=\"user@gmail.com\"\n />\n </div>\n <div class=\"field\">\n <label for=\"smtpPass\" class=\"block font-medium mb-2\"\n >Password *</label\n >\n <p-password\n id=\"smtpPass\"\n [ngModel]=\"formModel.smtpPass\"\n (ngModelChange)=\"updateFormModel('smtpPass', $event)\"\n [feedback]=\"false\"\n [toggleMask]=\"true\"\n styleClass=\"w-full\"\n inputStyleClass=\"w-full\"\n placeholder=\"App password\"\n />\n </div>\n <div class=\"field flex items-center gap-2\">\n <p-toggleswitch [ngModel]=\"formModel.smtpSecure\" (ngModelChange)=\"updateFormModel('smtpSecure', $event)\" />\n <label>Use SSL/TLS (Port 465)</label>\n </div>\n </div>\n </div>\n }\n\n <!-- SendGrid Fields -->\n @if (formModel.provider === providerEnum.SENDGRID) {\n <div class=\"border-t border-surface mt-4 pt-4\">\n <h3 class=\"font-semibold mb-4\">SendGrid Settings</h3>\n <div class=\"grid grid-cols-1 gap-4\">\n <div class=\"field\">\n <label for=\"sendgridApiKey\" class=\"block font-medium mb-2\"\n >API Key *</label\n >\n <p-password\n id=\"sendgridApiKey\"\n [ngModel]=\"formModel.sendgridApiKey\"\n (ngModelChange)=\"updateFormModel('sendgridApiKey', $event)\"\n [feedback]=\"false\"\n [toggleMask]=\"true\"\n styleClass=\"w-full\"\n inputStyleClass=\"w-full\"\n placeholder=\"SG.xxxx...\"\n />\n </div>\n </div>\n </div>\n }\n\n <!-- Mailgun Fields -->\n @if (formModel.provider === providerEnum.MAILGUN) {\n <div class=\"border-t border-surface mt-4 pt-4\">\n <h3 class=\"font-semibold mb-4\">Mailgun Settings</h3>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field\">\n <label for=\"mailgunApiKey\" class=\"block font-medium mb-2\"\n >API Key *</label\n >\n <p-password\n id=\"mailgunApiKey\"\n [ngModel]=\"formModel.mailgunApiKey\"\n (ngModelChange)=\"updateFormModel('mailgunApiKey', $event)\"\n [feedback]=\"false\"\n [toggleMask]=\"true\"\n styleClass=\"w-full\"\n inputStyleClass=\"w-full\"\n placeholder=\"key-xxxx...\"\n />\n </div>\n <div class=\"field\">\n <label for=\"mailgunDomain\" class=\"block font-medium mb-2\"\n >Domain *</label\n >\n <input\n pInputText\n id=\"mailgunDomain\"\n [ngModel]=\"formModel.mailgunDomain\"\n (ngModelChange)=\"updateFormModel('mailgunDomain', $event)\"\n class=\"w-full\"\n placeholder=\"mg.example.com\"\n />\n </div>\n <div class=\"field\">\n <label for=\"mailgunRegion\" class=\"block font-medium mb-2\"\n >Region</label\n >\n <p-select\n id=\"mailgunRegion\"\n [options]=\"regionOptions\"\n [ngModel]=\"formModel.mailgunRegion\"\n (ngModelChange)=\"updateFormModel('mailgunRegion', $event)\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select region\"\n class=\"w-full\"\n />\n </div>\n </div>\n </div>\n }\n\n <!-- Form Actions -->\n <div class=\"flex justify-end gap-2 mt-6 pt-4 border-t border-surface\">\n <p-button\n label=\"Cancel\"\n severity=\"secondary\"\n [outlined]=\"true\"\n routerLink=\"../\"\n />\n <p-button\n [label]=\"isEditMode() ? 'Update' : 'Create'\"\n icon=\"pi pi-save\"\n [loading]=\"isLoading()\"\n (onClick)=\"onSave()\"\n />\n </div>\n </div>\n\n <p-toast />\n `,\n})\nexport class EmailConfigFormComponent {\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly configService = inject(EmailConfigApiService);\n private readonly messageService = inject(MessageService);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly companyContext = inject(LAYOUT_AUTH_STATE, { optional: true });\n\n // Route params as signal\n private readonly routeParams = toSignal(this.route.paramMap);\n\n readonly providerEnum = EmailProviderEnum;\n\n readonly showCompanyInfo = computed(\n () => this.appConfig.enableCompanyFeature && !!this.companyContext,\n );\n readonly currentCompanyName = computed(\n () => this.companyContext?.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n readonly isLoading = signal(false);\n readonly existingConfig = signal<IEmailConfig | null>(null);\n readonly isEditMode = computed(() => !!this.existingConfig());\n\n readonly providerOptions = [\n { label: 'SMTP', value: EmailProviderEnum.SMTP },\n { label: 'SendGrid', value: EmailProviderEnum.SENDGRID },\n { label: 'Mailgun', value: EmailProviderEnum.MAILGUN },\n ];\n\n readonly regionOptions = [\n { label: 'US', value: 'us' },\n { label: 'EU', value: 'eu' },\n ];\n\n /** Form model as signal for zoneless change detection */\n private readonly _formModel = signal({\n id: '',\n name: '',\n provider: EmailProviderEnum.SMTP as EmailProviderEnum,\n fromEmail: '',\n fromName: '',\n isActive: true,\n isDefault: false,\n // SMTP\n smtpHost: '',\n smtpPort: 587,\n smtpUser: '',\n smtpPass: '',\n smtpSecure: false,\n // SendGrid\n sendgridApiKey: '',\n // Mailgun\n mailgunApiKey: '',\n mailgunDomain: '',\n mailgunRegion: 'us',\n });\n\n /** Expose form model for template binding */\n get formModel() {\n return this._formModel();\n }\n\n /** Update form model field - triggers change detection */\n updateFormModel<K extends keyof ReturnType<typeof this._formModel>>(\n field: K,\n value: ReturnType<typeof this._formModel>[K],\n ): void {\n this._formModel.update((m) => ({ ...m, [field]: value }));\n }\n\n constructor() {\n // Effect to handle route-based initialization\n effect(() => {\n const params = this.routeParams();\n if (!params) return;\n\n const id = params.get('id');\n if (id) {\n this.loadConfig(id);\n }\n });\n }\n\n async loadConfig(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.configService.findByIdAsync(id);\n if (response.success && response.data) {\n const config = response.data;\n this.existingConfig.set(config);\n\n this._formModel.set({\n id: config.id,\n name: config.name,\n provider: config.provider,\n fromEmail: config.fromEmail || '',\n fromName: config.fromName || '',\n isActive: config.isActive,\n isDefault: config.isDefault ?? false,\n // SMTP\n smtpHost: config.config?.['host'] || '',\n smtpPort: config.config?.['port'] || 587,\n smtpUser: config.config?.['auth']?.['user'] || '',\n smtpPass: config.config?.['auth']?.['pass'] || '',\n smtpSecure: config.config?.['secure'] || false,\n // SendGrid\n sendgridApiKey: config.config?.['apiKey'] || '',\n // Mailgun\n mailgunApiKey: config.config?.['apiKey'] || '',\n mailgunDomain: config.config?.['domain'] || '',\n mailgunRegion: config.config?.['region'] || 'us',\n });\n }\n } finally {\n this.isLoading.set(false);\n }\n }\n\n async onSave(): Promise<void> {\n if (!this.formModel.name || !this.formModel.provider) {\n this.messageService.add({\n severity: 'warn',\n summary: 'Validation',\n detail: 'Please fill in all required fields.',\n });\n return;\n }\n\n // Build provider-specific config\n let config: Record<string, any> = {};\n switch (this.formModel.provider) {\n case EmailProviderEnum.SMTP:\n config = {\n host: this.formModel.smtpHost,\n port: this.formModel.smtpPort,\n secure: this.formModel.smtpSecure,\n auth: {\n user: this.formModel.smtpUser,\n pass: this.formModel.smtpPass,\n },\n };\n break;\n case EmailProviderEnum.SENDGRID:\n config = {\n apiKey: this.formModel.sendgridApiKey,\n };\n break;\n case EmailProviderEnum.MAILGUN:\n config = {\n apiKey: this.formModel.mailgunApiKey,\n domain: this.formModel.mailgunDomain,\n region: this.formModel.mailgunRegion,\n };\n break;\n }\n\n this.isLoading.set(true);\n try {\n if (this.isEditMode()) {\n await this.configService.updateAsync({\n id: this.formModel.id,\n name: this.formModel.name,\n provider: this.formModel.provider,\n config,\n fromEmail: this.formModel.fromEmail || undefined,\n fromName: this.formModel.fromName || undefined,\n isActive: this.formModel.isActive,\n isDefault: this.formModel.isDefault,\n });\n } else {\n // ApiResourceService uses UpdateDto which requires id, cast to any for insert\n await this.configService.insertAsync({\n name: this.formModel.name,\n provider: this.formModel.provider,\n config,\n fromEmail: this.formModel.fromEmail || undefined,\n fromName: this.formModel.fromName || undefined,\n isActive: this.formModel.isActive,\n isDefault: this.formModel.isDefault,\n } as any);\n }\n\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: `Configuration ${this.isEditMode() ? 'updated' : 'created'} successfully.`,\n });\n\n this.router.navigate(['../'], { relativeTo: this.route });\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this.isLoading.set(false);\n }\n }\n}\n"],"names":["i3","i7","i9"],"mappings":"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"}
@@ -0,0 +1,541 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router } from '@angular/router';
4
+ import { firstValueFrom } from 'rxjs';
5
+ import { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';
6
+ import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
7
+ import { EMAIL_CONFIG_PERMISSIONS, AngularModule, PrimeModule, HasPermissionDirective } from '@flusys/ng-shared';
8
+ import { ConfirmationService, MessageService } from 'primeng/api';
9
+ import { EmailConfigApiService, EmailProviderEnum } from './flusys-ng-email.mjs';
10
+ import * as i1 from '@angular/forms';
11
+ import * as i2 from 'primeng/button';
12
+ import * as i3 from 'primeng/confirmdialog';
13
+ import * as i4 from 'primeng/dialog';
14
+ import * as i5 from 'primeng/inputtext';
15
+ import * as i7 from 'primeng/table';
16
+ import * as i8 from 'primeng/tag';
17
+ import * as i8$1 from 'primeng/toast';
18
+ import * as i10 from 'primeng/tooltip';
19
+ import * as i11 from '@angular/common';
20
+
21
+ /**
22
+ * Email configuration list component
23
+ */
24
+ class EmailConfigListComponent {
25
+ // Permission constants for template
26
+ EMAIL_CONFIG_PERMISSIONS = EMAIL_CONFIG_PERMISSIONS;
27
+ router = inject(Router);
28
+ configService = inject(EmailConfigApiService);
29
+ confirmationService = inject(ConfirmationService);
30
+ messageService = inject(MessageService);
31
+ appConfig = inject(APP_CONFIG);
32
+ companyContext = inject(LAYOUT_AUTH_STATE, { optional: true });
33
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
34
+ configs = signal([], ...(ngDevMode ? [{ debugName: "configs" }] : []));
35
+ totalRecords = signal(0, ...(ngDevMode ? [{ debugName: "totalRecords" }] : []));
36
+ pageSize = signal(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
37
+ first = signal(0, ...(ngDevMode ? [{ debugName: "first" }] : []));
38
+ showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature && !!this.companyContext, ...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : []));
39
+ currentCompanyName = computed(() => this.companyContext?.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
40
+ // Test dialog state (signals for zoneless change detection)
41
+ showTestDialog = signal(false, ...(ngDevMode ? [{ debugName: "showTestDialog" }] : []));
42
+ selectedConfig = signal(null, ...(ngDevMode ? [{ debugName: "selectedConfig" }] : []));
43
+ isSendingTest = signal(false, ...(ngDevMode ? [{ debugName: "isSendingTest" }] : []));
44
+ testRecipient = signal('', ...(ngDevMode ? [{ debugName: "testRecipient" }] : []));
45
+ onCreate() {
46
+ this.router.navigate(['/email/configs/new']);
47
+ }
48
+ onEdit(configId) {
49
+ this.router.navigate(['/email/configs', configId]);
50
+ }
51
+ async loadConfigs() {
52
+ this.isLoading.set(true);
53
+ try {
54
+ const response = await firstValueFrom(this.configService.getAll('', {
55
+ pagination: {
56
+ currentPage: Math.floor(this.first() / this.pageSize()),
57
+ pageSize: this.pageSize(),
58
+ },
59
+ filter: {},
60
+ select: [],
61
+ sort: {},
62
+ }));
63
+ if (response.success) {
64
+ this.configs.set(response.data ?? []);
65
+ this.totalRecords.set(response.meta?.total ?? 0);
66
+ }
67
+ }
68
+ finally {
69
+ this.isLoading.set(false);
70
+ }
71
+ }
72
+ onLazyLoad(event) {
73
+ this.first.set(event.first ?? 0);
74
+ this.pageSize.set(event.rows ?? 10);
75
+ this.loadConfigs();
76
+ }
77
+ getProviderIcon(provider) {
78
+ switch (provider) {
79
+ case EmailProviderEnum.SMTP:
80
+ return 'pi pi-server';
81
+ case EmailProviderEnum.SENDGRID:
82
+ return 'pi pi-cloud';
83
+ case EmailProviderEnum.MAILGUN:
84
+ return 'pi pi-cloud';
85
+ default:
86
+ return 'pi pi-envelope';
87
+ }
88
+ }
89
+ getProviderLabel(provider) {
90
+ switch (provider) {
91
+ case EmailProviderEnum.SMTP:
92
+ return 'SMTP';
93
+ case EmailProviderEnum.SENDGRID:
94
+ return 'SendGrid';
95
+ case EmailProviderEnum.MAILGUN:
96
+ return 'Mailgun';
97
+ default:
98
+ return provider || '';
99
+ }
100
+ }
101
+ getProviderSeverity(provider) {
102
+ switch (provider) {
103
+ case EmailProviderEnum.SMTP:
104
+ return 'info';
105
+ case EmailProviderEnum.SENDGRID:
106
+ return 'success';
107
+ case EmailProviderEnum.MAILGUN:
108
+ return 'warn';
109
+ default:
110
+ return 'secondary';
111
+ }
112
+ }
113
+ onTest(config) {
114
+ this.selectedConfig.set(config);
115
+ this.testRecipient.set('');
116
+ this.showTestDialog.set(true);
117
+ }
118
+ async sendTestEmail() {
119
+ const config = this.selectedConfig();
120
+ const recipient = this.testRecipient();
121
+ if (!config || !recipient) {
122
+ this.messageService.add({
123
+ severity: 'warn',
124
+ summary: 'Validation',
125
+ detail: 'Please enter a recipient email address.',
126
+ });
127
+ return;
128
+ }
129
+ this.isSendingTest.set(true);
130
+ try {
131
+ const response = await firstValueFrom(this.configService.sendTest(config.id, recipient));
132
+ if (response.data?.success) {
133
+ this.messageService.add({
134
+ severity: 'success',
135
+ summary: 'Success',
136
+ detail: `Test email sent successfully! Message ID: ${response.data.messageId}`,
137
+ });
138
+ this.showTestDialog.set(false);
139
+ }
140
+ else {
141
+ this.messageService.add({
142
+ severity: 'error',
143
+ summary: 'Error',
144
+ detail: response.data?.error || 'Failed to send test email.',
145
+ });
146
+ }
147
+ }
148
+ catch {
149
+ // Error toast handled by global interceptor
150
+ }
151
+ finally {
152
+ this.isSendingTest.set(false);
153
+ }
154
+ }
155
+ onDelete(config) {
156
+ this.confirmationService.confirm({
157
+ message: `Are you sure you want to delete "${config.name}"?`,
158
+ header: 'Delete Configuration',
159
+ icon: 'pi pi-exclamation-triangle',
160
+ acceptButtonStyleClass: 'p-button-danger',
161
+ accept: async () => {
162
+ try {
163
+ await this.configService.deleteAsync({ id: config.id, type: 'delete' });
164
+ this.messageService.add({
165
+ severity: 'success',
166
+ summary: 'Success',
167
+ detail: 'Configuration deleted successfully.',
168
+ });
169
+ this.loadConfigs();
170
+ }
171
+ catch {
172
+ // Error toast handled by global interceptor
173
+ }
174
+ },
175
+ });
176
+ }
177
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
178
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: EmailConfigListComponent, isStandalone: true, selector: "lib-email-config-list", providers: [ConfirmationService, MessageService], ngImport: i0, template: `
179
+ <div class="card">
180
+ <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4">
181
+ <div>
182
+ <h3 class="text-lg sm:text-xl font-semibold m-0">Email Configurations</h3>
183
+ @if (showCompanyInfo()) {
184
+ <p class="text-sm text-muted-color mt-1">
185
+ Company: {{ currentCompanyName() }}
186
+ </p>
187
+ }
188
+ </div>
189
+ <p-button
190
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.CREATE"
191
+ label="New Configuration"
192
+ icon="pi pi-plus"
193
+ (onClick)="onCreate()"
194
+ styleClass="w-full sm:w-auto"
195
+ />
196
+ </div>
197
+
198
+ <div class="overflow-x-auto -mx-4 sm:mx-0">
199
+ <p-table
200
+ [value]="configs()"
201
+ [loading]="isLoading()"
202
+ [paginator]="totalRecords() > 0"
203
+ [rows]="pageSize()"
204
+ [first]="first()"
205
+ [totalRecords]="totalRecords()"
206
+ [lazy]="true"
207
+ (onLazyLoad)="onLazyLoad($event)"
208
+ [rowsPerPageOptions]="[10, 25, 50]"
209
+ styleClass="p-datatable-sm"
210
+ [tableStyle]="{ 'min-width': '50rem' }"
211
+ >
212
+ <ng-template #header>
213
+ <tr>
214
+ <th>Name</th>
215
+ <th>Provider</th>
216
+ <th class="hidden md:table-cell">From Email</th>
217
+ <th>Status</th>
218
+ <th class="hidden lg:table-cell">Created</th>
219
+ <th class="w-[120px]">Actions</th>
220
+ </tr>
221
+ </ng-template>
222
+
223
+ <ng-template #body let-config>
224
+ <tr>
225
+ <td>
226
+ <i [class]="getProviderIcon(config.provider)" class="mr-2 text-muted-color"></i>
227
+ {{ config.name }}
228
+ @if (config.isDefault) {
229
+ <p-tag value="Default" severity="contrast" class="ml-2" />
230
+ }
231
+ </td>
232
+ <td>
233
+ <p-tag
234
+ [value]="getProviderLabel(config.provider)"
235
+ [severity]="getProviderSeverity(config.provider)"
236
+ />
237
+ </td>
238
+ <td class="hidden md:table-cell">{{ config.fromEmail || '-' }}</td>
239
+ <td>
240
+ <p-tag
241
+ [value]="config.isActive ? 'Active' : 'Inactive'"
242
+ [severity]="config.isActive ? 'success' : 'secondary'"
243
+ />
244
+ </td>
245
+ <td class="hidden lg:table-cell">{{ config.createdAt | date: 'short' }}</td>
246
+ <td>
247
+ <div class="flex gap-1">
248
+ <p-button
249
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.UPDATE"
250
+ icon="pi pi-send"
251
+ [text]="true"
252
+ size="small"
253
+ pTooltip="Test"
254
+ (onClick)="onTest(config)"
255
+ />
256
+ <p-button
257
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.UPDATE"
258
+ icon="pi pi-pencil"
259
+ [text]="true"
260
+ severity="secondary"
261
+ size="small"
262
+ pTooltip="Edit"
263
+ (onClick)="onEdit(config.id)"
264
+ />
265
+ <p-button
266
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.DELETE"
267
+ icon="pi pi-trash"
268
+ [text]="true"
269
+ severity="danger"
270
+ size="small"
271
+ pTooltip="Delete"
272
+ (onClick)="onDelete(config)"
273
+ />
274
+ </div>
275
+ </td>
276
+ </tr>
277
+ </ng-template>
278
+
279
+ <ng-template #emptymessage>
280
+ <tr>
281
+ <td colspan="6" class="text-center py-4 text-muted-color">
282
+ No email configurations found. Add a provider to start sending emails.
283
+ </td>
284
+ </tr>
285
+ </ng-template>
286
+ </p-table>
287
+ </div>
288
+ </div>
289
+
290
+ <!-- Test Email Dialog -->
291
+ <p-dialog
292
+ header="Test Email Configuration"
293
+ [visible]="showTestDialog()"
294
+ (visibleChange)="showTestDialog.set($event)"
295
+ [modal]="true"
296
+ [style]="{ width: '95vw', maxWidth: '400px' }"
297
+ [breakpoints]="{ '575px': '95vw' }"
298
+ >
299
+ <div class="grid gap-4">
300
+ <div class="field">
301
+ <label class="block font-medium mb-2">Configuration</label>
302
+ <input
303
+ pInputText
304
+ [value]="selectedConfig()?.name || ''"
305
+ class="w-full"
306
+ [disabled]="true"
307
+ />
308
+ </div>
309
+
310
+ <div class="field">
311
+ <label class="block font-medium mb-2">Provider</label>
312
+ <p-tag
313
+ [value]="getProviderLabel(selectedConfig()?.provider || '')"
314
+ [severity]="getProviderSeverity(selectedConfig()?.provider || '')"
315
+ />
316
+ </div>
317
+
318
+ <div class="field">
319
+ <label class="block font-medium mb-2">Recipient Email *</label>
320
+ <input
321
+ pInputText
322
+ [ngModel]="testRecipient()"
323
+ (ngModelChange)="testRecipient.set($event)"
324
+ class="w-full"
325
+ placeholder="recipient@example.com"
326
+ type="email"
327
+ />
328
+ <small class="text-muted-color mt-1 block">
329
+ A test email will be sent to this address
330
+ </small>
331
+ </div>
332
+ </div>
333
+
334
+ <ng-template #footer>
335
+ <p-button
336
+ label="Cancel"
337
+ severity="secondary"
338
+ [outlined]="true"
339
+ (onClick)="showTestDialog.set(false)"
340
+ />
341
+ <p-button
342
+ label="Send Test"
343
+ icon="pi pi-send"
344
+ [loading]="isSendingTest()"
345
+ (onClick)="sendTestEmail()"
346
+ />
347
+ </ng-template>
348
+ </p-dialog>
349
+
350
+ <p-confirmDialog />
351
+ <p-toast />
352
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: i4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i5.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i7.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: "component", type: i8.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: i8$1.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "motionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: i10.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "pipe", type: i11.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
353
+ }
354
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigListComponent, decorators: [{
355
+ type: Component,
356
+ args: [{
357
+ selector: 'lib-email-config-list',
358
+ standalone: true,
359
+ changeDetection: ChangeDetectionStrategy.OnPush,
360
+ imports: [AngularModule, PrimeModule, HasPermissionDirective],
361
+ providers: [ConfirmationService, MessageService],
362
+ template: `
363
+ <div class="card">
364
+ <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4">
365
+ <div>
366
+ <h3 class="text-lg sm:text-xl font-semibold m-0">Email Configurations</h3>
367
+ @if (showCompanyInfo()) {
368
+ <p class="text-sm text-muted-color mt-1">
369
+ Company: {{ currentCompanyName() }}
370
+ </p>
371
+ }
372
+ </div>
373
+ <p-button
374
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.CREATE"
375
+ label="New Configuration"
376
+ icon="pi pi-plus"
377
+ (onClick)="onCreate()"
378
+ styleClass="w-full sm:w-auto"
379
+ />
380
+ </div>
381
+
382
+ <div class="overflow-x-auto -mx-4 sm:mx-0">
383
+ <p-table
384
+ [value]="configs()"
385
+ [loading]="isLoading()"
386
+ [paginator]="totalRecords() > 0"
387
+ [rows]="pageSize()"
388
+ [first]="first()"
389
+ [totalRecords]="totalRecords()"
390
+ [lazy]="true"
391
+ (onLazyLoad)="onLazyLoad($event)"
392
+ [rowsPerPageOptions]="[10, 25, 50]"
393
+ styleClass="p-datatable-sm"
394
+ [tableStyle]="{ 'min-width': '50rem' }"
395
+ >
396
+ <ng-template #header>
397
+ <tr>
398
+ <th>Name</th>
399
+ <th>Provider</th>
400
+ <th class="hidden md:table-cell">From Email</th>
401
+ <th>Status</th>
402
+ <th class="hidden lg:table-cell">Created</th>
403
+ <th class="w-[120px]">Actions</th>
404
+ </tr>
405
+ </ng-template>
406
+
407
+ <ng-template #body let-config>
408
+ <tr>
409
+ <td>
410
+ <i [class]="getProviderIcon(config.provider)" class="mr-2 text-muted-color"></i>
411
+ {{ config.name }}
412
+ @if (config.isDefault) {
413
+ <p-tag value="Default" severity="contrast" class="ml-2" />
414
+ }
415
+ </td>
416
+ <td>
417
+ <p-tag
418
+ [value]="getProviderLabel(config.provider)"
419
+ [severity]="getProviderSeverity(config.provider)"
420
+ />
421
+ </td>
422
+ <td class="hidden md:table-cell">{{ config.fromEmail || '-' }}</td>
423
+ <td>
424
+ <p-tag
425
+ [value]="config.isActive ? 'Active' : 'Inactive'"
426
+ [severity]="config.isActive ? 'success' : 'secondary'"
427
+ />
428
+ </td>
429
+ <td class="hidden lg:table-cell">{{ config.createdAt | date: 'short' }}</td>
430
+ <td>
431
+ <div class="flex gap-1">
432
+ <p-button
433
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.UPDATE"
434
+ icon="pi pi-send"
435
+ [text]="true"
436
+ size="small"
437
+ pTooltip="Test"
438
+ (onClick)="onTest(config)"
439
+ />
440
+ <p-button
441
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.UPDATE"
442
+ icon="pi pi-pencil"
443
+ [text]="true"
444
+ severity="secondary"
445
+ size="small"
446
+ pTooltip="Edit"
447
+ (onClick)="onEdit(config.id)"
448
+ />
449
+ <p-button
450
+ *hasPermission="EMAIL_CONFIG_PERMISSIONS.DELETE"
451
+ icon="pi pi-trash"
452
+ [text]="true"
453
+ severity="danger"
454
+ size="small"
455
+ pTooltip="Delete"
456
+ (onClick)="onDelete(config)"
457
+ />
458
+ </div>
459
+ </td>
460
+ </tr>
461
+ </ng-template>
462
+
463
+ <ng-template #emptymessage>
464
+ <tr>
465
+ <td colspan="6" class="text-center py-4 text-muted-color">
466
+ No email configurations found. Add a provider to start sending emails.
467
+ </td>
468
+ </tr>
469
+ </ng-template>
470
+ </p-table>
471
+ </div>
472
+ </div>
473
+
474
+ <!-- Test Email Dialog -->
475
+ <p-dialog
476
+ header="Test Email Configuration"
477
+ [visible]="showTestDialog()"
478
+ (visibleChange)="showTestDialog.set($event)"
479
+ [modal]="true"
480
+ [style]="{ width: '95vw', maxWidth: '400px' }"
481
+ [breakpoints]="{ '575px': '95vw' }"
482
+ >
483
+ <div class="grid gap-4">
484
+ <div class="field">
485
+ <label class="block font-medium mb-2">Configuration</label>
486
+ <input
487
+ pInputText
488
+ [value]="selectedConfig()?.name || ''"
489
+ class="w-full"
490
+ [disabled]="true"
491
+ />
492
+ </div>
493
+
494
+ <div class="field">
495
+ <label class="block font-medium mb-2">Provider</label>
496
+ <p-tag
497
+ [value]="getProviderLabel(selectedConfig()?.provider || '')"
498
+ [severity]="getProviderSeverity(selectedConfig()?.provider || '')"
499
+ />
500
+ </div>
501
+
502
+ <div class="field">
503
+ <label class="block font-medium mb-2">Recipient Email *</label>
504
+ <input
505
+ pInputText
506
+ [ngModel]="testRecipient()"
507
+ (ngModelChange)="testRecipient.set($event)"
508
+ class="w-full"
509
+ placeholder="recipient@example.com"
510
+ type="email"
511
+ />
512
+ <small class="text-muted-color mt-1 block">
513
+ A test email will be sent to this address
514
+ </small>
515
+ </div>
516
+ </div>
517
+
518
+ <ng-template #footer>
519
+ <p-button
520
+ label="Cancel"
521
+ severity="secondary"
522
+ [outlined]="true"
523
+ (onClick)="showTestDialog.set(false)"
524
+ />
525
+ <p-button
526
+ label="Send Test"
527
+ icon="pi pi-send"
528
+ [loading]="isSendingTest()"
529
+ (onClick)="sendTestEmail()"
530
+ />
531
+ </ng-template>
532
+ </p-dialog>
533
+
534
+ <p-confirmDialog />
535
+ <p-toast />
536
+ `,
537
+ }]
538
+ }] });
539
+
540
+ export { EmailConfigListComponent };
541
+ //# sourceMappingURL=flusys-ng-email-email-config-list.component-DnIJdHdf.mjs.map