@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.
- package/README.md +872 -0
- package/fesm2022/flusys-ng-email-email-config-form.component-BK195yNS.mjs +713 -0
- package/fesm2022/flusys-ng-email-email-config-form.component-BK195yNS.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-email-config-list.component-DnIJdHdf.mjs +541 -0
- package/fesm2022/flusys-ng-email-email-config-list.component-DnIJdHdf.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-template-form.component-u40UX6yY.mjs +555 -0
- package/fesm2022/flusys-ng-email-template-form.component-u40UX6yY.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-template-list.component-91djzx28.mjs +636 -0
- package/fesm2022/flusys-ng-email-template-list.component-91djzx28.mjs.map +1 -0
- package/fesm2022/flusys-ng-email.mjs +579 -0
- package/fesm2022/flusys-ng-email.mjs.map +1 -0
- package/package.json +33 -0
- package/types/flusys-ng-email.d.ts +455 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-email-template-list.component-91djzx28.mjs","sources":["../../../projects/ng-email/pages/template/template-list.component.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n signal,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport { firstValueFrom } from 'rxjs';\nimport { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport { AngularModule, EMAIL_TEMPLATE_PERMISSIONS, HasPermissionDirective, PrimeModule } from '@flusys/ng-shared';\nimport { ConfirmationService, MessageService } from 'primeng/api';\nimport { IEmailConfig } from '../../interfaces/email-config.interface';\nimport { IEmailTemplate } from '../../interfaces/email-template.interface';\nimport { EmailConfigApiService } from '../../services/email-config-api.service';\nimport { EmailSendService } from '../../services/email-send.service';\nimport { EmailTemplateApiService } from '../../services/email-template-api.service';\n\n/**\n * Email template list component\n */\n@Component({\n selector: 'lib-template-list',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule, HasPermissionDirective],\n providers: [ConfirmationService, MessageService],\n template: `\n <div class=\"card\">\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\">Email Templates</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n Company: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <p-button\n *hasPermission=\"EMAIL_TEMPLATE_PERMISSIONS.CREATE\"\n label=\"New Template\"\n icon=\"pi pi-plus\"\n (onClick)=\"onCreate()\"\n styleClass=\"w-full sm:w-auto\"\n />\n </div>\n\n <div class=\"overflow-x-auto -mx-4 sm:mx-0\">\n <p-table\n [value]=\"templates()\"\n [loading]=\"isLoading()\"\n [paginator]=\"totalRecords() > 0\"\n [rows]=\"pageSize()\"\n [first]=\"first()\"\n [totalRecords]=\"totalRecords()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n styleClass=\"p-datatable-sm\"\n [tableStyle]=\"{ 'min-width': '50rem' }\"\n >\n <ng-template #header>\n <tr>\n <th>Name</th>\n <th class=\"hidden md:table-cell\">Slug</th>\n <th class=\"hidden lg:table-cell\">Subject</th>\n <th>Type</th>\n <th>Status</th>\n <th class=\"hidden xl:table-cell\">Created</th>\n <th class=\"w-[120px]\">Actions</th>\n </tr>\n </ng-template>\n\n <ng-template #body let-template>\n <tr>\n <td>\n <i class=\"pi pi-envelope mr-2 text-muted-color\"></i>\n {{ template.name }}\n </td>\n <td class=\"hidden md:table-cell\">\n <code class=\"text-sm bg-surface-100 dark:bg-surface-700 px-2 py-1 rounded\">{{ template.slug }}</code>\n </td>\n <td class=\"hidden lg:table-cell\">{{ template.subject }}</td>\n <td>\n <p-tag\n [value]=\"template.isHtml ? 'HTML' : 'Text'\"\n [severity]=\"template.isHtml ? 'info' : 'secondary'\"\n />\n </td>\n <td>\n <p-tag\n [value]=\"template.isActive ? 'Active' : 'Inactive'\"\n [severity]=\"template.isActive ? 'success' : 'secondary'\"\n />\n </td>\n <td class=\"hidden xl:table-cell\">{{ template.createdAt | date: 'short' }}</td>\n <td>\n <div class=\"flex gap-1\">\n <p-button\n *hasPermission=\"EMAIL_TEMPLATE_PERMISSIONS.UPDATE\"\n icon=\"pi pi-send\"\n [text]=\"true\"\n size=\"small\"\n pTooltip=\"Test Send\"\n (onClick)=\"onTestSend(template)\"\n />\n <p-button\n *hasPermission=\"EMAIL_TEMPLATE_PERMISSIONS.UPDATE\"\n icon=\"pi pi-pencil\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n pTooltip=\"Edit\"\n (onClick)=\"onEdit(template.id)\"\n />\n <p-button\n *hasPermission=\"EMAIL_TEMPLATE_PERMISSIONS.DELETE\"\n icon=\"pi pi-trash\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n pTooltip=\"Delete\"\n (onClick)=\"onDelete(template)\"\n />\n </div>\n </td>\n </tr>\n </ng-template>\n\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"7\" class=\"text-center py-4 text-muted-color\">\n No email templates found. Create your first template to get started.\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n\n <!-- Test Send Dialog -->\n <p-dialog\n header=\"Test Send Email\"\n [visible]=\"showTestDialog()\"\n (visibleChange)=\"showTestDialog.set($event)\"\n [modal]=\"true\"\n [style]=\"{ width: '95vw', maxWidth: '500px', maxHeight: '80vh' }\"\n [breakpoints]=\"{ '575px': '95vw' }\"\n >\n <div class=\"flex flex-col gap-4\">\n <div class=\"field\">\n <label class=\"block font-medium mb-2\">Template</label>\n <input\n pInputText\n [value]=\"selectedTemplate()?.name || ''\"\n class=\"w-full\"\n [disabled]=\"true\"\n />\n </div>\n\n <div class=\"field\">\n <label class=\"block font-medium mb-2\">Email Configuration *</label>\n <p-select\n [ngModel]=\"testSendModel.configId\"\n (ngModelChange)=\"updateTestSendModel('configId', $event)\"\n [options]=\"configOptions()\"\n optionLabel=\"label\"\n optionValue=\"value\"\n placeholder=\"Select configuration\"\n class=\"w-full\"\n [loading]=\"isLoadingConfigs()\"\n />\n </div>\n\n <div class=\"field\">\n <label class=\"block font-medium mb-2\">Recipient Email *</label>\n <input\n pInputText\n [ngModel]=\"testSendModel.recipient\"\n (ngModelChange)=\"updateTestSendModel('recipient', $event)\"\n class=\"w-full\"\n placeholder=\"recipient@example.com\"\n />\n </div>\n\n <!-- Dynamic Variables -->\n @if (templateVariables().length > 0) {\n <div class=\"border-t border-surface pt-4 mt-2\">\n <h4 class=\"font-medium mb-3 flex items-center gap-2\">\n <i class=\"pi pi-code text-muted-color\"></i>\n Template Variables\n </h4>\n <div class=\"flex flex-col gap-3\">\n @for (variable of templateVariables(); track variable) {\n <div class=\"field\">\n <label class=\"block text-sm font-medium mb-1\">\n <code class=\"text-primary bg-surface-100 dark:bg-surface-700 px-1 rounded\">{{ '{{' + variable + '}}' }}</code>\n </label>\n <input\n pInputText\n [ngModel]=\"variableValues[variable] || ''\"\n (ngModelChange)=\"updateVariableValue(variable, $event)\"\n class=\"w-full\"\n [placeholder]=\"'Enter value for ' + variable\"\n />\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-template #footer>\n <p-button\n label=\"Cancel\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (onClick)=\"showTestDialog.set(false)\"\n />\n <p-button\n label=\"Send Test\"\n icon=\"pi pi-send\"\n [loading]=\"isSendingTest()\"\n (onClick)=\"sendTestEmail()\"\n />\n </ng-template>\n </p-dialog>\n\n <p-confirmDialog />\n <p-toast />\n `,\n})\nexport class TemplateListComponent {\n // Permission constants for template\n readonly EMAIL_TEMPLATE_PERMISSIONS = EMAIL_TEMPLATE_PERMISSIONS;\n\n private readonly router = inject(Router);\n private readonly templateService = inject(EmailTemplateApiService);\n private readonly configService = inject(EmailConfigApiService);\n private readonly emailSendService = inject(EmailSendService);\n private readonly confirmationService = inject(ConfirmationService);\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 readonly isLoading = signal(false);\n readonly templates = signal<IEmailTemplate[]>([]);\n readonly totalRecords = signal(0);\n readonly pageSize = signal(10);\n readonly first = signal(0);\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 // Test send dialog (signals for zoneless change detection)\n readonly showTestDialog = signal(false);\n readonly selectedTemplate = signal<IEmailTemplate | null>(null);\n readonly configs = signal<IEmailConfig[]>([]);\n readonly isLoadingConfigs = signal(false);\n readonly isSendingTest = signal(false);\n\n // Form-bound properties as signals for zoneless change detection\n private readonly _testSendModel = signal({ configId: '', recipient: '' });\n private readonly _variableValues = signal<Record<string, string>>({});\n\n get testSendModel() {\n return this._testSendModel();\n }\n\n get variableValues() {\n return this._variableValues();\n }\n\n updateTestSendModel<K extends 'configId' | 'recipient'>(field: K, value: string): void {\n this._testSendModel.update((m) => ({ ...m, [field]: value }));\n }\n\n updateVariableValue(key: string, value: string): void {\n this._variableValues.update((v) => ({ ...v, [key]: value }));\n }\n\n readonly configOptions = computed(() =>\n this.configs().map((c) => ({\n label: `${c.name} (${c.provider})`,\n value: c.id,\n })),\n );\n\n /** Extract variables from template content */\n readonly templateVariables = computed(() => {\n const template = this.selectedTemplate();\n if (!template) return [];\n\n // Combine all content sources to extract variables\n const content = [\n template.subject,\n template.htmlContent,\n template.textContent || '',\n ].join(' ');\n\n // Find all {{variableName}} patterns\n const matches = content.matchAll(/\\{\\{(\\w+)\\}\\}/g);\n const variables = new Set<string>();\n\n for (const match of matches) {\n variables.add(match[1]);\n }\n\n return Array.from(variables).sort();\n });\n\n onCreate(): void {\n this.router.navigate(['/email/templates/new']);\n }\n\n onEdit(templateId: string): void {\n this.router.navigate(['/email/templates', templateId]);\n }\n\n async loadTemplates(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await firstValueFrom(\n this.templateService.getAll('', {\n pagination: {\n currentPage: Math.floor(this.first() / this.pageSize()),\n pageSize: this.pageSize(),\n },\n filter: {},\n select: [],\n sort: {},\n }),\n );\n\n if (response.success) {\n this.templates.set(response.data ?? []);\n this.totalRecords.set(response.meta?.total ?? 0);\n }\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onLazyLoad(event: { first?: number | null; rows?: number | null }): void {\n this.first.set(event.first ?? 0);\n this.pageSize.set(event.rows ?? 10);\n this.loadTemplates();\n }\n\n async onTestSend(template: IEmailTemplate): Promise<void> {\n this.selectedTemplate.set(template);\n this._testSendModel.set({ configId: '', recipient: '' });\n this._variableValues.set({}); // Reset variable values\n this.showTestDialog.set(true);\n await this.loadConfigs();\n }\n\n async loadConfigs(): Promise<void> {\n this.isLoadingConfigs.set(true);\n try {\n const response = await firstValueFrom(\n this.configService.getAll('', {\n pagination: { currentPage: 0, pageSize: 100 },\n filter: { isActive: true },\n select: [],\n sort: {},\n }),\n );\n if (response.success) {\n this.configs.set(response.data ?? []);\n }\n } finally {\n this.isLoadingConfigs.set(false);\n }\n }\n\n async sendTestEmail(): Promise<void> {\n const template = this.selectedTemplate();\n const model = this.testSendModel;\n if (!template || !model.configId || !model.recipient) {\n this.messageService.add({\n severity: 'warn',\n summary: 'Validation',\n detail: 'Please select a configuration and enter recipient email.',\n });\n return;\n }\n\n this.isSendingTest.set(true);\n try {\n // Build variables object (only include non-empty values)\n const variables: Record<string, string> = {};\n for (const [key, value] of Object.entries(this.variableValues)) {\n if (value) {\n variables[key] = value;\n }\n }\n\n const response = await firstValueFrom(\n this.emailSendService.sendTemplate({\n templateId: template.id,\n to: model.recipient,\n emailConfigId: model.configId,\n variables: Object.keys(variables).length > 0 ? variables : undefined,\n }),\n );\n\n if (response.data?.success) {\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: `Test email sent! Message ID: ${response.data.messageId}`,\n });\n this.showTestDialog.set(false);\n } else {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: response.data?.error || 'Failed to send test email.',\n });\n }\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this.isSendingTest.set(false);\n }\n }\n\n onDelete(template: IEmailTemplate): void {\n this.confirmationService.confirm({\n message: `Are you sure you want to delete \"${template.name}\"?`,\n header: 'Delete Template',\n icon: 'pi pi-exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n await this.templateService.deleteAsync({ id: template.id, type: 'delete' });\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: 'Template deleted successfully.',\n });\n this.loadTemplates();\n } catch {\n // Error toast handled by global interceptor\n }\n },\n });\n }\n}\n"],"names":["i9"],"mappings":"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"}
|
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
|
+
import { ApiResourceService, AngularModule } from '@flusys/ng-shared';
|
|
5
|
+
import { firstValueFrom } from 'rxjs';
|
|
6
|
+
import { APP_CONFIG } from '@flusys/ng-core';
|
|
7
|
+
import * as i1 from '@angular/router';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Supported email provider types
|
|
11
|
+
*/
|
|
12
|
+
var EmailProviderEnum;
|
|
13
|
+
(function (EmailProviderEnum) {
|
|
14
|
+
EmailProviderEnum["SMTP"] = "smtp";
|
|
15
|
+
EmailProviderEnum["SENDGRID"] = "sendgrid";
|
|
16
|
+
EmailProviderEnum["MAILGUN"] = "mailgun";
|
|
17
|
+
})(EmailProviderEnum || (EmailProviderEnum = {}));
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Email content block types
|
|
21
|
+
*/
|
|
22
|
+
var EmailBlockType;
|
|
23
|
+
(function (EmailBlockType) {
|
|
24
|
+
EmailBlockType["TEXT"] = "text";
|
|
25
|
+
EmailBlockType["IMAGE"] = "image";
|
|
26
|
+
EmailBlockType["BUTTON"] = "button";
|
|
27
|
+
EmailBlockType["DIVIDER"] = "divider";
|
|
28
|
+
EmailBlockType["HTML"] = "html";
|
|
29
|
+
})(EmailBlockType || (EmailBlockType = {}));
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Default email settings
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_EMAIL_SETTINGS = {
|
|
35
|
+
maxWidth: '600px',
|
|
36
|
+
backgroundColor: '#f5f5f5',
|
|
37
|
+
fontFamily: 'Arial, sans-serif',
|
|
38
|
+
baseTextColor: '#333333',
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Create a new email schema
|
|
42
|
+
*/
|
|
43
|
+
function createEmailSchema(partial = {}) {
|
|
44
|
+
return {
|
|
45
|
+
id: crypto.randomUUID(),
|
|
46
|
+
version: '1.0.0',
|
|
47
|
+
name: partial.name || 'Untitled Template',
|
|
48
|
+
subject: partial.subject || '',
|
|
49
|
+
sections: partial.sections || [
|
|
50
|
+
{ id: crypto.randomUUID(), type: 'header', name: 'Header', blocks: [], order: 0 },
|
|
51
|
+
{ id: crypto.randomUUID(), type: 'body', name: 'Body', blocks: [], order: 1 },
|
|
52
|
+
{ id: crypto.randomUUID(), type: 'footer', name: 'Footer', blocks: [], order: 2 },
|
|
53
|
+
],
|
|
54
|
+
settings: { ...DEFAULT_EMAIL_SETTINGS, ...partial.settings },
|
|
55
|
+
variables: partial.variables || [],
|
|
56
|
+
...partial,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Email Config API Service
|
|
62
|
+
* Handles email configuration CRUD operations
|
|
63
|
+
* Endpoint: POST /email/email-config/*
|
|
64
|
+
*/
|
|
65
|
+
class EmailConfigApiService extends ApiResourceService {
|
|
66
|
+
constructor() {
|
|
67
|
+
const http = inject(HttpClient);
|
|
68
|
+
super('email/email-config', http);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Send test email to verify configuration
|
|
72
|
+
*/
|
|
73
|
+
sendTest(configId, recipient) {
|
|
74
|
+
return this.http.post(`${this.baseUrl.replace('/email-config', '')}/send/test`, { emailConfigId: configId, recipient });
|
|
75
|
+
}
|
|
76
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
77
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, providedIn: 'root' });
|
|
78
|
+
}
|
|
79
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, decorators: [{
|
|
80
|
+
type: Injectable,
|
|
81
|
+
args: [{
|
|
82
|
+
providedIn: 'root',
|
|
83
|
+
}]
|
|
84
|
+
}], ctorParameters: () => [] });
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Email Template API Service
|
|
88
|
+
* Handles email template CRUD operations
|
|
89
|
+
* Endpoint: POST /email/email-template/*
|
|
90
|
+
*/
|
|
91
|
+
class EmailTemplateApiService extends ApiResourceService {
|
|
92
|
+
constructor() {
|
|
93
|
+
const http = inject(HttpClient);
|
|
94
|
+
super('email/email-template', http);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get template by slug (POST-only RPC pattern)
|
|
98
|
+
*/
|
|
99
|
+
getBySlug(slug) {
|
|
100
|
+
return this.http.post(`${this.baseUrl}/get-by-slug`, { slug });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a new email template
|
|
104
|
+
* POST /email/email-template/insert
|
|
105
|
+
* Uses ICreateEmailTemplateDto which has different required fields than update
|
|
106
|
+
*/
|
|
107
|
+
createTemplate(dto) {
|
|
108
|
+
return this.http.post(`${this.baseUrl}/insert`, dto);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a new email template (async/await version)
|
|
112
|
+
* POST /email/email-template/insert
|
|
113
|
+
*/
|
|
114
|
+
async createTemplateAsync(dto) {
|
|
115
|
+
return firstValueFrom(this.createTemplate(dto));
|
|
116
|
+
}
|
|
117
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
118
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, providedIn: 'root' });
|
|
119
|
+
}
|
|
120
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, decorators: [{
|
|
121
|
+
type: Injectable,
|
|
122
|
+
args: [{
|
|
123
|
+
providedIn: 'root',
|
|
124
|
+
}]
|
|
125
|
+
}], ctorParameters: () => [] });
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Email Send Service
|
|
129
|
+
* Handles sending emails directly or using templates
|
|
130
|
+
* Endpoint: POST /email/send/*
|
|
131
|
+
*
|
|
132
|
+
* Note: For testing configurations, use EmailConfigApiService.sendTest()
|
|
133
|
+
*/
|
|
134
|
+
class EmailSendService {
|
|
135
|
+
http = inject(HttpClient);
|
|
136
|
+
baseUrl = `${inject(APP_CONFIG).apiBaseUrl}/email/send`;
|
|
137
|
+
/**
|
|
138
|
+
* Send email directly (without template)
|
|
139
|
+
*/
|
|
140
|
+
sendDirect(dto) {
|
|
141
|
+
return this.http.post(`${this.baseUrl}/direct`, dto);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Send email using template
|
|
145
|
+
*/
|
|
146
|
+
sendTemplate(dto) {
|
|
147
|
+
return this.http.post(`${this.baseUrl}/template`, dto);
|
|
148
|
+
}
|
|
149
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
150
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, providedIn: 'root' });
|
|
151
|
+
}
|
|
152
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, decorators: [{
|
|
153
|
+
type: Injectable,
|
|
154
|
+
args: [{
|
|
155
|
+
providedIn: 'root',
|
|
156
|
+
}]
|
|
157
|
+
}] });
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Manages the email builder UI state including schema, selection, and UI toggles.
|
|
161
|
+
* Should be provided at the EmailBuilder component level (not root).
|
|
162
|
+
*/
|
|
163
|
+
class EmailBuilderStateService {
|
|
164
|
+
// Schema state
|
|
165
|
+
_schema = signal(createEmailSchema(), ...(ngDevMode ? [{ debugName: "_schema" }] : []));
|
|
166
|
+
_isDirty = signal(false, ...(ngDevMode ? [{ debugName: "_isDirty" }] : []));
|
|
167
|
+
// Selection state
|
|
168
|
+
_selectedSectionId = signal(null, ...(ngDevMode ? [{ debugName: "_selectedSectionId" }] : []));
|
|
169
|
+
_selectedBlockId = signal(null, ...(ngDevMode ? [{ debugName: "_selectedBlockId" }] : []));
|
|
170
|
+
// View mode
|
|
171
|
+
_viewMode = signal('visual', ...(ngDevMode ? [{ debugName: "_viewMode" }] : []));
|
|
172
|
+
// Public readonly signals
|
|
173
|
+
schema = this._schema.asReadonly();
|
|
174
|
+
isDirty = this._isDirty.asReadonly();
|
|
175
|
+
selectedSectionId = this._selectedSectionId.asReadonly();
|
|
176
|
+
selectedBlockId = this._selectedBlockId.asReadonly();
|
|
177
|
+
viewMode = this._viewMode.asReadonly();
|
|
178
|
+
// Computed signals
|
|
179
|
+
sections = computed(() => this._schema().sections, ...(ngDevMode ? [{ debugName: "sections" }] : []));
|
|
180
|
+
templateName = computed(() => this._schema().name, ...(ngDevMode ? [{ debugName: "templateName" }] : []));
|
|
181
|
+
subject = computed(() => this._schema().subject, ...(ngDevMode ? [{ debugName: "subject" }] : []));
|
|
182
|
+
settings = computed(() => this._schema().settings ?? DEFAULT_EMAIL_SETTINGS, ...(ngDevMode ? [{ debugName: "settings" }] : []));
|
|
183
|
+
variables = computed(() => this._schema().variables ?? [], ...(ngDevMode ? [{ debugName: "variables" }] : []));
|
|
184
|
+
headerSection = computed(() => {
|
|
185
|
+
return this.sections().find((s) => s.type === 'header') ?? null;
|
|
186
|
+
}, ...(ngDevMode ? [{ debugName: "headerSection" }] : []));
|
|
187
|
+
bodySection = computed(() => {
|
|
188
|
+
return this.sections().find((s) => s.type === 'body') ?? null;
|
|
189
|
+
}, ...(ngDevMode ? [{ debugName: "bodySection" }] : []));
|
|
190
|
+
footerSection = computed(() => {
|
|
191
|
+
return this.sections().find((s) => s.type === 'footer') ?? null;
|
|
192
|
+
}, ...(ngDevMode ? [{ debugName: "footerSection" }] : []));
|
|
193
|
+
selectedSection = computed(() => {
|
|
194
|
+
const sectionId = this._selectedSectionId();
|
|
195
|
+
if (!sectionId)
|
|
196
|
+
return null;
|
|
197
|
+
return this.sections().find((s) => s.id === sectionId) ?? null;
|
|
198
|
+
}, ...(ngDevMode ? [{ debugName: "selectedSection" }] : []));
|
|
199
|
+
selectedBlock = computed(() => {
|
|
200
|
+
const blockId = this._selectedBlockId();
|
|
201
|
+
if (!blockId)
|
|
202
|
+
return null;
|
|
203
|
+
for (const section of this.sections()) {
|
|
204
|
+
const block = section.blocks.find((b) => b.id === blockId);
|
|
205
|
+
if (block)
|
|
206
|
+
return block;
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}, ...(ngDevMode ? [{ debugName: "selectedBlock" }] : []));
|
|
210
|
+
allBlocks = computed(() => {
|
|
211
|
+
return this.sections().flatMap((s) => s.blocks);
|
|
212
|
+
}, ...(ngDevMode ? [{ debugName: "allBlocks" }] : []));
|
|
213
|
+
// =========================================
|
|
214
|
+
// Schema Operations
|
|
215
|
+
// =========================================
|
|
216
|
+
/**
|
|
217
|
+
* Load an existing schema into the builder
|
|
218
|
+
*/
|
|
219
|
+
loadSchema(schema) {
|
|
220
|
+
const cloned = structuredClone(schema);
|
|
221
|
+
this._schema.set(cloned);
|
|
222
|
+
this._isDirty.set(false);
|
|
223
|
+
this._selectedSectionId.set(null);
|
|
224
|
+
this._selectedBlockId.set(null);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Create a new empty schema
|
|
228
|
+
*/
|
|
229
|
+
createNewSchema(name = 'Untitled Template') {
|
|
230
|
+
this._schema.set(createEmailSchema({ name }));
|
|
231
|
+
this._isDirty.set(true);
|
|
232
|
+
this._selectedSectionId.set(null);
|
|
233
|
+
this._selectedBlockId.set(null);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Update template metadata
|
|
237
|
+
*/
|
|
238
|
+
updateSchemaMeta(updates) {
|
|
239
|
+
this._schema.update((schema) => ({
|
|
240
|
+
...schema,
|
|
241
|
+
...updates,
|
|
242
|
+
}));
|
|
243
|
+
this._isDirty.set(true);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Mark schema as saved (clears dirty flag)
|
|
247
|
+
*/
|
|
248
|
+
markAsSaved() {
|
|
249
|
+
this._isDirty.set(false);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Set view mode (visual or html)
|
|
253
|
+
*/
|
|
254
|
+
setViewMode(mode) {
|
|
255
|
+
this._viewMode.set(mode);
|
|
256
|
+
}
|
|
257
|
+
// =========================================
|
|
258
|
+
// Section Operations
|
|
259
|
+
// =========================================
|
|
260
|
+
/**
|
|
261
|
+
* Update section properties
|
|
262
|
+
*/
|
|
263
|
+
updateSection(sectionId, updates) {
|
|
264
|
+
this._schema.update((schema) => ({
|
|
265
|
+
...schema,
|
|
266
|
+
sections: schema.sections.map((s) => s.id === sectionId ? { ...s, ...updates } : s),
|
|
267
|
+
}));
|
|
268
|
+
this._isDirty.set(true);
|
|
269
|
+
}
|
|
270
|
+
// =========================================
|
|
271
|
+
// Block Operations
|
|
272
|
+
// =========================================
|
|
273
|
+
/**
|
|
274
|
+
* Add a new block to a section
|
|
275
|
+
*/
|
|
276
|
+
addBlock(sectionId, blockType, block) {
|
|
277
|
+
const newBlock = {
|
|
278
|
+
id: crypto.randomUUID(),
|
|
279
|
+
type: blockType,
|
|
280
|
+
order: 0,
|
|
281
|
+
content: this.getDefaultContent(blockType),
|
|
282
|
+
...block,
|
|
283
|
+
};
|
|
284
|
+
this._schema.update((schema) => ({
|
|
285
|
+
...schema,
|
|
286
|
+
sections: schema.sections.map((s) => {
|
|
287
|
+
if (s.id !== sectionId)
|
|
288
|
+
return s;
|
|
289
|
+
const blocks = [...s.blocks, newBlock];
|
|
290
|
+
// Update order
|
|
291
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
292
|
+
return { ...s, blocks };
|
|
293
|
+
}),
|
|
294
|
+
}));
|
|
295
|
+
this._isDirty.set(true);
|
|
296
|
+
return newBlock.id;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Update block properties
|
|
300
|
+
*/
|
|
301
|
+
updateBlock(sectionId, blockId, updates) {
|
|
302
|
+
this._schema.update((schema) => ({
|
|
303
|
+
...schema,
|
|
304
|
+
sections: schema.sections.map((s) => {
|
|
305
|
+
if (s.id !== sectionId)
|
|
306
|
+
return s;
|
|
307
|
+
return {
|
|
308
|
+
...s,
|
|
309
|
+
blocks: s.blocks.map((b) => (b.id === blockId ? { ...b, ...updates } : b)),
|
|
310
|
+
};
|
|
311
|
+
}),
|
|
312
|
+
}));
|
|
313
|
+
this._isDirty.set(true);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Delete a block from a section
|
|
317
|
+
*/
|
|
318
|
+
deleteBlock(sectionId, blockId) {
|
|
319
|
+
this._schema.update((schema) => ({
|
|
320
|
+
...schema,
|
|
321
|
+
sections: schema.sections.map((s) => {
|
|
322
|
+
if (s.id !== sectionId)
|
|
323
|
+
return s;
|
|
324
|
+
const blocks = s.blocks.filter((b) => b.id !== blockId);
|
|
325
|
+
// Update order
|
|
326
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
327
|
+
return { ...s, blocks };
|
|
328
|
+
}),
|
|
329
|
+
}));
|
|
330
|
+
this._isDirty.set(true);
|
|
331
|
+
// Clear selection if deleted block was selected
|
|
332
|
+
if (this._selectedBlockId() === blockId) {
|
|
333
|
+
this._selectedBlockId.set(null);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Reorder blocks within a section
|
|
338
|
+
*/
|
|
339
|
+
reorderBlocks(sectionId, fromIndex, toIndex) {
|
|
340
|
+
this._schema.update((schema) => ({
|
|
341
|
+
...schema,
|
|
342
|
+
sections: schema.sections.map((s) => {
|
|
343
|
+
if (s.id !== sectionId)
|
|
344
|
+
return s;
|
|
345
|
+
const blocks = [...s.blocks];
|
|
346
|
+
const [removed] = blocks.splice(fromIndex, 1);
|
|
347
|
+
blocks.splice(toIndex, 0, removed);
|
|
348
|
+
// Update order
|
|
349
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
350
|
+
return { ...s, blocks };
|
|
351
|
+
}),
|
|
352
|
+
}));
|
|
353
|
+
this._isDirty.set(true);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Duplicate a block
|
|
357
|
+
*/
|
|
358
|
+
duplicateBlock(sectionId, blockId) {
|
|
359
|
+
const section = this.sections().find((s) => s.id === sectionId);
|
|
360
|
+
const block = section?.blocks.find((b) => b.id === blockId);
|
|
361
|
+
if (!block)
|
|
362
|
+
return null;
|
|
363
|
+
const newBlock = {
|
|
364
|
+
...structuredClone(block),
|
|
365
|
+
id: crypto.randomUUID(),
|
|
366
|
+
};
|
|
367
|
+
this._schema.update((schema) => ({
|
|
368
|
+
...schema,
|
|
369
|
+
sections: schema.sections.map((s) => {
|
|
370
|
+
if (s.id !== sectionId)
|
|
371
|
+
return s;
|
|
372
|
+
const blockIndex = s.blocks.findIndex((b) => b.id === blockId);
|
|
373
|
+
const blocks = [...s.blocks];
|
|
374
|
+
blocks.splice(blockIndex + 1, 0, newBlock);
|
|
375
|
+
// Update order
|
|
376
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
377
|
+
return { ...s, blocks };
|
|
378
|
+
}),
|
|
379
|
+
}));
|
|
380
|
+
this._isDirty.set(true);
|
|
381
|
+
return newBlock.id;
|
|
382
|
+
}
|
|
383
|
+
// =========================================
|
|
384
|
+
// Selection Operations
|
|
385
|
+
// =========================================
|
|
386
|
+
/**
|
|
387
|
+
* Select a section
|
|
388
|
+
*/
|
|
389
|
+
selectSection(sectionId) {
|
|
390
|
+
this._selectedSectionId.set(sectionId);
|
|
391
|
+
this._selectedBlockId.set(null);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Select a block
|
|
395
|
+
*/
|
|
396
|
+
selectBlock(blockId) {
|
|
397
|
+
if (blockId) {
|
|
398
|
+
// Find the section containing this block
|
|
399
|
+
for (const section of this.sections()) {
|
|
400
|
+
if (section.blocks.some((b) => b.id === blockId)) {
|
|
401
|
+
this._selectedSectionId.set(section.id);
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
this._selectedBlockId.set(blockId);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Clear all selection
|
|
410
|
+
*/
|
|
411
|
+
clearSelection() {
|
|
412
|
+
this._selectedSectionId.set(null);
|
|
413
|
+
this._selectedBlockId.set(null);
|
|
414
|
+
}
|
|
415
|
+
// =========================================
|
|
416
|
+
// Helper Methods
|
|
417
|
+
// =========================================
|
|
418
|
+
/**
|
|
419
|
+
* Get default content for a block type
|
|
420
|
+
*/
|
|
421
|
+
getDefaultContent(type) {
|
|
422
|
+
switch (type) {
|
|
423
|
+
case EmailBlockType.TEXT:
|
|
424
|
+
return { text: 'Enter your text here...', html: '<p>Enter your text here...</p>' };
|
|
425
|
+
case EmailBlockType.IMAGE:
|
|
426
|
+
return { src: '', alt: 'Image' };
|
|
427
|
+
case EmailBlockType.BUTTON:
|
|
428
|
+
return {
|
|
429
|
+
text: 'Click Here',
|
|
430
|
+
link: 'https://',
|
|
431
|
+
backgroundColor: '#007bff',
|
|
432
|
+
textColor: '#ffffff',
|
|
433
|
+
borderRadius: '4px',
|
|
434
|
+
};
|
|
435
|
+
case EmailBlockType.DIVIDER:
|
|
436
|
+
return { height: '1px', color: '#cccccc', style: 'solid' };
|
|
437
|
+
case EmailBlockType.HTML:
|
|
438
|
+
return { html: '<!-- Custom HTML -->' };
|
|
439
|
+
default:
|
|
440
|
+
return {};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
444
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService });
|
|
445
|
+
}
|
|
446
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService, decorators: [{
|
|
447
|
+
type: Injectable
|
|
448
|
+
}] });
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Email module routes
|
|
452
|
+
*/
|
|
453
|
+
const EMAIL_ROUTES = [
|
|
454
|
+
{
|
|
455
|
+
path: '',
|
|
456
|
+
loadComponent: () => Promise.resolve().then(function () { return emailContainer_component; }).then((m) => m.EmailContainerComponent),
|
|
457
|
+
children: [
|
|
458
|
+
// Templates
|
|
459
|
+
{
|
|
460
|
+
path: 'templates',
|
|
461
|
+
children: [
|
|
462
|
+
{
|
|
463
|
+
path: '',
|
|
464
|
+
loadComponent: () => import('./flusys-ng-email-template-list.component-91djzx28.mjs').then((m) => m.TemplateListComponent),
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
path: 'new',
|
|
468
|
+
loadComponent: () => import('./flusys-ng-email-template-form.component-u40UX6yY.mjs').then((m) => m.TemplateFormComponent),
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
path: ':id',
|
|
472
|
+
loadComponent: () => import('./flusys-ng-email-template-form.component-u40UX6yY.mjs').then((m) => m.TemplateFormComponent),
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
},
|
|
476
|
+
// Configs
|
|
477
|
+
{
|
|
478
|
+
path: 'configs',
|
|
479
|
+
children: [
|
|
480
|
+
{
|
|
481
|
+
path: '',
|
|
482
|
+
loadComponent: () => import('./flusys-ng-email-email-config-list.component-DnIJdHdf.mjs').then((m) => m.EmailConfigListComponent),
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
path: 'new',
|
|
486
|
+
loadComponent: () => import('./flusys-ng-email-email-config-form.component-BK195yNS.mjs').then((m) => m.EmailConfigFormComponent),
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
path: ':id',
|
|
490
|
+
loadComponent: () => import('./flusys-ng-email-email-config-form.component-BK195yNS.mjs').then((m) => m.EmailConfigFormComponent),
|
|
491
|
+
},
|
|
492
|
+
],
|
|
493
|
+
},
|
|
494
|
+
// Default redirect
|
|
495
|
+
{
|
|
496
|
+
path: '',
|
|
497
|
+
redirectTo: 'templates',
|
|
498
|
+
pathMatch: 'full',
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
},
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Email container component with tab navigation
|
|
506
|
+
*/
|
|
507
|
+
class EmailContainerComponent {
|
|
508
|
+
tabs = [
|
|
509
|
+
{ id: 'templates', label: 'Templates', icon: 'pi pi-file', route: 'templates' },
|
|
510
|
+
{ id: 'configs', label: 'Configurations', icon: 'pi pi-cog', route: 'configs' },
|
|
511
|
+
];
|
|
512
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
513
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: EmailContainerComponent, isStandalone: true, selector: "lib-email-container", ngImport: i0, template: `
|
|
514
|
+
<div class="p-2 sm:p-4">
|
|
515
|
+
<div class="mb-4">
|
|
516
|
+
<h1 class="text-xl sm:text-2xl font-bold m-0">Email</h1>
|
|
517
|
+
<p class="text-sm text-muted-color mt-1">Manage email templates and provider configurations</p>
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap -mx-2 sm:mx-0 px-2 sm:px-0">
|
|
521
|
+
@for (tab of tabs; track tab.id) {
|
|
522
|
+
<a
|
|
523
|
+
[routerLink]="tab.route"
|
|
524
|
+
routerLinkActive="tab-active"
|
|
525
|
+
[routerLinkActiveOptions]="{ exact: false }"
|
|
526
|
+
class="flex items-center gap-2 px-3 sm:px-4 py-2 rounded-t-lg cursor-pointer transition-colors text-muted-color no-underline border-b-2 border-transparent -mb-px hover:bg-surface-hover [&.tab-active]:text-primary [&.tab-active]:border-primary [&.tab-active]:bg-surface-ground whitespace-nowrap shrink-0 text-sm sm:text-base">
|
|
527
|
+
<i [class]="tab.icon"></i>
|
|
528
|
+
<span>{{ tab.label }}</span>
|
|
529
|
+
</a>
|
|
530
|
+
}
|
|
531
|
+
</div>
|
|
532
|
+
|
|
533
|
+
<router-outlet />
|
|
534
|
+
</div>
|
|
535
|
+
`, isInline: true, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
536
|
+
}
|
|
537
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailContainerComponent, decorators: [{
|
|
538
|
+
type: Component,
|
|
539
|
+
args: [{ selector: 'lib-email-container', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AngularModule], template: `
|
|
540
|
+
<div class="p-2 sm:p-4">
|
|
541
|
+
<div class="mb-4">
|
|
542
|
+
<h1 class="text-xl sm:text-2xl font-bold m-0">Email</h1>
|
|
543
|
+
<p class="text-sm text-muted-color mt-1">Manage email templates and provider configurations</p>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap -mx-2 sm:mx-0 px-2 sm:px-0">
|
|
547
|
+
@for (tab of tabs; track tab.id) {
|
|
548
|
+
<a
|
|
549
|
+
[routerLink]="tab.route"
|
|
550
|
+
routerLinkActive="tab-active"
|
|
551
|
+
[routerLinkActiveOptions]="{ exact: false }"
|
|
552
|
+
class="flex items-center gap-2 px-3 sm:px-4 py-2 rounded-t-lg cursor-pointer transition-colors text-muted-color no-underline border-b-2 border-transparent -mb-px hover:bg-surface-hover [&.tab-active]:text-primary [&.tab-active]:border-primary [&.tab-active]:bg-surface-ground whitespace-nowrap shrink-0 text-sm sm:text-base">
|
|
553
|
+
<i [class]="tab.icon"></i>
|
|
554
|
+
<span>{{ tab.label }}</span>
|
|
555
|
+
</a>
|
|
556
|
+
}
|
|
557
|
+
</div>
|
|
558
|
+
|
|
559
|
+
<router-outlet />
|
|
560
|
+
</div>
|
|
561
|
+
`, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"] }]
|
|
562
|
+
}] });
|
|
563
|
+
|
|
564
|
+
var emailContainer_component = /*#__PURE__*/Object.freeze({
|
|
565
|
+
__proto__: null,
|
|
566
|
+
EmailContainerComponent: EmailContainerComponent
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// =============================================================================
|
|
570
|
+
// @flusys/ng-email - Email Package
|
|
571
|
+
// =============================================================================
|
|
572
|
+
// Enums
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Generated bundle index. Do not edit.
|
|
576
|
+
*/
|
|
577
|
+
|
|
578
|
+
export { DEFAULT_EMAIL_SETTINGS, EMAIL_ROUTES, EmailBlockType, EmailBuilderStateService, EmailConfigApiService, EmailContainerComponent, EmailProviderEnum, EmailSendService, EmailTemplateApiService, createEmailSchema };
|
|
579
|
+
//# sourceMappingURL=flusys-ng-email.mjs.map
|