@dev.smartpricing/message-composer-utils 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/api/aiIntegration.js +7 -0
- package/dist/types/api/aiIntegration.js.map +1 -0
- package/dist/types/api/apiMessages.js +2 -0
- package/dist/types/api/apiMessages.js.map +1 -0
- package/dist/types/api/index.js +3 -0
- package/dist/types/api/index.js.map +1 -0
- package/dist/types/app.js +23 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/brand.js +31 -0
- package/dist/types/brand.js.map +1 -0
- package/dist/types/dynamic-values.js +5 -0
- package/dist/types/dynamic-values.js.map +1 -0
- package/dist/types/emailblocks.v1.defaults.js +83 -0
- package/dist/types/emailblocks.v1.defaults.js.map +1 -0
- package/dist/types/emailblocks.v1.js +339 -0
- package/dist/types/emailblocks.v1.js.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/kafka-events.js +2 -0
- package/dist/types/kafka-events.js.map +1 -0
- package/dist/types/language.js +2 -0
- package/dist/types/language.js.map +1 -0
- package/dist/types/media.js +6 -0
- package/dist/types/media.js.map +1 -0
- package/dist/types/message.js +41 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/meta-template.js +2 -0
- package/dist/types/meta-template.js.map +1 -0
- package/dist/types/meta-webhook.js +2 -0
- package/dist/types/meta-webhook.js.map +1 -0
- package/dist/types/submission-job.js +2 -0
- package/dist/types/submission-job.js.map +1 -0
- package/dist/types/tag.js +2 -0
- package/dist/types/tag.js.map +1 -0
- package/dist/types/utils.js +2 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types/whatsappblocks.v1.js +24 -0
- package/dist/types/whatsappblocks.v1.js.map +1 -0
- package/dist/utils/array.js +26 -0
- package/dist/utils/array.js.map +1 -0
- package/dist/utils/async.js +22 -0
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/date.js +37 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/index.js +34 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/intl.js +37 -0
- package/dist/utils/intl.js.map +1 -0
- package/dist/utils/meta-status.js +21 -0
- package/dist/utils/meta-status.js.map +1 -0
- package/dist/utils/number.js +24 -0
- package/dist/utils/number.js.map +1 -0
- package/dist/utils/object.js +87 -0
- package/dist/utils/object.js.map +1 -0
- package/dist/utils/string.js +22 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/utils/templates/brand-cascade.js +116 -0
- package/dist/utils/templates/brand-cascade.js.map +1 -0
- package/dist/utils/templates/email-compiler.js +126 -0
- package/dist/utils/templates/email-compiler.js.map +1 -0
- package/dist/utils/templates/email-mjml.js +444 -0
- package/dist/utils/templates/email-mjml.js.map +1 -0
- package/dist/utils/templates/email.js +580 -0
- package/dist/utils/templates/email.js.map +1 -0
- package/dist/utils/templates/html-sanitizer.js +95 -0
- package/dist/utils/templates/html-sanitizer.js.map +1 -0
- package/dist/utils/templates/messages.js +33 -0
- package/dist/utils/templates/messages.js.map +1 -0
- package/dist/utils/templates/meta.js +246 -0
- package/dist/utils/templates/meta.js.map +1 -0
- package/dist/utils/templates/tiptap.js +167 -0
- package/dist/utils/templates/tiptap.js.map +1 -0
- package/dist/utils/templates/whatsapp-compiler.js +168 -0
- package/dist/utils/templates/whatsapp-compiler.js.map +1 -0
- package/dist/utils/templates/whatsapp.js +329 -0
- package/dist/utils/templates/whatsapp.js.map +1 -0
- package/dist/utils/validations.js +39 -0
- package/dist/utils/validations.js.map +1 -0
- package/package.json +43 -0
- package/src/types/api/aiIntegration.ts +59 -0
- package/src/types/api/apiMessages.ts +22 -0
- package/src/types/api/index.ts +2 -0
- package/src/types/app.ts +76 -0
- package/src/types/brand.ts +80 -0
- package/src/types/dynamic-values.ts +47 -0
- package/src/types/emailblocks.v1.defaults.ts +123 -0
- package/src/types/emailblocks.v1.ts +655 -0
- package/src/types/index.ts +15 -0
- package/src/types/kafka-events.ts +46 -0
- package/src/types/language.ts +9 -0
- package/src/types/media.ts +26 -0
- package/src/types/message.ts +635 -0
- package/src/types/meta-template.ts +50 -0
- package/src/types/meta-webhook.ts +32 -0
- package/src/types/submission-job.ts +30 -0
- package/src/types/tag.ts +8 -0
- package/src/types/utils.ts +14 -0
- package/src/types/whatsappblocks.v1.ts +102 -0
- package/src/utils/array.ts +33 -0
- package/src/utils/async.ts +30 -0
- package/src/utils/date.ts +39 -0
- package/src/utils/index.ts +44 -0
- package/src/utils/intl.ts +51 -0
- package/src/utils/meta-status.ts +24 -0
- package/src/utils/number.ts +36 -0
- package/src/utils/object.ts +101 -0
- package/src/utils/string.ts +24 -0
- package/src/utils/templates/brand-cascade.ts +156 -0
- package/src/utils/templates/email-compiler.ts +155 -0
- package/src/utils/templates/email-mjml.ts +602 -0
- package/src/utils/templates/email.ts +713 -0
- package/src/utils/templates/html-sanitizer.ts +121 -0
- package/src/utils/templates/messages.ts +44 -0
- package/src/utils/templates/meta.ts +336 -0
- package/src/utils/templates/tiptap.ts +247 -0
- package/src/utils/templates/whatsapp-compiler.ts +212 -0
- package/src/utils/templates/whatsapp.ts +408 -0
- package/src/utils/validations.ts +49 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
import type { JSONContent } from "@tiptap/core";
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_SPACER_SETTINGS,
|
|
4
|
+
DEFAULT_DIVIDER_SETTINGS,
|
|
5
|
+
DEFAULT_HEADING_SETTINGS,
|
|
6
|
+
DEFAULT_PARAGRAPH_SETTINGS,
|
|
7
|
+
DEFAULT_BUTTON_SETTINGS,
|
|
8
|
+
DEFAULT_GRID_SETTINGS,
|
|
9
|
+
DEFAULT_DISCOUNT_SETTINGS,
|
|
10
|
+
DEFAULT_HEADER_SETTINGS,
|
|
11
|
+
DEFAULT_FOOTER_SETTINGS,
|
|
12
|
+
DEFAULT_UNSUBSCRIBE_LINK_SETTINGS,
|
|
13
|
+
DEFAULT_TOP_PRODUCTS_SETTINGS,
|
|
14
|
+
} from "./emailblocks.v1.defaults.js";
|
|
15
|
+
import { BrandDefaultButtonSettings } from "./brand.js";
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// EMAIL BLOCK TYPES
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
export const EMAIL_BLOCK_TYPES = [
|
|
22
|
+
"spacer",
|
|
23
|
+
"divider",
|
|
24
|
+
"heading",
|
|
25
|
+
"paragraph",
|
|
26
|
+
"image",
|
|
27
|
+
"button",
|
|
28
|
+
"grid",
|
|
29
|
+
"raw_html",
|
|
30
|
+
"discount",
|
|
31
|
+
"header",
|
|
32
|
+
"footer",
|
|
33
|
+
"unsubscribe_link",
|
|
34
|
+
"socials",
|
|
35
|
+
"top_products",
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
export const TRANSLATABLE_BLOCK_TYPES = [
|
|
39
|
+
"heading",
|
|
40
|
+
"paragraph",
|
|
41
|
+
"button",
|
|
42
|
+
"discount",
|
|
43
|
+
"footer",
|
|
44
|
+
"raw_html",
|
|
45
|
+
"unsubscribe_link",
|
|
46
|
+
] as const;
|
|
47
|
+
|
|
48
|
+
export type EmailBlockType = EmailBlock["type"];
|
|
49
|
+
export type TranslatableBlockType = TranslatableBlock["type"];
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// VALIDATION CONSTANTS
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
// Spacer
|
|
56
|
+
export const SPACER_MIN_HEIGHT = 8;
|
|
57
|
+
export const SPACER_MAX_HEIGHT = 200;
|
|
58
|
+
export const SPACER_SIZE_PRESETS = {
|
|
59
|
+
small: 24,
|
|
60
|
+
medium: 40,
|
|
61
|
+
large: 64,
|
|
62
|
+
extra_large: 96,
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
// Divider
|
|
66
|
+
export const DIVIDER_MIN_THICKNESS = 1;
|
|
67
|
+
export const DIVIDER_MAX_THICKNESS = 20;
|
|
68
|
+
export const DIVIDER_MIN_WIDTH = 10;
|
|
69
|
+
export const DIVIDER_MAX_WIDTH = 100;
|
|
70
|
+
|
|
71
|
+
// Text blocks
|
|
72
|
+
export const FONT_SIZE_MIN = 10;
|
|
73
|
+
export const FONT_SIZE_MAX = 48;
|
|
74
|
+
export const EMAIL_SAFE_FONTS = [
|
|
75
|
+
"Arial",
|
|
76
|
+
"Helvetica",
|
|
77
|
+
"Georgia",
|
|
78
|
+
"Times New Roman",
|
|
79
|
+
"Trebuchet MS",
|
|
80
|
+
"Verdana",
|
|
81
|
+
"Courier New",
|
|
82
|
+
] as const;
|
|
83
|
+
export type SafeFonts = (typeof EMAIL_SAFE_FONTS)[number];
|
|
84
|
+
|
|
85
|
+
export const EMAIL_SAFE_FONT_ITEMS = EMAIL_SAFE_FONTS.map((font) => ({
|
|
86
|
+
value: font,
|
|
87
|
+
label: font,
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
// Heading
|
|
91
|
+
export const HEADING_TAGS = ["h1", "h2", "h3", "h4", "h5", "h6"] as const;
|
|
92
|
+
export const TEXT_TAGS = ["p", ...HEADING_TAGS] as const;
|
|
93
|
+
|
|
94
|
+
export const TAGS_DEFAULT_FONT_SIZE: Record<
|
|
95
|
+
(typeof TEXT_TAGS)[number],
|
|
96
|
+
number
|
|
97
|
+
> = {
|
|
98
|
+
h1: 28,
|
|
99
|
+
h2: 24,
|
|
100
|
+
h3: 20,
|
|
101
|
+
h4: 18,
|
|
102
|
+
h5: 16,
|
|
103
|
+
h6: 14,
|
|
104
|
+
p: 16,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// HTML
|
|
108
|
+
export const HTML_MAX_LENGTH = 50000;
|
|
109
|
+
|
|
110
|
+
// Image
|
|
111
|
+
export const IMAGE_MIN_WIDTH = 50;
|
|
112
|
+
export const IMAGE_MAX_WIDTH = 600;
|
|
113
|
+
|
|
114
|
+
// Content width
|
|
115
|
+
export const CONTENT_WIDTH_MIN = 400;
|
|
116
|
+
export const CONTENT_WIDTH_MAX = 800;
|
|
117
|
+
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// BASE BLOCK
|
|
120
|
+
// ============================================================================
|
|
121
|
+
|
|
122
|
+
export interface EmailBlockBase {
|
|
123
|
+
id: string; // crypto.randomUUID()
|
|
124
|
+
type: EmailBlockType;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// INDIVIDUAL BLOCK TYPES
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
export interface SpacerBlock extends EmailBlockBase {
|
|
132
|
+
type: "spacer";
|
|
133
|
+
settings: {
|
|
134
|
+
customSize: boolean;
|
|
135
|
+
height: number; // 8-200px
|
|
136
|
+
backgroundColor: string; // CSS color or 'transparent'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface DividerBlock extends EmailBlockBase {
|
|
141
|
+
type: "divider";
|
|
142
|
+
settings: {
|
|
143
|
+
style: "solid" | "dashed" | "dotted";
|
|
144
|
+
thickness: number; // 1-10px
|
|
145
|
+
width: number; // 10-100%
|
|
146
|
+
color: string;
|
|
147
|
+
backgroundColor: string;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface HeadingBlock extends EmailBlockBase {
|
|
152
|
+
type: "heading";
|
|
153
|
+
settings: {
|
|
154
|
+
tag: (typeof HEADING_TAGS)[number];
|
|
155
|
+
content: JSONContent | undefined; // TipTap format
|
|
156
|
+
fontFamily?: string; // undefined = use global default
|
|
157
|
+
fontSize: number; // 16-48px
|
|
158
|
+
textColor?: string; // undefined = use global default
|
|
159
|
+
backgroundColor: string;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface ParagraphBlock extends EmailBlockBase {
|
|
164
|
+
type: "paragraph";
|
|
165
|
+
settings: {
|
|
166
|
+
tag: (typeof TEXT_TAGS)[number];
|
|
167
|
+
content: JSONContent | undefined; // TipTap rich text
|
|
168
|
+
fontFamily?: string; // undefined = use global default
|
|
169
|
+
fontSize: number; // 10-32px
|
|
170
|
+
textColor?: string; // undefined = use global default
|
|
171
|
+
backgroundColor: string;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface ImageBlock extends EmailBlockBase {
|
|
176
|
+
type: "image";
|
|
177
|
+
settings: {
|
|
178
|
+
src: string; // Image source URL
|
|
179
|
+
href?: string; // Optional link URL
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface ButtonBlock extends EmailBlockBase {
|
|
184
|
+
type: "button";
|
|
185
|
+
settings: {
|
|
186
|
+
content: JSONContent | undefined; // Button text with formatting
|
|
187
|
+
linkType: "web" | "email" | "phone";
|
|
188
|
+
url: string;
|
|
189
|
+
fontFamily?: string; // undefined = use global default
|
|
190
|
+
fontSize: number; // 12-32px
|
|
191
|
+
shape: "square" | "rounded" | "pill";
|
|
192
|
+
width: "fit_to_text" | "full_width";
|
|
193
|
+
alignment: "left" | "center" | "right";
|
|
194
|
+
textColor?: string; // undefined = use global default
|
|
195
|
+
backgroundColor?: string; //undefined = use global default
|
|
196
|
+
backgroundBlock: string;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Grid types
|
|
201
|
+
export interface GridColumn {
|
|
202
|
+
id: string; // UUID
|
|
203
|
+
blocks: GridAllowedBlock[];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface GridBlock extends EmailBlockBase {
|
|
207
|
+
type: "grid";
|
|
208
|
+
settings: {
|
|
209
|
+
columns: number; // 1, 2, or 3
|
|
210
|
+
backgroundColor: string;
|
|
211
|
+
columnData: GridColumn[];
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Blocks allowed inside grid columns (NO grid-in-grid, no header/footer/html/drif)
|
|
216
|
+
export type GridAllowedBlock =
|
|
217
|
+
| DiscountBlock
|
|
218
|
+
| HeadingBlock
|
|
219
|
+
| ParagraphBlock
|
|
220
|
+
| ImageBlock
|
|
221
|
+
| ButtonBlock;
|
|
222
|
+
|
|
223
|
+
export interface RawHtmlBlock extends EmailBlockBase {
|
|
224
|
+
type: "raw_html";
|
|
225
|
+
settings: {
|
|
226
|
+
html: string; // Max 50,000 chars
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface DiscountBlock extends EmailBlockBase {
|
|
231
|
+
type: "discount";
|
|
232
|
+
settings: {
|
|
233
|
+
content: JSONContent | undefined; // Discount code text with formatting
|
|
234
|
+
tag: (typeof TEXT_TAGS)[number];
|
|
235
|
+
fontFamily?: string; // undefined = use global default
|
|
236
|
+
fontSize: number; // 12-48px
|
|
237
|
+
style: "square" | "rounded" | "pill";
|
|
238
|
+
width: "fit_to_text" | "full_width";
|
|
239
|
+
textColor?: string; // undefined = use global default
|
|
240
|
+
backgroundComponent: string; // Code box background
|
|
241
|
+
backgroundBlock: string; // Overall block background
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface HeaderBlock extends EmailBlockBase {
|
|
246
|
+
type: "header";
|
|
247
|
+
settings: {
|
|
248
|
+
src: string;
|
|
249
|
+
alt: string;
|
|
250
|
+
width: number; // 100-300px
|
|
251
|
+
alignment: "left" | "center" | "right";
|
|
252
|
+
backgroundColor: string;
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface FooterBlock extends EmailBlockBase {
|
|
257
|
+
type: "footer";
|
|
258
|
+
settings: {
|
|
259
|
+
content: JSONContent | undefined; // Rich text
|
|
260
|
+
fontSize: number; // 10-16px
|
|
261
|
+
fontFamily?: string; // undefined = use global default
|
|
262
|
+
textColor?: string; // undefined = use global default
|
|
263
|
+
backgroundColor: string;
|
|
264
|
+
alignment: "left" | "center" | "right";
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface UnsubscribeLinkBlock extends EmailBlockBase {
|
|
269
|
+
type: "unsubscribe_link";
|
|
270
|
+
settings: {
|
|
271
|
+
content: JSONContent | undefined; // Must contain {{unsubscribe}}
|
|
272
|
+
fontFamily?: string;
|
|
273
|
+
fontSize: number; // default 12px
|
|
274
|
+
textColor?: string; // default lower contrast
|
|
275
|
+
backgroundColor: string;
|
|
276
|
+
alignment: "left" | "center" | "right";
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export type SocialPlatform =
|
|
281
|
+
| "facebook"
|
|
282
|
+
| "instagram"
|
|
283
|
+
| "tripadvisor"
|
|
284
|
+
| "tiktok"
|
|
285
|
+
| "google";
|
|
286
|
+
|
|
287
|
+
export interface SocialLink {
|
|
288
|
+
enabled: boolean;
|
|
289
|
+
url: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export const SOCIAL_ICONS: Record<SocialPlatform, string> = {
|
|
293
|
+
facebook:
|
|
294
|
+
"http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/8246b205-8497-4fdc-b834-a66a6fccf009/24x24.png",
|
|
295
|
+
instagram:
|
|
296
|
+
"http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/0d446d50-f646-428c-83f2-73ca2b6c4c3e/24x24.png",
|
|
297
|
+
tripadvisor:
|
|
298
|
+
"http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/6fc003ce-242d-46a9-923e-76e7f078727e/24x24.png",
|
|
299
|
+
tiktok:
|
|
300
|
+
"http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/a56f5bf7-0f22-4a06-b41a-d552684e731b/24x24.png",
|
|
301
|
+
google:
|
|
302
|
+
"http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/2dd79979-88ea-4074-9a4e-e646ddaed114/24x24.png",
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
export const SOCIAL_PLATFORMS = Object.keys(SOCIAL_ICONS) as SocialPlatform[];
|
|
306
|
+
|
|
307
|
+
export interface SocialsBlock extends EmailBlockBase {
|
|
308
|
+
type: "socials";
|
|
309
|
+
settings: {
|
|
310
|
+
backgroundColor: string;
|
|
311
|
+
socials: Record<SocialPlatform, SocialLink>;
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface TopProductsProduct {
|
|
316
|
+
name: string;
|
|
317
|
+
image: string;
|
|
318
|
+
link: string;
|
|
319
|
+
price: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export interface TopProductsBlock extends EmailBlockBase {
|
|
323
|
+
type: "top_products";
|
|
324
|
+
settings: {
|
|
325
|
+
storeId: string; // Smartconnect store identifier for the upselling API
|
|
326
|
+
maxProducts: number; // Max products to display (default 4)
|
|
327
|
+
backgroundColor: string; // Wrapper background color
|
|
328
|
+
};
|
|
329
|
+
/** Populated at compile time by the backend enrichment step */
|
|
330
|
+
_products?: TopProductsProduct[];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ============================================================================
|
|
334
|
+
// UNION TYPE
|
|
335
|
+
// ============================================================================
|
|
336
|
+
|
|
337
|
+
export type EmailBlock =
|
|
338
|
+
| SpacerBlock
|
|
339
|
+
| DividerBlock
|
|
340
|
+
| HeadingBlock
|
|
341
|
+
| ParagraphBlock
|
|
342
|
+
| ImageBlock
|
|
343
|
+
| ButtonBlock
|
|
344
|
+
| GridBlock
|
|
345
|
+
| RawHtmlBlock
|
|
346
|
+
| DiscountBlock
|
|
347
|
+
| HeaderBlock
|
|
348
|
+
| FooterBlock
|
|
349
|
+
| UnsubscribeLinkBlock
|
|
350
|
+
| SocialsBlock
|
|
351
|
+
| TopProductsBlock;
|
|
352
|
+
|
|
353
|
+
export type TranslatableBlock =
|
|
354
|
+
| HeadingBlock
|
|
355
|
+
| ParagraphBlock
|
|
356
|
+
| ButtonBlock
|
|
357
|
+
| DiscountBlock
|
|
358
|
+
| FooterBlock
|
|
359
|
+
| UnsubscribeLinkBlock;
|
|
360
|
+
|
|
361
|
+
// ============================================================================
|
|
362
|
+
// GLOBAL EMAIL SETTINGS
|
|
363
|
+
// ============================================================================
|
|
364
|
+
|
|
365
|
+
export interface EmailGlobalSettings {
|
|
366
|
+
backgroundColor?: string; // Default #F3F4F6 (page/canvas background)
|
|
367
|
+
contentBackgroundColor?: string; // Default #FFFFFF (content area/body background)
|
|
368
|
+
contentWidth?: number; // Default 600px (400-800)
|
|
369
|
+
fontFamily?: SafeFonts; // Default Arial
|
|
370
|
+
textColor?: string; // Default #1F2937
|
|
371
|
+
verticalSpacing?: number; // Default 0px (0-50), gap between blocks
|
|
372
|
+
horizontalSpacing?: number; // Default 0px (0-50), left/right content inset
|
|
373
|
+
button?: BrandDefaultButtonSettings;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export const DEFAULT_EMAIL_GLOBAL_SETTINGS: Required<EmailGlobalSettings> = {
|
|
377
|
+
backgroundColor: "#F3F4F6",
|
|
378
|
+
contentBackgroundColor: "#FFFFFF",
|
|
379
|
+
contentWidth: 600,
|
|
380
|
+
fontFamily: "Arial",
|
|
381
|
+
textColor: "#1F2937",
|
|
382
|
+
verticalSpacing: 0,
|
|
383
|
+
horizontalSpacing: 0,
|
|
384
|
+
button: {
|
|
385
|
+
backgroundColor: "#FFFFFF",
|
|
386
|
+
textColor: "#000000",
|
|
387
|
+
},
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
export function emptySpacerBlock(): SpacerBlock {
|
|
391
|
+
return {
|
|
392
|
+
id: crypto.randomUUID(),
|
|
393
|
+
type: "spacer",
|
|
394
|
+
settings: { ...DEFAULT_SPACER_SETTINGS },
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function emptyDividerBlock(): DividerBlock {
|
|
399
|
+
return {
|
|
400
|
+
id: crypto.randomUUID(),
|
|
401
|
+
type: "divider",
|
|
402
|
+
settings: { ...DEFAULT_DIVIDER_SETTINGS },
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function emptyHeadingBlock(): HeadingBlock {
|
|
407
|
+
return {
|
|
408
|
+
id: crypto.randomUUID(),
|
|
409
|
+
type: "heading",
|
|
410
|
+
settings: { ...DEFAULT_HEADING_SETTINGS, content: undefined },
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function emptyParagraphBlock(): ParagraphBlock {
|
|
415
|
+
return {
|
|
416
|
+
id: crypto.randomUUID(),
|
|
417
|
+
type: "paragraph",
|
|
418
|
+
settings: { ...DEFAULT_PARAGRAPH_SETTINGS, content: undefined },
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function emptyImageBlock(): ImageBlock {
|
|
423
|
+
return {
|
|
424
|
+
id: crypto.randomUUID(),
|
|
425
|
+
type: "image",
|
|
426
|
+
settings: { src: "", href: undefined },
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export function emptyButtonBlock(): ButtonBlock {
|
|
431
|
+
return {
|
|
432
|
+
id: crypto.randomUUID(),
|
|
433
|
+
type: "button",
|
|
434
|
+
settings: { ...DEFAULT_BUTTON_SETTINGS, content: undefined },
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export function emptyGridBlock(): GridBlock {
|
|
439
|
+
return {
|
|
440
|
+
id: crypto.randomUUID(),
|
|
441
|
+
type: "grid",
|
|
442
|
+
settings: { ...DEFAULT_GRID_SETTINGS, columnData: [] },
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function emptyRawHtmlBlock(): RawHtmlBlock {
|
|
447
|
+
return {
|
|
448
|
+
id: crypto.randomUUID(),
|
|
449
|
+
type: "raw_html",
|
|
450
|
+
settings: { html: "" },
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export function emptyDiscountBlock(): DiscountBlock {
|
|
455
|
+
return {
|
|
456
|
+
id: crypto.randomUUID(),
|
|
457
|
+
type: "discount",
|
|
458
|
+
settings: { ...DEFAULT_DISCOUNT_SETTINGS, content: undefined },
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export function emptyHeaderBlock(): HeaderBlock {
|
|
463
|
+
return {
|
|
464
|
+
id: crypto.randomUUID(),
|
|
465
|
+
type: "header",
|
|
466
|
+
settings: { ...DEFAULT_HEADER_SETTINGS },
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export function emptyFooterBlock(): FooterBlock {
|
|
471
|
+
return {
|
|
472
|
+
id: crypto.randomUUID(),
|
|
473
|
+
type: "footer",
|
|
474
|
+
settings: {
|
|
475
|
+
...DEFAULT_FOOTER_SETTINGS,
|
|
476
|
+
content: {
|
|
477
|
+
type: "doc",
|
|
478
|
+
content: [
|
|
479
|
+
{
|
|
480
|
+
type: "paragraph",
|
|
481
|
+
attrs: { textAlign: null },
|
|
482
|
+
content: [
|
|
483
|
+
{
|
|
484
|
+
type: "text",
|
|
485
|
+
marks: [{ type: "bold" }],
|
|
486
|
+
text: "{{property_name}}",
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
type: "paragraph",
|
|
492
|
+
attrs: { textAlign: null },
|
|
493
|
+
content: [{ type: "text", text: "{{property_address}}" }],
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
type: "paragraph",
|
|
497
|
+
attrs: { textAlign: null },
|
|
498
|
+
content: [
|
|
499
|
+
{
|
|
500
|
+
type: "text",
|
|
501
|
+
text: "{{property_telephone}} / {{property_email}} / {{property_website}}",
|
|
502
|
+
},
|
|
503
|
+
],
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const UNSUBSCRIBE_LINK_CONTENT: Record<
|
|
512
|
+
string,
|
|
513
|
+
{ prefix: string; linkText: string; suffix: string }
|
|
514
|
+
> = {
|
|
515
|
+
en: {
|
|
516
|
+
prefix:
|
|
517
|
+
"If you don't want to receive this type of emails anymore, you can unsubscribe ",
|
|
518
|
+
linkText: "here",
|
|
519
|
+
suffix: ".",
|
|
520
|
+
},
|
|
521
|
+
it: {
|
|
522
|
+
prefix:
|
|
523
|
+
"Se non desideri più ricevere questo tipo di email, puoi annullare l'iscrizione ",
|
|
524
|
+
linkText: "qui",
|
|
525
|
+
suffix: ".",
|
|
526
|
+
},
|
|
527
|
+
de: {
|
|
528
|
+
prefix:
|
|
529
|
+
"Wenn Sie diese Art von E-Mails nicht mehr erhalten möchten, können Sie sich ",
|
|
530
|
+
linkText: "hier",
|
|
531
|
+
suffix: " abmelden.",
|
|
532
|
+
},
|
|
533
|
+
fr: {
|
|
534
|
+
prefix:
|
|
535
|
+
"Si vous ne souhaitez plus recevoir ce type d'e-mails, vous pouvez vous désabonner ",
|
|
536
|
+
linkText: "ici",
|
|
537
|
+
suffix: ".",
|
|
538
|
+
},
|
|
539
|
+
es: {
|
|
540
|
+
prefix:
|
|
541
|
+
"Si no deseas recibir más este tipo de correos, puedes darte de baja ",
|
|
542
|
+
linkText: "aquí",
|
|
543
|
+
suffix: ".",
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
export function emptyUnsubscribeLinkBlock(
|
|
548
|
+
language?: string,
|
|
549
|
+
): UnsubscribeLinkBlock {
|
|
550
|
+
const { prefix, linkText, suffix } = (UNSUBSCRIBE_LINK_CONTENT[
|
|
551
|
+
language ?? "en"
|
|
552
|
+
] ?? UNSUBSCRIBE_LINK_CONTENT.en)!;
|
|
553
|
+
|
|
554
|
+
return {
|
|
555
|
+
id: crypto.randomUUID(),
|
|
556
|
+
type: "unsubscribe_link",
|
|
557
|
+
settings: {
|
|
558
|
+
...DEFAULT_UNSUBSCRIBE_LINK_SETTINGS,
|
|
559
|
+
content: {
|
|
560
|
+
type: "doc",
|
|
561
|
+
content: [
|
|
562
|
+
{
|
|
563
|
+
type: "paragraph",
|
|
564
|
+
attrs: { textAlign: null },
|
|
565
|
+
content: [
|
|
566
|
+
{
|
|
567
|
+
type: "text",
|
|
568
|
+
text: prefix,
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
type: "text",
|
|
572
|
+
marks: [
|
|
573
|
+
{
|
|
574
|
+
type: "link",
|
|
575
|
+
attrs: {
|
|
576
|
+
href: "{{unsubscribe}}",
|
|
577
|
+
target: "_blank",
|
|
578
|
+
rel: "noopener noreferrer nofollow",
|
|
579
|
+
class: "underline",
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
text: linkText,
|
|
584
|
+
},
|
|
585
|
+
{ type: "text", text: suffix },
|
|
586
|
+
],
|
|
587
|
+
},
|
|
588
|
+
],
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export function emptyTopProductsBlock(): TopProductsBlock {
|
|
595
|
+
return {
|
|
596
|
+
id: crypto.randomUUID(),
|
|
597
|
+
type: "top_products",
|
|
598
|
+
settings: { ...DEFAULT_TOP_PRODUCTS_SETTINGS },
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function emptySocialsBlock(): SocialsBlock {
|
|
603
|
+
return {
|
|
604
|
+
id: crypto.randomUUID(),
|
|
605
|
+
type: "socials",
|
|
606
|
+
settings: {
|
|
607
|
+
backgroundColor: "transparent",
|
|
608
|
+
socials: {
|
|
609
|
+
facebook: { enabled: false, url: "" },
|
|
610
|
+
instagram: { enabled: false, url: "" },
|
|
611
|
+
tripadvisor: { enabled: false, url: "" },
|
|
612
|
+
tiktok: { enabled: false, url: "" },
|
|
613
|
+
google: { enabled: false, url: "" },
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export function emptyEmailBlock(
|
|
620
|
+
type: EmailBlockType,
|
|
621
|
+
language?: string,
|
|
622
|
+
): EmailBlock {
|
|
623
|
+
switch (type) {
|
|
624
|
+
case "spacer":
|
|
625
|
+
return emptySpacerBlock();
|
|
626
|
+
case "divider":
|
|
627
|
+
return emptyDividerBlock();
|
|
628
|
+
case "heading":
|
|
629
|
+
return emptyHeadingBlock();
|
|
630
|
+
case "paragraph":
|
|
631
|
+
return emptyParagraphBlock();
|
|
632
|
+
case "image":
|
|
633
|
+
return emptyImageBlock();
|
|
634
|
+
case "button":
|
|
635
|
+
return emptyButtonBlock();
|
|
636
|
+
case "grid":
|
|
637
|
+
return emptyGridBlock();
|
|
638
|
+
case "raw_html":
|
|
639
|
+
return emptyRawHtmlBlock();
|
|
640
|
+
case "discount":
|
|
641
|
+
return emptyDiscountBlock();
|
|
642
|
+
case "header":
|
|
643
|
+
return emptyHeaderBlock();
|
|
644
|
+
case "footer":
|
|
645
|
+
return emptyFooterBlock();
|
|
646
|
+
case "unsubscribe_link":
|
|
647
|
+
return emptyUnsubscribeLinkBlock(language);
|
|
648
|
+
case "socials":
|
|
649
|
+
return emptySocialsBlock();
|
|
650
|
+
case "top_products":
|
|
651
|
+
return emptyTopProductsBlock();
|
|
652
|
+
default:
|
|
653
|
+
throw new Error(`Unknown block type: ${type}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./app.js";
|
|
2
|
+
export * from "./utils.js";
|
|
3
|
+
export * from "./language.js";
|
|
4
|
+
export * from "./message.js";
|
|
5
|
+
export * from "./api/index.js";
|
|
6
|
+
export * from "./whatsappblocks.v1.js";
|
|
7
|
+
export * from "./emailblocks.v1.js";
|
|
8
|
+
export * from "./emailblocks.v1.defaults.js";
|
|
9
|
+
export * from "./media.js";
|
|
10
|
+
export * from "./meta-webhook.js";
|
|
11
|
+
export * from "./meta-template.js";
|
|
12
|
+
export * from "./submission-job.js";
|
|
13
|
+
export * from "./kafka-events.js";
|
|
14
|
+
export * from "./dynamic-values.js";
|
|
15
|
+
export * from "./brand.js";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { MessageStatus, MessageGroupCategory } from "./message.js";
|
|
2
|
+
|
|
3
|
+
export interface KafkaEventBase {
|
|
4
|
+
event_id: string;
|
|
5
|
+
event_type: string;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
message_group_id: string;
|
|
8
|
+
owner?: string;
|
|
9
|
+
user_id: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface MessageGroupDeletedEvent extends KafkaEventBase {
|
|
13
|
+
event_type: "MESSAGE_GROUP_DELETED";
|
|
14
|
+
message_group_name: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface MessageStatusChangedEvent extends KafkaEventBase {
|
|
18
|
+
event_type: "MESSAGE_STATUS_CHANGED";
|
|
19
|
+
message_id: string;
|
|
20
|
+
language_id: string;
|
|
21
|
+
previous_status: MessageStatus;
|
|
22
|
+
new_status: MessageStatus;
|
|
23
|
+
was_approved: boolean;
|
|
24
|
+
source: "api" | "meta_webhook";
|
|
25
|
+
aggregated_status: Record<MessageStatus, number>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MessageGroupLanguageLostEvent extends KafkaEventBase {
|
|
29
|
+
event_type: "MESSAGE_GROUP_LANGUAGE_LOST";
|
|
30
|
+
language_id: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface MessageGroupCategoryChangedEvent extends KafkaEventBase {
|
|
34
|
+
event_type: "MESSAGE_GROUP_CATEGORY_CHANGED";
|
|
35
|
+
previous_category: MessageGroupCategory;
|
|
36
|
+
new_category: MessageGroupCategory;
|
|
37
|
+
source: "meta_webhook";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type SmartnessKafkaEvent =
|
|
41
|
+
| MessageGroupDeletedEvent
|
|
42
|
+
| MessageStatusChangedEvent
|
|
43
|
+
| MessageGroupLanguageLostEvent
|
|
44
|
+
| MessageGroupCategoryChangedEvent;
|
|
45
|
+
|
|
46
|
+
export type SmartnessKafkaEventType = SmartnessKafkaEvent["event_type"];
|