@antelopejs/dms-mailing 0.7.0 → 0.8.0

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.
Files changed (219) hide show
  1. package/README.md +28 -10
  2. package/dist/constants.d.ts +0 -2
  3. package/dist/constants.js +1 -3
  4. package/dist/constants.js.map +1 -1
  5. package/dist/crons/jobs.d.ts +1 -1
  6. package/dist/data/body.js +2 -1
  7. package/dist/data/body.js.map +1 -1
  8. package/dist/data/templates-table.js +5 -11
  9. package/dist/data/templates-table.js.map +1 -1
  10. package/dist/db/models/index.d.ts +0 -1
  11. package/dist/db/models/index.js +0 -1
  12. package/dist/db/models/index.js.map +1 -1
  13. package/dist/db/models/send-events.model.js +2 -3
  14. package/dist/db/models/send-events.model.js.map +1 -1
  15. package/dist/db/models/sends.model.js +2 -3
  16. package/dist/db/models/sends.model.js.map +1 -1
  17. package/dist/db/models/template-versions.model.js.map +1 -1
  18. package/dist/db/models/templates.model.js +4 -10
  19. package/dist/db/models/templates.model.js.map +1 -1
  20. package/dist/db/tables/index.d.ts +0 -1
  21. package/dist/db/tables/index.js +0 -1
  22. package/dist/db/tables/index.js.map +1 -1
  23. package/dist/db/tables/settings.table.d.ts +0 -1
  24. package/dist/db/tables/settings.table.js +0 -4
  25. package/dist/db/tables/settings.table.js.map +1 -1
  26. package/dist/db/tables/templates.table.d.ts +0 -3
  27. package/dist/db/tables/templates.table.js +1 -13
  28. package/dist/db/tables/templates.table.js.map +1 -1
  29. package/dist/engine/changes.js +2 -1
  30. package/dist/engine/changes.js.map +1 -1
  31. package/dist/engine/conditions.js +2 -3
  32. package/dist/engine/conditions.js.map +1 -1
  33. package/dist/engine/fallback-html.js +8 -8
  34. package/dist/engine/fallback-html.js.map +1 -1
  35. package/dist/engine/formats.js +6 -6
  36. package/dist/engine/formats.js.map +1 -1
  37. package/dist/engine/paths.js +2 -3
  38. package/dist/engine/paths.js.map +1 -1
  39. package/dist/engine/system-variables.js +1 -1
  40. package/dist/engine/system-variables.js.map +1 -1
  41. package/dist/engine/tokens.js.map +1 -1
  42. package/dist/hooks/index.d.ts +0 -1
  43. package/dist/hooks/index.js +0 -1
  44. package/dist/hooks/index.js.map +1 -1
  45. package/dist/implementations/dms-mailing/index.d.ts +3 -4
  46. package/dist/implementations/dms-mailing/index.js +8 -9
  47. package/dist/implementations/dms-mailing/index.js.map +1 -1
  48. package/dist/index.js +0 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/pages/sends.js.map +1 -1
  51. package/dist/pages/settings/form.js +8 -0
  52. package/dist/pages/settings/form.js.map +1 -1
  53. package/dist/pages/toolbar.js.map +1 -1
  54. package/dist/routes/events.js +2 -2
  55. package/dist/routes/events.js.map +1 -1
  56. package/dist/routes/metrics.js +6 -5
  57. package/dist/routes/metrics.js.map +1 -1
  58. package/dist/routes/sends.js +1 -1
  59. package/dist/routes/sends.js.map +1 -1
  60. package/dist/routes/settings.js +6 -6
  61. package/dist/routes/settings.js.map +1 -1
  62. package/dist/routes/templates.js +6 -10
  63. package/dist/routes/templates.js.map +1 -1
  64. package/dist/services/attention.js +2 -1
  65. package/dist/services/attention.js.map +1 -1
  66. package/dist/services/categories.js +6 -6
  67. package/dist/services/categories.js.map +1 -1
  68. package/dist/services/checked-send.js +16 -9
  69. package/dist/services/checked-send.js.map +1 -1
  70. package/dist/services/declarations.js +42 -184
  71. package/dist/services/declarations.js.map +1 -1
  72. package/dist/services/events.js +11 -7
  73. package/dist/services/events.js.map +1 -1
  74. package/dist/services/localized-text.d.ts +2 -1
  75. package/dist/services/localized-text.js +2 -1
  76. package/dist/services/localized-text.js.map +1 -1
  77. package/dist/services/metrics.js.map +1 -1
  78. package/dist/services/render.js.map +1 -1
  79. package/dist/services/send-import.js +7 -5
  80. package/dist/services/send-import.js.map +1 -1
  81. package/dist/services/send.js +4 -3
  82. package/dist/services/send.js.map +1 -1
  83. package/dist/services/settings.d.ts +1 -1
  84. package/dist/services/settings.js +1 -5
  85. package/dist/services/settings.js.map +1 -1
  86. package/dist/services/starters.js +5 -5
  87. package/dist/services/starters.js.map +1 -1
  88. package/dist/services/template-stats.js +5 -2
  89. package/dist/services/template-stats.js.map +1 -1
  90. package/dist/services/templates.d.ts +2 -2
  91. package/dist/services/templates.js +54 -29
  92. package/dist/services/templates.js.map +1 -1
  93. package/dist/types/settings.d.ts +2 -0
  94. package/dist/types/settings.js +8 -1
  95. package/dist/types/settings.js.map +1 -1
  96. package/dist/validation/declarations.schema.d.ts +16 -16
  97. package/dist/validation/declarations.schema.js +2 -2
  98. package/dist/validation/declarations.schema.js.map +1 -1
  99. package/dist/validation/guards.d.ts +4 -0
  100. package/dist/validation/guards.js +19 -0
  101. package/dist/validation/guards.js.map +1 -0
  102. package/dist/validation/send-event-type.schema.d.ts +2 -0
  103. package/dist/validation/send-event-type.schema.js +11 -0
  104. package/dist/validation/send-event-type.schema.js.map +1 -0
  105. package/dist/validation/settings.schema.d.ts +16 -16
  106. package/dist/validation/settings.schema.js +1 -1
  107. package/dist/validation/settings.schema.js.map +1 -1
  108. package/dist/validation/templates.schema.d.ts +19 -18
  109. package/dist/validation/templates.schema.js.map +1 -1
  110. package/frontend-vue/app/build/components/TemplateDrawerFooter.vue +45 -0
  111. package/frontend-vue/app/build/components/TemplateDrawerPerformance.vue +102 -0
  112. package/frontend-vue/app/build/components/TemplateDrawerVariables.vue +110 -0
  113. package/frontend-vue/app/build/composables/useDrawerStats.ts +78 -0
  114. package/frontend-vue/app/components/DuplicateModal.vue +3 -11
  115. package/frontend-vue/app/components/FixAddressModal.vue +2 -1
  116. package/frontend-vue/app/components/NewTemplateModal.vue +3 -11
  117. package/frontend-vue/app/components/RealSendModal.vue +6 -17
  118. package/frontend-vue/app/components/RenderingModal.vue +2 -1
  119. package/frontend-vue/app/components/SendDrawer.vue +5 -4
  120. package/frontend-vue/app/components/StarterGallery.vue +3 -11
  121. package/frontend-vue/app/components/TemplateDrawer.vue +40 -269
  122. package/frontend-vue/app/components/TestSendModal.vue +7 -18
  123. package/frontend-vue/app/components/VersionHistory.vue +2 -7
  124. package/frontend-vue/app/components/WebhookStatus.vue +2 -1
  125. package/frontend-vue/app/components/editor/EditorWorkspace.vue +2 -7
  126. package/frontend-vue/build/backend-boundary.ts +122 -0
  127. package/frontend-vue/dms.frontend.build.ts +7 -0
  128. package/frontend-vue/eslint.config.mjs +13 -0
  129. package/frontend-vue/package.json +4 -2
  130. package/frontend-vue/pnpm-lock.yaml +210 -61
  131. package/frontend-vue/tests/backend-boundary.test.ts +203 -0
  132. package/frontend-vue/tests/dnd.test.ts +1 -2
  133. package/frontend-vue/tests/editor-block-list.test.ts +136 -53
  134. package/frontend-vue/tests/helpers/auth-fetch.ts +123 -0
  135. package/frontend-vue/tests/helpers/nuxt-globals.ts +17 -1
  136. package/frontend-vue/tests/new-template-modal.test.ts +41 -6
  137. package/frontend-vue/tests/page-reads.test.ts +26 -6
  138. package/frontend-vue/tests/send-actions.test.ts +0 -1
  139. package/frontend-vue/tests/send-drawer.test.ts +2 -6
  140. package/frontend-vue/tests/send-modals.test.ts +8 -5
  141. package/frontend-vue/tests/sortable-list.test.ts +54 -62
  142. package/frontend-vue/tests/suppression.test.ts +1 -2
  143. package/frontend-vue/tests/template-drawer.test.ts +27 -18
  144. package/frontend-vue/tests/template-gallery.test.ts +7 -5
  145. package/frontend-vue/tests/template-preview-frame.test.ts +2 -5
  146. package/package.json +8 -13
  147. package/skills/dms-mailing/SKILL.md +11 -17
  148. package/skills/dms-mailing/cases.json +49 -0
  149. package/src/constants.ts +0 -2
  150. package/src/crons/jobs.ts +1 -1
  151. package/src/data/body.ts +2 -1
  152. package/src/data/templates-table.ts +15 -22
  153. package/src/db/models/index.ts +0 -1
  154. package/src/db/models/send-events.model.ts +2 -2
  155. package/src/db/models/sends.model.ts +7 -8
  156. package/src/db/models/template-versions.model.ts +5 -1
  157. package/src/db/models/templates.model.ts +9 -16
  158. package/src/db/tables/index.ts +0 -1
  159. package/src/db/tables/settings.table.ts +0 -8
  160. package/src/db/tables/templates.table.ts +2 -16
  161. package/src/engine/changes.ts +3 -2
  162. package/src/engine/conditions.ts +2 -4
  163. package/src/engine/fallback-html.ts +13 -13
  164. package/src/engine/formats.ts +6 -6
  165. package/src/engine/paths.ts +4 -3
  166. package/src/engine/system-variables.ts +4 -3
  167. package/src/engine/tokens.ts +1 -2
  168. package/src/hooks/index.ts +0 -1
  169. package/src/implementations/dms-mailing/index.ts +5 -18
  170. package/src/index.ts +1 -6
  171. package/src/pages/sends.ts +5 -3
  172. package/src/pages/settings/form.ts +16 -0
  173. package/src/pages/templates.ts +1 -1
  174. package/src/pages/toolbar.ts +4 -2
  175. package/src/routes/events.ts +3 -6
  176. package/src/routes/metrics.ts +7 -5
  177. package/src/routes/sends.ts +10 -18
  178. package/src/routes/settings.ts +8 -9
  179. package/src/routes/suppressions.ts +1 -1
  180. package/src/routes/templates.ts +16 -18
  181. package/src/services/attention.ts +4 -3
  182. package/src/services/categories.ts +6 -6
  183. package/src/services/checked-send.ts +17 -19
  184. package/src/services/declarations.ts +62 -318
  185. package/src/services/events.ts +16 -13
  186. package/src/services/localized-text.ts +4 -2
  187. package/src/services/metrics.ts +2 -2
  188. package/src/services/notify.ts +1 -1
  189. package/src/services/render.ts +5 -1
  190. package/src/services/send-import.ts +18 -13
  191. package/src/services/send.ts +7 -7
  192. package/src/services/settings.ts +3 -10
  193. package/src/services/starters.ts +6 -6
  194. package/src/services/template-stats.ts +11 -4
  195. package/src/services/templates.ts +69 -52
  196. package/src/types/settings.ts +20 -0
  197. package/src/validation/declarations.schema.ts +2 -2
  198. package/src/validation/guards.ts +25 -0
  199. package/src/validation/send-event-type.schema.ts +10 -0
  200. package/src/validation/settings.schema.ts +7 -2
  201. package/src/validation/templates.schema.ts +2 -1
  202. package/dist/db/models/template-slugs.model.d.ts +0 -27
  203. package/dist/db/models/template-slugs.model.js +0 -43
  204. package/dist/db/models/template-slugs.model.js.map +0 -1
  205. package/dist/db/tables/template-slugs.table.d.ts +0 -7
  206. package/dist/db/tables/template-slugs.table.js +0 -35
  207. package/dist/db/tables/template-slugs.table.js.map +0 -1
  208. package/dist/hooks/database-ready.d.ts +0 -7
  209. package/dist/hooks/database-ready.js +0 -26
  210. package/dist/hooks/database-ready.js.map +0 -1
  211. package/dist/services/fingerprint.d.ts +0 -1
  212. package/dist/services/fingerprint.js +0 -20
  213. package/dist/services/fingerprint.js.map +0 -1
  214. package/frontend-vue/tests/i18n-editor.test.ts +0 -50
  215. package/frontend-vue/tests/i18n.test.ts +0 -138
  216. package/src/db/models/template-slugs.model.ts +0 -61
  217. package/src/db/tables/template-slugs.table.ts +0 -29
  218. package/src/hooks/database-ready.ts +0 -47
  219. package/src/services/fingerprint.ts +0 -22
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import type { Block } from "../types";
2
3
  export declare const slugSchema: z.ZodString;
3
4
  export declare const createTemplateSchema: z.ZodObject<{
4
5
  slug: z.ZodString;
@@ -32,15 +33,15 @@ export declare const conditionSchema: z.ZodObject<{
32
33
  value: string;
33
34
  operator: "eq" | "ne" | "gt" | "lt" | "truthy" | "falsy";
34
35
  }>;
35
- export declare const blockSchema: z.ZodType<unknown>;
36
+ export declare const blockSchema: z.ZodType<Block, z.ZodTypeDef, unknown>;
36
37
  export declare const localeContentSchema: z.ZodObject<{
37
38
  subject: z.ZodString;
38
39
  preheader: z.ZodString;
39
- blocks: z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">;
40
+ blocks: z.ZodArray<z.ZodType<Block, z.ZodTypeDef, unknown>, "many">;
40
41
  }, "strip", z.ZodTypeAny, {
41
42
  subject: string;
42
43
  preheader: string;
43
- blocks: unknown[];
44
+ blocks: Block[];
44
45
  }, {
45
46
  subject: string;
46
47
  preheader: string;
@@ -50,11 +51,11 @@ export declare const templateContentSchema: z.ZodObject<{
50
51
  locales: z.ZodRecord<z.ZodString, z.ZodObject<{
51
52
  subject: z.ZodString;
52
53
  preheader: z.ZodString;
53
- blocks: z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">;
54
+ blocks: z.ZodArray<z.ZodType<Block, z.ZodTypeDef, unknown>, "many">;
54
55
  }, "strip", z.ZodTypeAny, {
55
56
  subject: string;
56
57
  preheader: string;
57
- blocks: unknown[];
58
+ blocks: Block[];
58
59
  }, {
59
60
  subject: string;
60
61
  preheader: string;
@@ -64,7 +65,7 @@ export declare const templateContentSchema: z.ZodObject<{
64
65
  locales: Record<string, {
65
66
  subject: string;
66
67
  preheader: string;
67
- blocks: unknown[];
68
+ blocks: Block[];
68
69
  }>;
69
70
  }, {
70
71
  locales: Record<string, {
@@ -150,11 +151,11 @@ export declare const saveContentSchema: z.ZodObject<{
150
151
  locales: z.ZodRecord<z.ZodString, z.ZodObject<{
151
152
  subject: z.ZodString;
152
153
  preheader: z.ZodString;
153
- blocks: z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">;
154
+ blocks: z.ZodArray<z.ZodType<Block, z.ZodTypeDef, unknown>, "many">;
154
155
  }, "strip", z.ZodTypeAny, {
155
156
  subject: string;
156
157
  preheader: string;
157
- blocks: unknown[];
158
+ blocks: Block[];
158
159
  }, {
159
160
  subject: string;
160
161
  preheader: string;
@@ -164,7 +165,7 @@ export declare const saveContentSchema: z.ZodObject<{
164
165
  locales: Record<string, {
165
166
  subject: string;
166
167
  preheader: string;
167
- blocks: unknown[];
168
+ blocks: Block[];
168
169
  }>;
169
170
  }, {
170
171
  locales: Record<string, {
@@ -192,7 +193,7 @@ export declare const saveContentSchema: z.ZodObject<{
192
193
  locales: Record<string, {
193
194
  subject: string;
194
195
  preheader: string;
195
- blocks: unknown[];
196
+ blocks: Block[];
196
197
  }>;
197
198
  };
198
199
  revision?: number | undefined;
@@ -231,11 +232,11 @@ export declare const previewSchema: z.ZodObject<{
231
232
  locales: z.ZodRecord<z.ZodString, z.ZodObject<{
232
233
  subject: z.ZodString;
233
234
  preheader: z.ZodString;
234
- blocks: z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">;
235
+ blocks: z.ZodArray<z.ZodType<Block, z.ZodTypeDef, unknown>, "many">;
235
236
  }, "strip", z.ZodTypeAny, {
236
237
  subject: string;
237
238
  preheader: string;
238
- blocks: unknown[];
239
+ blocks: Block[];
239
240
  }, {
240
241
  subject: string;
241
242
  preheader: string;
@@ -245,7 +246,7 @@ export declare const previewSchema: z.ZodObject<{
245
246
  locales: Record<string, {
246
247
  subject: string;
247
248
  preheader: string;
248
- blocks: unknown[];
249
+ blocks: Block[];
249
250
  }>;
250
251
  }, {
251
252
  locales: Record<string, {
@@ -261,7 +262,7 @@ export declare const previewSchema: z.ZodObject<{
261
262
  locales: Record<string, {
262
263
  subject: string;
263
264
  preheader: string;
264
- blocks: unknown[];
265
+ blocks: Block[];
265
266
  }>;
266
267
  } | undefined;
267
268
  data?: Record<string, unknown> | undefined;
@@ -298,11 +299,11 @@ export declare const testSendSchema: z.ZodObject<{
298
299
  locales: z.ZodRecord<z.ZodString, z.ZodObject<{
299
300
  subject: z.ZodString;
300
301
  preheader: z.ZodString;
301
- blocks: z.ZodArray<z.ZodType<unknown, z.ZodTypeDef, unknown>, "many">;
302
+ blocks: z.ZodArray<z.ZodType<Block, z.ZodTypeDef, unknown>, "many">;
302
303
  }, "strip", z.ZodTypeAny, {
303
304
  subject: string;
304
305
  preheader: string;
305
- blocks: unknown[];
306
+ blocks: Block[];
306
307
  }, {
307
308
  subject: string;
308
309
  preheader: string;
@@ -312,7 +313,7 @@ export declare const testSendSchema: z.ZodObject<{
312
313
  locales: Record<string, {
313
314
  subject: string;
314
315
  preheader: string;
315
- blocks: unknown[];
316
+ blocks: Block[];
316
317
  }>;
317
318
  }, {
318
319
  locales: Record<string, {
@@ -331,7 +332,7 @@ export declare const testSendSchema: z.ZodObject<{
331
332
  locales: Record<string, {
332
333
  subject: string;
333
334
  preheader: string;
334
- blocks: unknown[];
335
+ blocks: Block[];
335
336
  }>;
336
337
  } | undefined;
337
338
  data?: Record<string, unknown> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"templates.schema.js","sourceRoot":"","sources":["../../src/validation/templates.schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"templates.schema.js","sourceRoot":"","sources":["../../src/validation/templates.schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ import type { TemplateOverlays } from '../../composables/useTemplateDrawer'
3
+ import type { TemplateRow } from '../../types/mailing'
4
+
5
+ /**
6
+ * The footer of a template's drawer, its test, duplicate and edit actions:
7
+ * the drawer's own bindings, under the names it gives them.
8
+ */
9
+ interface TemplateDrawerFooterProps {
10
+ templateId: string
11
+ locale: string
12
+ template: TemplateRow
13
+ overlays: TemplateOverlays
14
+ openEditor: (targetLocale?: string) => void
15
+ }
16
+
17
+ defineProps<TemplateDrawerFooterProps>()
18
+
19
+ const { t } = useI18n()
20
+ </script>
21
+
22
+ <template>
23
+ <DmsContainerFooter data-template-footer>
24
+ <UButton
25
+ icon="i-ph-flask"
26
+ color="neutral"
27
+ variant="ghost"
28
+ :label="t('dms_mailing.templates.card.test')"
29
+ @click="overlays.openTestSend(templateId, { locale })"
30
+ />
31
+ <UButton
32
+ class="ml-auto"
33
+ icon="i-ph-copy"
34
+ color="neutral"
35
+ variant="outline"
36
+ :label="t('dms_mailing.templates.actions.duplicate')"
37
+ @click="overlays.openDuplicate(templateId, { rowData: template })"
38
+ />
39
+ <UButton
40
+ icon="i-ph-pencil-simple"
41
+ :label="t('dms_mailing.templates.actions.open_editor')"
42
+ @click="openEditor(locale)"
43
+ />
44
+ </DmsContainerFooter>
45
+ </template>
@@ -0,0 +1,102 @@
1
+ <script setup lang="ts">
2
+ import type { TemplatePerformance } from '../../types/mailing'
3
+
4
+ /** A figure of the drawer's last 30 days, as `DmsStatGroup` draws it. */
5
+ interface DrawerStat {
6
+ id: string
7
+ eyebrow: string
8
+ value: string
9
+ detail?: string
10
+ detailTone?: 'error'
11
+ to?: string
12
+ }
13
+
14
+ /**
15
+ * The performance tab of a template's drawer: the drawer's own bindings,
16
+ * under the names it gives them.
17
+ */
18
+ interface TemplateDrawerPerformanceProps {
19
+ stats: DrawerStat[]
20
+ loading: boolean
21
+ hasSends: boolean
22
+ performance: TemplatePerformance | null
23
+ openSendLog: () => void
24
+ formatNumber: (value: number) => string
25
+ }
26
+
27
+ defineProps<TemplateDrawerPerformanceProps>()
28
+
29
+ const { t } = useI18n()
30
+ </script>
31
+
32
+ <template>
33
+ <div class="flex flex-col gap-2">
34
+ <div class="flex items-center justify-between">
35
+ <DmsEyebrow :label="t('dms_mailing.templates.drawer.last_30_days')" />
36
+ <UButton
37
+ variant="link"
38
+ size="xs"
39
+ class="p-0"
40
+ :label="t('dms_mailing.templates.drawer.open_send_log')"
41
+ @click="openSendLog"
42
+ />
43
+ </div>
44
+ <DmsStatGroup
45
+ layout="joined"
46
+ :columns="3"
47
+ :items="stats"
48
+ :loading="loading"
49
+ />
50
+ </div>
51
+ <div class="flex flex-col gap-1">
52
+ <DmsEyebrow :label="t('dms_mailing.templates.drawer.called_from')" />
53
+ <p
54
+ v-if="!hasSends || !performance?.sources.length"
55
+ class="text-muted text-[12.5px]"
56
+ >
57
+ {{ t('dms_mailing.templates.drawer.no_sources') }}
58
+ </p>
59
+ <DmsListRow
60
+ v-for="source in performance?.sources ?? []"
61
+ :key="source.source"
62
+ icon="i-ph-code"
63
+ size="sm"
64
+ mono
65
+ :title="source.source || t('dms_mailing.templates.drawer.unknown_source')"
66
+ :trailing="
67
+ t(
68
+ 'dms_mailing.templates.drawer.sends_count',
69
+ { count: formatNumber(source.count) },
70
+ source.count,
71
+ )
72
+ "
73
+ />
74
+ </div>
75
+ <div class="flex flex-col gap-1">
76
+ <DmsEyebrow :label="t('dms_mailing.templates.drawer.fallbacks')" />
77
+ <p v-if="!hasSends" class="text-muted text-[12.5px]">
78
+ {{ t('dms_mailing.templates.drawer.no_sources') }}
79
+ </p>
80
+ <p
81
+ v-else-if="!performance?.fallbacks.length"
82
+ class="text-muted text-[12.5px]"
83
+ >
84
+ {{ t('dms_mailing.templates.drawer.no_fallbacks') }}
85
+ </p>
86
+ <DmsListRow
87
+ v-for="fallback in performance?.fallbacks ?? []"
88
+ :key="`${fallback.requested}-${fallback.used}`"
89
+ icon="i-ph-translate"
90
+ tone="warning"
91
+ size="sm"
92
+ :title="`${fallback.requested.toUpperCase()} → ${fallback.used.toUpperCase()}`"
93
+ :trailing="
94
+ t(
95
+ 'dms_mailing.templates.drawer.sends_count',
96
+ { count: formatNumber(fallback.count) },
97
+ fallback.count,
98
+ )
99
+ "
100
+ />
101
+ </div>
102
+ </template>
@@ -0,0 +1,110 @@
1
+ <script setup lang="ts">
2
+ import type { MergedVariable } from '../../utils/variables'
3
+ import type { SystemVariable } from '../../utils/system-variables'
4
+ import { variableTypeLabelKey } from '../../utils/variable-types'
5
+
6
+ /**
7
+ * The variables tab of a template's drawer: the drawer's own bindings, under
8
+ * the names it gives them.
9
+ */
10
+ interface TemplateDrawerVariablesProps {
11
+ variables: MergedVariable[]
12
+ isLive: boolean
13
+ hasDraftDeclarations: boolean
14
+ systemVars: SystemVariable[]
15
+ snippet: string
16
+ declareVariable: (path: string) => Promise<void>
17
+ openEditor: (targetLocale?: string) => void
18
+ }
19
+
20
+ defineProps<TemplateDrawerVariablesProps>()
21
+
22
+ const { t } = useI18n()
23
+ </script>
24
+
25
+ <template>
26
+ <div class="flex flex-col gap-1">
27
+ <DmsEyebrow :label="t('dms_mailing.templates.drawer.declared_detected')" />
28
+ <p v-if="!variables.length" class="text-muted text-[12.5px]">
29
+ {{ t('dms_mailing.templates.drawer.no_variables') }}
30
+ </p>
31
+ <div
32
+ v-for="variable in variables"
33
+ :key="variable.path"
34
+ class="border-default flex min-h-9 items-center gap-2 border-b last:border-b-0"
35
+ >
36
+ <code
37
+ class="truncate font-mono text-[12px]"
38
+ :class="variable.usage === 'unused' ? 'text-dimmed' : 'text-toned'"
39
+ >
40
+ {{ variable.path }}
41
+ </code>
42
+ <span
43
+ v-if="variable.required && variable.usage !== 'detected'"
44
+ class="text-error"
45
+ :title="t('dms_mailing.templates.drawer.required')"
46
+ >
47
+ *
48
+ </span>
49
+ <DmsStatusPill
50
+ v-if="variable.usage === 'detected'"
51
+ tone="warning"
52
+ size="sm"
53
+ dot="none"
54
+ :label="t('dms_mailing.templates.drawer.not_declared')"
55
+ />
56
+ <DmsStatusPill
57
+ v-if="variable.usage === 'unused'"
58
+ tone="neutral"
59
+ size="sm"
60
+ dot="none"
61
+ :label="t('dms_mailing.templates.drawer.unused')"
62
+ />
63
+ <UButton
64
+ v-if="variable.usage === 'detected' && !isLive"
65
+ class="ml-auto"
66
+ color="neutral"
67
+ variant="ghost"
68
+ size="xs"
69
+ :label="t('dms_mailing.templates.drawer.declare')"
70
+ @click="declareVariable(variable.path)"
71
+ />
72
+ <span
73
+ v-else-if="variable.usage !== 'detected'"
74
+ class="text-dimmed ml-auto font-mono text-[11px]"
75
+ >
76
+ {{ t(variableTypeLabelKey(variable.type)) }}
77
+ </span>
78
+ </div>
79
+ </div>
80
+ <DmsBanner
81
+ v-if="hasDraftDeclarations"
82
+ tone="info"
83
+ size="sm"
84
+ icon="i-ph-brackets-curly"
85
+ :title="t('dms_mailing.templates.drawer.draft_declarations')"
86
+ :description="
87
+ t('dms_mailing.templates.drawer.draft_declarations_description')
88
+ "
89
+ >
90
+ <template #actions>
91
+ <UButton
92
+ color="neutral"
93
+ variant="outline"
94
+ size="xs"
95
+ :label="t('dms_mailing.templates.actions.open_editor')"
96
+ @click="openEditor()"
97
+ />
98
+ </template>
99
+ </DmsBanner>
100
+ <MailingSystemVariables :variables="systemVars" />
101
+ <div class="flex flex-col gap-1.5">
102
+ <div class="flex items-center justify-between">
103
+ <DmsEyebrow :label="t('dms_mailing.templates.drawer.call_from_code')" />
104
+ <DmsCopyButton :value="snippet" />
105
+ </div>
106
+ <pre
107
+ class="bg-elevated text-toned overflow-x-auto rounded-md p-3 font-mono text-[11.5px] leading-relaxed"
108
+ >{{ snippet }}</pre>
109
+ </div>
110
+ </template>
@@ -0,0 +1,78 @@
1
+ import { computed, type ComputedRef, type Ref } from 'vue'
2
+ import type { TemplatePerformance, TemplateRow } from '../../types/mailing'
3
+ import { SENDS_PATH } from '../../utils/pages'
4
+
5
+ /**
6
+ * The figures of a template's drawer and the send log they link to: the
7
+ * drawer's script run that builds them, called where it stood.
8
+ */
9
+ export function useDrawerStats(
10
+ template: ComputedRef<TemplateRow | null>,
11
+ performance: Ref<TemplatePerformance | null>,
12
+ t: ReturnType<typeof useI18n>['t'],
13
+ uiLocale: Ref<string>,
14
+ ) {
15
+ /** The send log reads these: `?template=` narrows it, `?view=` opens a tab. */
16
+ const SENDS_TEMPLATE_KEY = 'template'
17
+ const SENDS_VIEW_KEY = 'view'
18
+ const PROBLEMS_VIEW = 'problems'
19
+ const OPEN_RATE_DIGITS = 1
20
+ const PERCENT = 100
21
+
22
+ const formatNumber = (value: number) =>
23
+ new Intl.NumberFormat(uiLocale.value, {
24
+ maximumFractionDigits: OPEN_RATE_DIGITS,
25
+ }).format(value)
26
+
27
+ /** A rate in percent, written the reader's way ("20.8%", "20,8 %"). */
28
+ const formatPercent = (value: number) =>
29
+ new Intl.NumberFormat(uiLocale.value, {
30
+ style: 'percent',
31
+ maximumFractionDigits: OPEN_RATE_DIGITS,
32
+ }).format(value / PERCENT)
33
+
34
+ /** The send log narrowed to this template, on one of its tabs if given. */
35
+ function sendLogRoute(view?: string) {
36
+ return {
37
+ path: SENDS_PATH,
38
+ query: {
39
+ [SENDS_TEMPLATE_KEY]: template.value?.slug ?? '',
40
+ ...(view ? { [SENDS_VIEW_KEY]: view } : {}),
41
+ },
42
+ }
43
+ }
44
+
45
+ function sendLogUrl(view?: string): string {
46
+ const { path, query } = sendLogRoute(view)
47
+ return `${path}?${new URLSearchParams(query).toString()}`
48
+ }
49
+
50
+ const hasSends = computed(() => Boolean(performance.value?.sends))
51
+
52
+ const stats = computed(() => [
53
+ {
54
+ id: 'sends',
55
+ eyebrow: t('dms_mailing.templates.drawer.stats_sends'),
56
+ value: formatNumber(performance.value?.sends ?? 0),
57
+ },
58
+ {
59
+ id: 'open',
60
+ eyebrow: t('dms_mailing.templates.drawer.stats_open'),
61
+ value: performance.value?.sends
62
+ ? formatPercent(performance.value.openRate)
63
+ : '—',
64
+ },
65
+ {
66
+ id: 'problems',
67
+ eyebrow: t('dms_mailing.templates.drawer.stats_problems'),
68
+ value: formatNumber(performance.value?.problems ?? 0),
69
+ detail: performance.value?.problems
70
+ ? t('dms_mailing.templates.drawer.problems_detail')
71
+ : undefined,
72
+ detailTone: 'error' as const,
73
+ to: performance.value?.problems ? sendLogUrl(PROBLEMS_VIEW) : undefined,
74
+ },
75
+ ])
76
+
77
+ return { formatNumber, sendLogRoute, hasSends, stats }
78
+ }
@@ -6,11 +6,7 @@ import {
6
6
  useTemplateContentRead,
7
7
  useTemplateListRead,
8
8
  } from '../composables/useMailingReads'
9
- import {
10
- HTTP_CONFLICT,
11
- apiErrorMessage,
12
- apiErrorStatus,
13
- } from '../utils/api-error'
9
+ import { HTTP_CONFLICT, apiErrorStatus } from '../utils/api-error'
14
10
  import {
15
11
  fitName,
16
12
  freeSlug,
@@ -31,9 +27,8 @@ const props = defineProps<DuplicateModalProps>()
31
27
  const emit = defineEmits<{ success: [created?: boolean] }>()
32
28
 
33
29
  const api = useMailingApi()
34
- const toast = useToast()
30
+ const { presentError } = useApiErrorPresenter()
35
31
  const { t } = useI18n()
36
- const { processApiMessage } = useTranslation()
37
32
 
38
33
  const templateId = computed(() => props.rowData?._id ?? props.templateId ?? '')
39
34
  const readTemplates = useTemplateListRead()
@@ -105,10 +100,7 @@ function reportFailure(error: unknown): void {
105
100
  takenSlugs.value = new Set([...takenSlugs.value, slug.value])
106
101
  return
107
102
  }
108
- toast.add({
109
- color: 'error',
110
- title: processApiMessage(apiErrorMessage(error)),
111
- })
103
+ presentError(error, { fallbackKey: 'error.500.description' })
112
104
  }
113
105
 
114
106
  async function submit(): Promise<void> {
@@ -26,6 +26,7 @@ const KEY_PREFIX = 'dms_mailing.sends.fix_address.'
26
26
  const api = useMailingApi()
27
27
  const reportReplay = useReplayToast()
28
28
  const { t } = useI18n()
29
+ const { presentError } = useApiErrorPresenter()
29
30
 
30
31
  const previous = computed(() => props.rowData?.recipientEmail ?? '')
31
32
  const address = ref(previous.value)
@@ -66,7 +67,7 @@ async function submit(): Promise<void> {
66
67
  reportReplay(result, email, key('sent', { email }))
67
68
  emit('success', true)
68
69
  } catch (error) {
69
- useApiError(error)
70
+ presentError(error, { fallbackKey: 'error.500.description' })
70
71
  } finally {
71
72
  sending.value = false
72
73
  }
@@ -9,11 +9,7 @@ import {
9
9
  useStartersRead,
10
10
  useTemplateListRead,
11
11
  } from '../composables/useMailingReads'
12
- import {
13
- HTTP_CONFLICT,
14
- apiErrorMessage,
15
- apiErrorStatus,
16
- } from '../utils/api-error'
12
+ import { HTTP_CONFLICT, apiErrorStatus } from '../utils/api-error'
17
13
  import { NO_CATEGORY, fromCategoryOption } from '../utils/categories'
18
14
  import { groupByCategory, matchesSearch } from '../utils/gallery'
19
15
  import { slugify, validateName, validateSlug } from '../utils/slug'
@@ -73,9 +69,8 @@ const props = defineProps<NewTemplateModalProps>()
73
69
  const emit = defineEmits<{ success: [created?: boolean] }>()
74
70
 
75
71
  const api = useMailingApi()
76
- const toast = useToast()
72
+ const { presentError } = useApiErrorPresenter()
77
73
  const { t } = useI18n()
78
- const { processApiMessage } = useTranslation()
79
74
 
80
75
  const name = ref(props.initialName ?? '')
81
76
  const slug = ref(slugify(name.value))
@@ -256,10 +251,7 @@ function reportFailure(error: unknown): void {
256
251
  refusedSlugs.value = new Set([...refusedSlugs.value, slug.value])
257
252
  return
258
253
  }
259
- toast.add({
260
- color: 'error',
261
- title: processApiMessage(apiErrorMessage(error)),
262
- })
254
+ presentError(error, { fallbackKey: 'error.500.description' })
263
255
  }
264
256
 
265
257
  async function submit(): Promise<void> {
@@ -7,7 +7,6 @@ import { useMailingApi } from '../composables/useMailingApi'
7
7
  import { useTemplateContentRead } from '../composables/useMailingReads'
8
8
  import type { SendResult } from '../composables/useMailingApi'
9
9
  import { useTemplateDrawer } from '../composables/useTemplateDrawer'
10
- import { apiErrorMessage } from '../utils/api-error'
11
10
  import { firstName, formatCardDate } from '../utils/gallery'
12
11
  import { localeChipClass, missingLocales } from '../utils/locales'
13
12
  import {
@@ -57,10 +56,10 @@ const emit = defineEmits<{ success: [sent?: boolean] }>()
57
56
 
58
57
  const api = useMailingApi()
59
58
  const toast = useToast()
59
+ const { presentError } = useApiErrorPresenter()
60
60
  const { t, locale: uiLocale } = useI18n()
61
61
  const onDate = (date: string): string =>
62
62
  t('dms_mailing.common.on_date', { date })
63
- const { processApiMessage } = useTranslation()
64
63
  const { uniqueLocales } = useUniqueLocales()
65
64
  const overlays = useTemplateDrawer()
66
65
 
@@ -110,10 +109,7 @@ onMounted(async () => {
110
109
  values.value = initialSendValues(fields.value, detail.value.testData)
111
110
  locale.value = detail.value.fallbackLocale
112
111
  } catch (error) {
113
- toast.add({
114
- color: 'error',
115
- title: processApiMessage(apiErrorMessage(error)),
116
- })
112
+ presentError(error, { fallbackKey: 'error.500.description' })
117
113
  } finally {
118
114
  loading.value = false
119
115
  }
@@ -296,15 +292,11 @@ function openSettings(): void {
296
292
  void navigateDms({ path: SETTINGS_PATH })
297
293
  }
298
294
 
299
- function report(results: SendResult[], to: string[]): void {
295
+ function report(results: SendResult[]): void {
300
296
  results
301
297
  .filter((result) => result.error)
302
298
  .forEach((result) =>
303
- toast.add({
304
- color: 'error',
305
- title: to[results.indexOf(result)] ?? result.sendId,
306
- description: processApiMessage(result.error),
307
- }),
299
+ presentError(result.error, { fallbackKey: 'error.500.description' }),
308
300
  )
309
301
  const sent = results.filter((result) => !result.error).length
310
302
  if (!sent) return
@@ -331,13 +323,10 @@ async function submit(): Promise<void> {
331
323
  locale: locale.value || undefined,
332
324
  data: sendData.value,
333
325
  })
334
- report(response.results, to)
326
+ report(response.results)
335
327
  close(true)
336
328
  } catch (error) {
337
- toast.add({
338
- color: 'error',
339
- title: processApiMessage(apiErrorMessage(error)),
340
- })
329
+ presentError(error, { fallbackKey: 'error.500.description' })
341
330
  } finally {
342
331
  sending.value = false
343
332
  }
@@ -45,6 +45,7 @@ const FRAME_WIDTHS: Record<RenderingView, string> = {
45
45
  }
46
46
 
47
47
  const { t, locale } = useI18n()
48
+ const { presentError } = useApiErrorPresenter()
48
49
 
49
50
  const view = ref<RenderingView>('desktop')
50
51
  const rendering = ref<SendRendering | null>(null)
@@ -99,7 +100,7 @@ async function load(): Promise<void> {
99
100
  rendering.value = html
100
101
  } catch (error) {
101
102
  failed.value = true
102
- useApiError(error)
103
+ presentError(error, { fallbackKey: `${KEY_PREFIX}error_description` })
103
104
  } finally {
104
105
  loading.value = false
105
106
  }