@flusys/ng-email 1.1.0-beta
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 +660 -0
- package/fesm2022/flusys-ng-email-email-config-form.component-8dOBD-Q-.mjs +651 -0
- package/fesm2022/flusys-ng-email-email-config-form.component-8dOBD-Q-.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-email-config-list.component-CJhSPkCZ.mjs +508 -0
- package/fesm2022/flusys-ng-email-email-config-list.component-CJhSPkCZ.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-template-form.component-DjzG_lG1.mjs +529 -0
- package/fesm2022/flusys-ng-email-template-form.component-DjzG_lG1.mjs.map +1 -0
- package/fesm2022/flusys-ng-email-template-list.component-CGJxfZMT.mjs +595 -0
- package/fesm2022/flusys-ng-email-template-list.component-CGJxfZMT.mjs.map +1 -0
- package/fesm2022/flusys-ng-email.mjs +571 -0
- package/fesm2022/flusys-ng-email.mjs.map +1 -0
- package/package.json +32 -0
- package/types/flusys-ng-email.d.ts +456 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-email-template-list.component-CGJxfZMT.mjs","sources":["../../../projects/ng-email/pages/template/template-list.component.ts"],"sourcesContent":["import { Component, ChangeDetectionStrategy, inject, signal, OnInit, computed } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { FormsModule } from '@angular/forms';\nimport { firstValueFrom } from 'rxjs';\nimport { ConfirmationService, MessageService } from 'primeng/api';\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 { EmailTemplateApiService } from '../../services/email-template-api.service';\nimport { EmailConfigApiService } from '../../services/email-config-api.service';\nimport { EmailSendService } from '../../services/email-send.service';\nimport { IEmailTemplate } from '../../interfaces/email-template.interface';\nimport { IEmailConfig } from '../../interfaces/email-config.interface';\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, FormsModule],\n providers: [ConfirmationService, MessageService],\n template: `\n <div class=\"card\">\n <div class=\"flex justify-between items-center mb-4\">\n <div>\n <h3 class=\"text-xl font-semibold\">Email Templates</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-gray-600 mt-1\">\n Company: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <p-button\n label=\"New Template\"\n icon=\"pi pi-plus\"\n (onClick)=\"onCreate()\"\n />\n </div>\n\n <p-table\n [value]=\"templates()\"\n [loading]=\"isLoading()\"\n [paginator]=\"true\"\n [rows]=\"pageSize()\"\n [totalRecords]=\"totalRecords()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onPageChange($event)\"\n styleClass=\"p-datatable-sm\"\n >\n <ng-template #header>\n <tr>\n <th>Name</th>\n <th>Slug</th>\n <th>Subject</th>\n <th>Type</th>\n <th>Status</th>\n <th>Created</th>\n <th style=\"width: 150px\">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\"></i>\n {{ template.name }}\n </td>\n <td>\n <code class=\"text-sm bg-gray-100 px-2 py-1 rounded\">{{ template.slug }}</code>\n </td>\n <td>{{ 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>{{ template.createdAt | date: 'short' }}</td>\n <td>\n <p-button\n icon=\"pi pi-send\"\n [text]=\"true\"\n size=\"small\"\n pTooltip=\"Test Send\"\n (onClick)=\"onTestSend(template)\"\n />\n <p-button\n icon=\"pi pi-pencil\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (onClick)=\"onEdit(template.id)\"\n />\n <p-button\n icon=\"pi pi-trash\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n (onClick)=\"onDelete(template)\"\n />\n </td>\n </tr>\n </ng-template>\n\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"7\" class=\"text-center py-4\">\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\n <!-- Test Send Dialog -->\n <p-dialog\n header=\"Test Send Email\"\n [(visible)]=\"showTestDialog\"\n [modal]=\"true\"\n [style]=\"{ width: '500px', maxHeight: '80vh' }\"\n >\n <div class=\"grid 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 [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 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 pt-4 mt-2\">\n <h4 class=\"font-medium mb-3 flex items-center gap-2\">\n <i class=\"pi pi-code\"></i>\n Template Variables\n </h4>\n <div class=\"grid 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\">{{ '{{' + variable + '}}' }}</code>\n </label>\n <input\n pInputText\n [ngModel]=\"variableValues[variable] || ''\"\n (ngModelChange)=\"variableValues[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 [text]=\"true\"\n (onClick)=\"showTestDialog = 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 implements OnInit {\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);\n\n readonly isLoading = signal(false);\n readonly templates = signal<IEmailTemplate[]>([]);\n readonly totalRecords = signal(0);\n readonly pageSize = signal(10);\n readonly currentPage = signal(1);\n\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n // Test send dialog\n showTestDialog = 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 (ngModel requires plain properties)\n testSendModel = { configId: '', recipient: '' };\n variableValues: Record<string, string> = {};\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 ngOnInit(): void {\n this.loadTemplates();\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: this.currentPage() - 1,\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 onPageChange(event: any): void {\n this.currentPage.set(event.first / event.rows + 1);\n this.pageSize.set(event.rows);\n this.loadTemplates();\n }\n\n async onTestSend(template: IEmailTemplate): Promise<void> {\n this.selectedTemplate.set(template);\n this.testSendModel = { configId: '', recipient: '' };\n this.variableValues = {}; // Reset variable values\n this.showTestDialog = 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 if (!template || !this.testSendModel.configId || !this.testSendModel.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: this.testSendModel.recipient,\n emailConfigId: this.testSendModel.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 = 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 (error: any) {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: error?.message || 'Failed to send test email.',\n });\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 (error) {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: 'Failed to delete template.',\n });\n }\n },\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,571 @@
|
|
|
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 { APP_CONFIG } from '@flusys/ng-core';
|
|
5
|
+
import { ApiResourceService } from '@flusys/ng-shared';
|
|
6
|
+
import { CommonModule } from '@angular/common';
|
|
7
|
+
import { RouterOutlet, RouterLink, RouterLinkActive } 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
|
+
apiBaseUrl;
|
|
67
|
+
constructor() {
|
|
68
|
+
const http = inject(HttpClient);
|
|
69
|
+
super('email/email-config', http);
|
|
70
|
+
this.apiBaseUrl = inject(APP_CONFIG).apiBaseUrl;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Send test email to verify configuration
|
|
74
|
+
*/
|
|
75
|
+
sendTest(configId, recipient) {
|
|
76
|
+
return this.http.post(`${this.apiBaseUrl}/email/send/test`, { emailConfigId: configId, recipient });
|
|
77
|
+
}
|
|
78
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
79
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, providedIn: 'root' });
|
|
80
|
+
}
|
|
81
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailConfigApiService, decorators: [{
|
|
82
|
+
type: Injectable,
|
|
83
|
+
args: [{
|
|
84
|
+
providedIn: 'root',
|
|
85
|
+
}]
|
|
86
|
+
}], ctorParameters: () => [] });
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Email Template API Service
|
|
90
|
+
* Handles email template CRUD operations
|
|
91
|
+
* Endpoint: POST /email/email-template/*
|
|
92
|
+
*/
|
|
93
|
+
class EmailTemplateApiService extends ApiResourceService {
|
|
94
|
+
constructor() {
|
|
95
|
+
const http = inject(HttpClient);
|
|
96
|
+
super('email/email-template', http);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get template by slug (POST-only RPC pattern)
|
|
100
|
+
*/
|
|
101
|
+
getBySlug(slug) {
|
|
102
|
+
return this.http.post(`${this.baseUrl}/get-by-slug`, { slug });
|
|
103
|
+
}
|
|
104
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
105
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, providedIn: 'root' });
|
|
106
|
+
}
|
|
107
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailTemplateApiService, decorators: [{
|
|
108
|
+
type: Injectable,
|
|
109
|
+
args: [{
|
|
110
|
+
providedIn: 'root',
|
|
111
|
+
}]
|
|
112
|
+
}], ctorParameters: () => [] });
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Email Send Service
|
|
116
|
+
* Handles sending emails directly or using templates
|
|
117
|
+
*/
|
|
118
|
+
class EmailSendService {
|
|
119
|
+
http = inject(HttpClient);
|
|
120
|
+
baseUrl = inject(APP_CONFIG).apiBaseUrl;
|
|
121
|
+
/**
|
|
122
|
+
* Send email directly (without template)
|
|
123
|
+
*/
|
|
124
|
+
sendDirect(dto) {
|
|
125
|
+
return this.http.post(`${this.baseUrl}/email/send/direct`, dto);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Send email using template
|
|
129
|
+
*/
|
|
130
|
+
sendTemplate(dto) {
|
|
131
|
+
return this.http.post(`${this.baseUrl}/email/send/template`, dto);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Send test email (for testing configuration)
|
|
135
|
+
*/
|
|
136
|
+
sendTest(dto) {
|
|
137
|
+
return this.http.post(`${this.baseUrl}/email/send/test`, { emailConfigId: dto.configId, recipient: dto.recipient });
|
|
138
|
+
}
|
|
139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
140
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, providedIn: 'root' });
|
|
141
|
+
}
|
|
142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailSendService, decorators: [{
|
|
143
|
+
type: Injectable,
|
|
144
|
+
args: [{
|
|
145
|
+
providedIn: 'root',
|
|
146
|
+
}]
|
|
147
|
+
}] });
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Manages the email builder UI state including schema, selection, and UI toggles.
|
|
151
|
+
* Should be provided at the EmailBuilder component level (not root).
|
|
152
|
+
*/
|
|
153
|
+
class EmailBuilderStateService {
|
|
154
|
+
// Schema state
|
|
155
|
+
_schema = signal(createEmailSchema(), ...(ngDevMode ? [{ debugName: "_schema" }] : []));
|
|
156
|
+
_isDirty = signal(false, ...(ngDevMode ? [{ debugName: "_isDirty" }] : []));
|
|
157
|
+
// Selection state
|
|
158
|
+
_selectedSectionId = signal(null, ...(ngDevMode ? [{ debugName: "_selectedSectionId" }] : []));
|
|
159
|
+
_selectedBlockId = signal(null, ...(ngDevMode ? [{ debugName: "_selectedBlockId" }] : []));
|
|
160
|
+
// View mode
|
|
161
|
+
_viewMode = signal('visual', ...(ngDevMode ? [{ debugName: "_viewMode" }] : []));
|
|
162
|
+
// Public readonly signals
|
|
163
|
+
schema = this._schema.asReadonly();
|
|
164
|
+
isDirty = this._isDirty.asReadonly();
|
|
165
|
+
selectedSectionId = this._selectedSectionId.asReadonly();
|
|
166
|
+
selectedBlockId = this._selectedBlockId.asReadonly();
|
|
167
|
+
viewMode = this._viewMode.asReadonly();
|
|
168
|
+
// Computed signals
|
|
169
|
+
sections = computed(() => this._schema().sections, ...(ngDevMode ? [{ debugName: "sections" }] : []));
|
|
170
|
+
templateName = computed(() => this._schema().name, ...(ngDevMode ? [{ debugName: "templateName" }] : []));
|
|
171
|
+
subject = computed(() => this._schema().subject, ...(ngDevMode ? [{ debugName: "subject" }] : []));
|
|
172
|
+
settings = computed(() => this._schema().settings ?? DEFAULT_EMAIL_SETTINGS, ...(ngDevMode ? [{ debugName: "settings" }] : []));
|
|
173
|
+
variables = computed(() => this._schema().variables ?? [], ...(ngDevMode ? [{ debugName: "variables" }] : []));
|
|
174
|
+
headerSection = computed(() => {
|
|
175
|
+
return this.sections().find((s) => s.type === 'header') ?? null;
|
|
176
|
+
}, ...(ngDevMode ? [{ debugName: "headerSection" }] : []));
|
|
177
|
+
bodySection = computed(() => {
|
|
178
|
+
return this.sections().find((s) => s.type === 'body') ?? null;
|
|
179
|
+
}, ...(ngDevMode ? [{ debugName: "bodySection" }] : []));
|
|
180
|
+
footerSection = computed(() => {
|
|
181
|
+
return this.sections().find((s) => s.type === 'footer') ?? null;
|
|
182
|
+
}, ...(ngDevMode ? [{ debugName: "footerSection" }] : []));
|
|
183
|
+
selectedSection = computed(() => {
|
|
184
|
+
const sectionId = this._selectedSectionId();
|
|
185
|
+
if (!sectionId)
|
|
186
|
+
return null;
|
|
187
|
+
return this.sections().find((s) => s.id === sectionId) ?? null;
|
|
188
|
+
}, ...(ngDevMode ? [{ debugName: "selectedSection" }] : []));
|
|
189
|
+
selectedBlock = computed(() => {
|
|
190
|
+
const blockId = this._selectedBlockId();
|
|
191
|
+
if (!blockId)
|
|
192
|
+
return null;
|
|
193
|
+
for (const section of this.sections()) {
|
|
194
|
+
const block = section.blocks.find((b) => b.id === blockId);
|
|
195
|
+
if (block)
|
|
196
|
+
return block;
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}, ...(ngDevMode ? [{ debugName: "selectedBlock" }] : []));
|
|
200
|
+
allBlocks = computed(() => {
|
|
201
|
+
return this.sections().flatMap((s) => s.blocks);
|
|
202
|
+
}, ...(ngDevMode ? [{ debugName: "allBlocks" }] : []));
|
|
203
|
+
// =========================================
|
|
204
|
+
// Schema Operations
|
|
205
|
+
// =========================================
|
|
206
|
+
/**
|
|
207
|
+
* Load an existing schema into the builder
|
|
208
|
+
*/
|
|
209
|
+
loadSchema(schema) {
|
|
210
|
+
const cloned = structuredClone(schema);
|
|
211
|
+
this._schema.set(cloned);
|
|
212
|
+
this._isDirty.set(false);
|
|
213
|
+
this._selectedSectionId.set(null);
|
|
214
|
+
this._selectedBlockId.set(null);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a new empty schema
|
|
218
|
+
*/
|
|
219
|
+
createNewSchema(name = 'Untitled Template') {
|
|
220
|
+
this._schema.set(createEmailSchema({ name }));
|
|
221
|
+
this._isDirty.set(true);
|
|
222
|
+
this._selectedSectionId.set(null);
|
|
223
|
+
this._selectedBlockId.set(null);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Update template metadata
|
|
227
|
+
*/
|
|
228
|
+
updateSchemaMeta(updates) {
|
|
229
|
+
this._schema.update((schema) => ({
|
|
230
|
+
...schema,
|
|
231
|
+
...updates,
|
|
232
|
+
}));
|
|
233
|
+
this._isDirty.set(true);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Mark schema as saved (clears dirty flag)
|
|
237
|
+
*/
|
|
238
|
+
markAsSaved() {
|
|
239
|
+
this._isDirty.set(false);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Set view mode (visual or html)
|
|
243
|
+
*/
|
|
244
|
+
setViewMode(mode) {
|
|
245
|
+
this._viewMode.set(mode);
|
|
246
|
+
}
|
|
247
|
+
// =========================================
|
|
248
|
+
// Section Operations
|
|
249
|
+
// =========================================
|
|
250
|
+
/**
|
|
251
|
+
* Update section properties
|
|
252
|
+
*/
|
|
253
|
+
updateSection(sectionId, updates) {
|
|
254
|
+
this._schema.update((schema) => ({
|
|
255
|
+
...schema,
|
|
256
|
+
sections: schema.sections.map((s) => s.id === sectionId ? { ...s, ...updates } : s),
|
|
257
|
+
}));
|
|
258
|
+
this._isDirty.set(true);
|
|
259
|
+
}
|
|
260
|
+
// =========================================
|
|
261
|
+
// Block Operations
|
|
262
|
+
// =========================================
|
|
263
|
+
/**
|
|
264
|
+
* Add a new block to a section
|
|
265
|
+
*/
|
|
266
|
+
addBlock(sectionId, blockType, block) {
|
|
267
|
+
const newBlock = {
|
|
268
|
+
id: crypto.randomUUID(),
|
|
269
|
+
type: blockType,
|
|
270
|
+
order: 0,
|
|
271
|
+
content: this.getDefaultContent(blockType),
|
|
272
|
+
...block,
|
|
273
|
+
};
|
|
274
|
+
this._schema.update((schema) => ({
|
|
275
|
+
...schema,
|
|
276
|
+
sections: schema.sections.map((s) => {
|
|
277
|
+
if (s.id !== sectionId)
|
|
278
|
+
return s;
|
|
279
|
+
const blocks = [...s.blocks, newBlock];
|
|
280
|
+
// Update order
|
|
281
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
282
|
+
return { ...s, blocks };
|
|
283
|
+
}),
|
|
284
|
+
}));
|
|
285
|
+
this._isDirty.set(true);
|
|
286
|
+
return newBlock.id;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Update block properties
|
|
290
|
+
*/
|
|
291
|
+
updateBlock(sectionId, blockId, updates) {
|
|
292
|
+
this._schema.update((schema) => ({
|
|
293
|
+
...schema,
|
|
294
|
+
sections: schema.sections.map((s) => {
|
|
295
|
+
if (s.id !== sectionId)
|
|
296
|
+
return s;
|
|
297
|
+
return {
|
|
298
|
+
...s,
|
|
299
|
+
blocks: s.blocks.map((b) => (b.id === blockId ? { ...b, ...updates } : b)),
|
|
300
|
+
};
|
|
301
|
+
}),
|
|
302
|
+
}));
|
|
303
|
+
this._isDirty.set(true);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Delete a block from a section
|
|
307
|
+
*/
|
|
308
|
+
deleteBlock(sectionId, blockId) {
|
|
309
|
+
this._schema.update((schema) => ({
|
|
310
|
+
...schema,
|
|
311
|
+
sections: schema.sections.map((s) => {
|
|
312
|
+
if (s.id !== sectionId)
|
|
313
|
+
return s;
|
|
314
|
+
const blocks = s.blocks.filter((b) => b.id !== blockId);
|
|
315
|
+
// Update order
|
|
316
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
317
|
+
return { ...s, blocks };
|
|
318
|
+
}),
|
|
319
|
+
}));
|
|
320
|
+
this._isDirty.set(true);
|
|
321
|
+
// Clear selection if deleted block was selected
|
|
322
|
+
if (this._selectedBlockId() === blockId) {
|
|
323
|
+
this._selectedBlockId.set(null);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Reorder blocks within a section
|
|
328
|
+
*/
|
|
329
|
+
reorderBlocks(sectionId, fromIndex, toIndex) {
|
|
330
|
+
this._schema.update((schema) => ({
|
|
331
|
+
...schema,
|
|
332
|
+
sections: schema.sections.map((s) => {
|
|
333
|
+
if (s.id !== sectionId)
|
|
334
|
+
return s;
|
|
335
|
+
const blocks = [...s.blocks];
|
|
336
|
+
const [removed] = blocks.splice(fromIndex, 1);
|
|
337
|
+
blocks.splice(toIndex, 0, removed);
|
|
338
|
+
// Update order
|
|
339
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
340
|
+
return { ...s, blocks };
|
|
341
|
+
}),
|
|
342
|
+
}));
|
|
343
|
+
this._isDirty.set(true);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Duplicate a block
|
|
347
|
+
*/
|
|
348
|
+
duplicateBlock(sectionId, blockId) {
|
|
349
|
+
const section = this.sections().find((s) => s.id === sectionId);
|
|
350
|
+
const block = section?.blocks.find((b) => b.id === blockId);
|
|
351
|
+
if (!block)
|
|
352
|
+
return null;
|
|
353
|
+
const newBlock = {
|
|
354
|
+
...structuredClone(block),
|
|
355
|
+
id: crypto.randomUUID(),
|
|
356
|
+
};
|
|
357
|
+
this._schema.update((schema) => ({
|
|
358
|
+
...schema,
|
|
359
|
+
sections: schema.sections.map((s) => {
|
|
360
|
+
if (s.id !== sectionId)
|
|
361
|
+
return s;
|
|
362
|
+
const blockIndex = s.blocks.findIndex((b) => b.id === blockId);
|
|
363
|
+
const blocks = [...s.blocks];
|
|
364
|
+
blocks.splice(blockIndex + 1, 0, newBlock);
|
|
365
|
+
// Update order
|
|
366
|
+
blocks.forEach((b, i) => (b.order = i));
|
|
367
|
+
return { ...s, blocks };
|
|
368
|
+
}),
|
|
369
|
+
}));
|
|
370
|
+
this._isDirty.set(true);
|
|
371
|
+
return newBlock.id;
|
|
372
|
+
}
|
|
373
|
+
// =========================================
|
|
374
|
+
// Selection Operations
|
|
375
|
+
// =========================================
|
|
376
|
+
/**
|
|
377
|
+
* Select a section
|
|
378
|
+
*/
|
|
379
|
+
selectSection(sectionId) {
|
|
380
|
+
this._selectedSectionId.set(sectionId);
|
|
381
|
+
this._selectedBlockId.set(null);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Select a block
|
|
385
|
+
*/
|
|
386
|
+
selectBlock(blockId) {
|
|
387
|
+
if (blockId) {
|
|
388
|
+
// Find the section containing this block
|
|
389
|
+
for (const section of this.sections()) {
|
|
390
|
+
if (section.blocks.some((b) => b.id === blockId)) {
|
|
391
|
+
this._selectedSectionId.set(section.id);
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
this._selectedBlockId.set(blockId);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Clear all selection
|
|
400
|
+
*/
|
|
401
|
+
clearSelection() {
|
|
402
|
+
this._selectedSectionId.set(null);
|
|
403
|
+
this._selectedBlockId.set(null);
|
|
404
|
+
}
|
|
405
|
+
// =========================================
|
|
406
|
+
// Helper Methods
|
|
407
|
+
// =========================================
|
|
408
|
+
/**
|
|
409
|
+
* Get default content for a block type
|
|
410
|
+
*/
|
|
411
|
+
getDefaultContent(type) {
|
|
412
|
+
switch (type) {
|
|
413
|
+
case EmailBlockType.TEXT:
|
|
414
|
+
return { text: 'Enter your text here...', html: '<p>Enter your text here...</p>' };
|
|
415
|
+
case EmailBlockType.IMAGE:
|
|
416
|
+
return { src: '', alt: 'Image' };
|
|
417
|
+
case EmailBlockType.BUTTON:
|
|
418
|
+
return {
|
|
419
|
+
text: 'Click Here',
|
|
420
|
+
link: 'https://',
|
|
421
|
+
backgroundColor: '#007bff',
|
|
422
|
+
textColor: '#ffffff',
|
|
423
|
+
borderRadius: '4px',
|
|
424
|
+
};
|
|
425
|
+
case EmailBlockType.DIVIDER:
|
|
426
|
+
return { height: '1px', color: '#cccccc', style: 'solid' };
|
|
427
|
+
case EmailBlockType.HTML:
|
|
428
|
+
return { html: '<!-- Custom HTML -->' };
|
|
429
|
+
default:
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
434
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService });
|
|
435
|
+
}
|
|
436
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailBuilderStateService, decorators: [{
|
|
437
|
+
type: Injectable
|
|
438
|
+
}] });
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Email module routes
|
|
442
|
+
*/
|
|
443
|
+
const EMAIL_ROUTES = [
|
|
444
|
+
{
|
|
445
|
+
path: '',
|
|
446
|
+
loadComponent: () => Promise.resolve().then(function () { return emailContainer_component; }).then((m) => m.EmailContainerComponent),
|
|
447
|
+
children: [
|
|
448
|
+
// Templates
|
|
449
|
+
{
|
|
450
|
+
path: 'templates',
|
|
451
|
+
children: [
|
|
452
|
+
{
|
|
453
|
+
path: '',
|
|
454
|
+
loadComponent: () => import('./flusys-ng-email-template-list.component-CGJxfZMT.mjs').then((m) => m.TemplateListComponent),
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
path: 'new',
|
|
458
|
+
loadComponent: () => import('./flusys-ng-email-template-form.component-DjzG_lG1.mjs').then((m) => m.TemplateFormComponent),
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
path: ':id',
|
|
462
|
+
loadComponent: () => import('./flusys-ng-email-template-form.component-DjzG_lG1.mjs').then((m) => m.TemplateFormComponent),
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
},
|
|
466
|
+
// Configs
|
|
467
|
+
{
|
|
468
|
+
path: 'configs',
|
|
469
|
+
children: [
|
|
470
|
+
{
|
|
471
|
+
path: '',
|
|
472
|
+
loadComponent: () => import('./flusys-ng-email-email-config-list.component-CJhSPkCZ.mjs').then((m) => m.EmailConfigListComponent),
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
path: 'new',
|
|
476
|
+
loadComponent: () => import('./flusys-ng-email-email-config-form.component-8dOBD-Q-.mjs').then((m) => m.EmailConfigFormComponent),
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
path: ':id',
|
|
480
|
+
loadComponent: () => import('./flusys-ng-email-email-config-form.component-8dOBD-Q-.mjs').then((m) => m.EmailConfigFormComponent),
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
},
|
|
484
|
+
// Default redirect
|
|
485
|
+
{
|
|
486
|
+
path: '',
|
|
487
|
+
redirectTo: 'templates',
|
|
488
|
+
pathMatch: 'full',
|
|
489
|
+
},
|
|
490
|
+
],
|
|
491
|
+
},
|
|
492
|
+
];
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Email container component with tab navigation
|
|
496
|
+
*/
|
|
497
|
+
class EmailContainerComponent {
|
|
498
|
+
tabs = [
|
|
499
|
+
{ id: 'templates', label: 'Templates', icon: 'pi pi-file', route: 'templates' },
|
|
500
|
+
{ id: 'configs', label: 'Configurations', icon: 'pi pi-cog', route: 'configs' },
|
|
501
|
+
];
|
|
502
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
503
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: EmailContainerComponent, isStandalone: true, selector: "lib-email-container", ngImport: i0, template: `
|
|
504
|
+
<div class="email-page p-4">
|
|
505
|
+
<div class="email-header mb-4">
|
|
506
|
+
<h1 class="text-2xl font-bold m-0">Email</h1>
|
|
507
|
+
<p class="text-gray-500 mt-1">Manage email templates and provider configurations</p>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
510
|
+
<div class="email-tabs flex gap-1 mb-4 border-b border-gray-200">
|
|
511
|
+
@for (tab of tabs; track tab.id) {
|
|
512
|
+
<a
|
|
513
|
+
[routerLink]="tab.route"
|
|
514
|
+
routerLinkActive="active"
|
|
515
|
+
class="tab-link flex items-center gap-2 px-4 py-2 rounded-t-lg cursor-pointer transition-colors">
|
|
516
|
+
<i [class]="tab.icon"></i>
|
|
517
|
+
<span>{{ tab.label }}</span>
|
|
518
|
+
</a>
|
|
519
|
+
}
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
<div class="email-content">
|
|
523
|
+
<router-outlet />
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
`, isInline: true, styles: [".tab-link{color:var(--text-color-secondary, #6b7280);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px}.tab-link.active{color:var(--primary-color, #3b82f6);border-bottom-color:var(--primary-color, #3b82f6);background-color:var(--surface-ground, #f9fafb)}.tab-link:hover:not(.active){background-color:var(--surface-hover, #f3f4f6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
527
|
+
}
|
|
528
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailContainerComponent, decorators: [{
|
|
529
|
+
type: Component,
|
|
530
|
+
args: [{ selector: 'lib-email-container', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], template: `
|
|
531
|
+
<div class="email-page p-4">
|
|
532
|
+
<div class="email-header mb-4">
|
|
533
|
+
<h1 class="text-2xl font-bold m-0">Email</h1>
|
|
534
|
+
<p class="text-gray-500 mt-1">Manage email templates and provider configurations</p>
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
<div class="email-tabs flex gap-1 mb-4 border-b border-gray-200">
|
|
538
|
+
@for (tab of tabs; track tab.id) {
|
|
539
|
+
<a
|
|
540
|
+
[routerLink]="tab.route"
|
|
541
|
+
routerLinkActive="active"
|
|
542
|
+
class="tab-link flex items-center gap-2 px-4 py-2 rounded-t-lg cursor-pointer transition-colors">
|
|
543
|
+
<i [class]="tab.icon"></i>
|
|
544
|
+
<span>{{ tab.label }}</span>
|
|
545
|
+
</a>
|
|
546
|
+
}
|
|
547
|
+
</div>
|
|
548
|
+
|
|
549
|
+
<div class="email-content">
|
|
550
|
+
<router-outlet />
|
|
551
|
+
</div>
|
|
552
|
+
</div>
|
|
553
|
+
`, styles: [".tab-link{color:var(--text-color-secondary, #6b7280);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px}.tab-link.active{color:var(--primary-color, #3b82f6);border-bottom-color:var(--primary-color, #3b82f6);background-color:var(--surface-ground, #f9fafb)}.tab-link:hover:not(.active){background-color:var(--surface-hover, #f3f4f6)}\n"] }]
|
|
554
|
+
}] });
|
|
555
|
+
|
|
556
|
+
var emailContainer_component = /*#__PURE__*/Object.freeze({
|
|
557
|
+
__proto__: null,
|
|
558
|
+
EmailContainerComponent: EmailContainerComponent
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// =============================================================================
|
|
562
|
+
// @flusys/ng-email - Email Package
|
|
563
|
+
// =============================================================================
|
|
564
|
+
// Enums
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Generated bundle index. Do not edit.
|
|
568
|
+
*/
|
|
569
|
+
|
|
570
|
+
export { DEFAULT_EMAIL_SETTINGS, EMAIL_ROUTES, EmailBlockType, EmailBuilderStateService, EmailConfigApiService, EmailContainerComponent, EmailProviderEnum, EmailSendService, EmailTemplateApiService, createEmailSchema };
|
|
571
|
+
//# sourceMappingURL=flusys-ng-email.mjs.map
|