@dev.smartpricing/message-composer-layer 1.0.1

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 (169) hide show
  1. package/README.md +75 -0
  2. package/app/api/ai.ts +28 -0
  3. package/app/api/brands.ts +54 -0
  4. package/app/api/client.ts +56 -0
  5. package/app/api/compilation.ts +34 -0
  6. package/app/api/dynamicValues.ts +11 -0
  7. package/app/api/index.ts +11 -0
  8. package/app/api/languages.ts +6 -0
  9. package/app/api/media.ts +26 -0
  10. package/app/api/messageGroups.ts +49 -0
  11. package/app/api/messages.ts +22 -0
  12. package/app/api/meta.ts +18 -0
  13. package/app/api/tracking.ts +9 -0
  14. package/app/components/Brand/BrandDrawer.vue +281 -0
  15. package/app/components/Brand/BrandPreview.vue +137 -0
  16. package/app/components/Brand/Steps/BrandStepGeneral.vue +37 -0
  17. package/app/components/Brand/Steps/BrandStepSocials.vue +48 -0
  18. package/app/components/Brand/Steps/BrandStepVisual.vue +214 -0
  19. package/app/components/Common/BrandColorSwatches.vue +37 -0
  20. package/app/components/Common/ColorInput.vue +144 -0
  21. package/app/components/Common/EmojiPickerButton.vue +35 -0
  22. package/app/components/Common/FontFamilySelect.vue +39 -0
  23. package/app/components/Common/HtmlPreviewIframe.vue +68 -0
  24. package/app/components/Common/IncompleteTranslationsDialog.vue +97 -0
  25. package/app/components/Common/LanguageList.vue +356 -0
  26. package/app/components/Common/LoadingOverlay.vue +12 -0
  27. package/app/components/Common/MediaUploadOrSelect.vue +299 -0
  28. package/app/components/Common/MessagePreviewSlideover.vue +88 -0
  29. package/app/components/Common/MonacoEditor.vue +110 -0
  30. package/app/components/Common/PhoneInput.vue +804 -0
  31. package/app/components/Common/SectionHeader.vue +26 -0
  32. package/app/components/Common/TranslationActionBar.vue +139 -0
  33. package/app/components/Common/ViewLessMore.vue +40 -0
  34. package/app/components/CreateTemplateButton.vue +59 -0
  35. package/app/components/DynamicDataButton.vue +75 -0
  36. package/app/components/DynamicDataSlideover.vue +149 -0
  37. package/app/components/Editor/AiGenerateSlideover.vue +292 -0
  38. package/app/components/Editor/EditorLinkPopover.vue +154 -0
  39. package/app/components/Editor/RichTextEditor.vue +495 -0
  40. package/app/components/Email/Editor/BlockLibrary.vue +89 -0
  41. package/app/components/Email/Editor/BlockSettings.vue +60 -0
  42. package/app/components/Email/Editor/Blocks/ButtonBlock.vue +117 -0
  43. package/app/components/Email/Editor/Blocks/ButtonSettings.vue +228 -0
  44. package/app/components/Email/Editor/Blocks/DiscountCodeBlock.vue +74 -0
  45. package/app/components/Email/Editor/Blocks/DiscountCodeSettings.vue +162 -0
  46. package/app/components/Email/Editor/Blocks/DividerBlock.vue +31 -0
  47. package/app/components/Email/Editor/Blocks/DividerSettings.vue +108 -0
  48. package/app/components/Email/Editor/Blocks/FooterBlock.vue +61 -0
  49. package/app/components/Email/Editor/Blocks/FooterSettings.vue +123 -0
  50. package/app/components/Email/Editor/Blocks/GridBlock.vue +128 -0
  51. package/app/components/Email/Editor/Blocks/GridSettings.vue +109 -0
  52. package/app/components/Email/Editor/Blocks/HTMLBlock.vue +31 -0
  53. package/app/components/Email/Editor/Blocks/HTMLSettings.vue +85 -0
  54. package/app/components/Email/Editor/Blocks/HeaderBlock.vue +53 -0
  55. package/app/components/Email/Editor/Blocks/HeaderSettings.vue +113 -0
  56. package/app/components/Email/Editor/Blocks/HeadingBlock.vue +61 -0
  57. package/app/components/Email/Editor/Blocks/HeadingSettings.vue +156 -0
  58. package/app/components/Email/Editor/Blocks/ImageBlock.vue +49 -0
  59. package/app/components/Email/Editor/Blocks/ImageSettings.vue +53 -0
  60. package/app/components/Email/Editor/Blocks/IndexBlock.vue +155 -0
  61. package/app/components/Email/Editor/Blocks/ParagraphBlock.vue +61 -0
  62. package/app/components/Email/Editor/Blocks/ParagraphSettings.vue +157 -0
  63. package/app/components/Email/Editor/Blocks/SocialsBlock.vue +63 -0
  64. package/app/components/Email/Editor/Blocks/SocialsSettings.vue +117 -0
  65. package/app/components/Email/Editor/Blocks/SpacerBlock.vue +37 -0
  66. package/app/components/Email/Editor/Blocks/SpacerSettings.vue +95 -0
  67. package/app/components/Email/Editor/Blocks/TopProductsBlock.vue +47 -0
  68. package/app/components/Email/Editor/Blocks/TopProductsSettings.vue +87 -0
  69. package/app/components/Email/Editor/Blocks/UnsubscribeLinkBlock.vue +61 -0
  70. package/app/components/Email/Editor/Blocks/UnsubscribeLinkSettings.vue +123 -0
  71. package/app/components/Email/Editor/Canvas.vue +143 -0
  72. package/app/components/Email/Editor/GeneralStyleSettings.vue +125 -0
  73. package/app/components/Email/Editor/Index.vue +77 -0
  74. package/app/components/Email/Editor/LeftSidebar.vue +95 -0
  75. package/app/components/Email/InlinePreview.vue +124 -0
  76. package/app/components/Email/Preview.vue +126 -0
  77. package/app/components/Email/PreviewPanel.vue +57 -0
  78. package/app/components/Email/SendTestEmailModal.vue +121 -0
  79. package/app/components/Email/TranslationEditor.vue +198 -0
  80. package/app/components/Email/Translator/Button.vue +101 -0
  81. package/app/components/Email/Translator/Discount.vue +60 -0
  82. package/app/components/Email/Translator/Footer.vue +66 -0
  83. package/app/components/Email/Translator/Grid.vue +127 -0
  84. package/app/components/Email/Translator/Header.vue +90 -0
  85. package/app/components/Email/Translator/Heading.vue +66 -0
  86. package/app/components/Email/Translator/Image.vue +91 -0
  87. package/app/components/Email/Translator/Index.vue +138 -0
  88. package/app/components/Email/Translator/Paragraph.vue +66 -0
  89. package/app/components/Email/Translator/RawHtml.vue +64 -0
  90. package/app/components/Email/Translator/UnsubscribeLink.vue +59 -0
  91. package/app/components/TemplateList/BaseTable.vue +354 -0
  92. package/app/components/TemplateList/StatusCell.vue +67 -0
  93. package/app/components/Whatsapp/CategoryChanger.vue +63 -0
  94. package/app/components/Whatsapp/Editor/Body.vue +53 -0
  95. package/app/components/Whatsapp/Editor/Buttons.vue +341 -0
  96. package/app/components/Whatsapp/Editor/Footer.vue +70 -0
  97. package/app/components/Whatsapp/Editor/Header.vue +156 -0
  98. package/app/components/Whatsapp/Editor/Index.vue +89 -0
  99. package/app/components/Whatsapp/Editor/SyncWrapper.vue +166 -0
  100. package/app/components/Whatsapp/Preview.vue +197 -0
  101. package/app/components/Whatsapp/PreviewPanel.vue +24 -0
  102. package/app/components/Whatsapp/TranslationEditor.vue +150 -0
  103. package/app/components/Whatsapp/Translator/Body.vue +61 -0
  104. package/app/components/Whatsapp/Translator/Button.vue +209 -0
  105. package/app/components/Whatsapp/Translator/Footer.vue +56 -0
  106. package/app/components/Whatsapp/Translator/Header.vue +61 -0
  107. package/app/components/Whatsapp/Translator/HeaderMedia.vue +117 -0
  108. package/app/components/Whatsapp/Translator/Index.vue +159 -0
  109. package/app/composables/composerContext.ts +35 -0
  110. package/app/composables/useAutoTranslate.ts +242 -0
  111. package/app/composables/useAutoTranslateEmail.ts +294 -0
  112. package/app/composables/useChangeTracking.ts +212 -0
  113. package/app/composables/useChangeTrackingEmail.ts +227 -0
  114. package/app/composables/useChannels.ts +36 -0
  115. package/app/composables/useEmailBlockContext.ts +43 -0
  116. package/app/composables/useExitConfirmation.ts +39 -0
  117. package/app/composables/useGoBack.ts +15 -0
  118. package/app/composables/useIncompleteTranslations.ts +55 -0
  119. package/app/composables/useIncompleteTranslationsEmail.ts +56 -0
  120. package/app/composables/useMediaLimits.ts +42 -0
  121. package/app/composables/useTemplateFormValidation.ts +109 -0
  122. package/app/composables/useTemplateOperations.ts +147 -0
  123. package/app/composables/useTracking.ts +39 -0
  124. package/app/composables/useTranslationFilters.ts +176 -0
  125. package/app/composables/useTranslationFiltersEmail.ts +244 -0
  126. package/app/composables/useWhatsappTemplateBehaviors.ts +58 -0
  127. package/app/middleware/channel-guard.ts +13 -0
  128. package/app/pages/brands.vue +195 -0
  129. package/app/pages/images.vue +141 -0
  130. package/app/pages/index.vue +198 -0
  131. package/app/pages/preview/[id].vue +47 -0
  132. package/app/pages/template/email/[id].vue +596 -0
  133. package/app/pages/template/email/create.vue +562 -0
  134. package/app/pages/template/whatsapp/[id].vue +561 -0
  135. package/app/pages/template/whatsapp/create.vue +468 -0
  136. package/app/plugins/admin-shortcut.client.ts +7 -0
  137. package/app/plugins/tracking.client.ts +12 -0
  138. package/app/queries/ai.ts +20 -0
  139. package/app/queries/brands.ts +75 -0
  140. package/app/queries/compilation.ts +37 -0
  141. package/app/queries/dynamicValues.ts +13 -0
  142. package/app/queries/index.ts +9 -0
  143. package/app/queries/languages.ts +10 -0
  144. package/app/queries/media.ts +27 -0
  145. package/app/queries/messageGroups.ts +112 -0
  146. package/app/queries/messages.ts +42 -0
  147. package/app/queries/meta.ts +13 -0
  148. package/app/stores/adminStore.ts +50 -0
  149. package/app/stores/appContext.ts +99 -0
  150. package/app/stores/emailEditor.ts +220 -0
  151. package/app/stores/main.ts +3 -0
  152. package/app/stores/metaSubmission.ts +116 -0
  153. package/app/types/app-config.d.ts +14 -0
  154. package/app/types/hooks.d.ts +9 -0
  155. package/app/types/tracking.ts +148 -0
  156. package/app/utils/locale.ts +17 -0
  157. package/app/utils/notifyParent.ts +7 -0
  158. package/app/utils/resolveDefaultLanguage.ts +14 -0
  159. package/app/utils/socialDefaults.ts +42 -0
  160. package/app/utils/testIds.const.ts +728 -0
  161. package/app.config.ts +5 -0
  162. package/i18n/check-translations.ts +56 -0
  163. package/i18n/locales/de.ts +834 -0
  164. package/i18n/locales/en.ts +826 -0
  165. package/i18n/locales/es.ts +833 -0
  166. package/i18n/locales/fr.ts +837 -0
  167. package/i18n/locales/it.ts +831 -0
  168. package/nuxt.config.ts +65 -0
  169. package/package.json +64 -0
@@ -0,0 +1,148 @@
1
+ export type MessagesKind = 'email' | 'whatsapp'
2
+
3
+ export interface MessageActionProperties {
4
+ message_name: string
5
+ languages: string[]
6
+ message_id: string
7
+ message_kind: MessagesKind
8
+ message_category: string
9
+ }
10
+
11
+ // ── WhatsApp shared property interfaces ──
12
+
13
+ export type WaHeaderType = 'none' | 'text' | 'video' | 'image' | 'document'
14
+
15
+ export interface WaBaseProperties {
16
+ name: string
17
+ category: string
18
+ }
19
+
20
+ export interface WaDraftProperties extends WaBaseProperties {
21
+ languages: string[]
22
+ header: WaHeaderType
23
+ footer: boolean
24
+ buttons: number
25
+ is_internal: boolean
26
+ }
27
+
28
+ export interface WaLanguageProperties extends WaBaseProperties {
29
+ language: string
30
+ }
31
+
32
+ export interface WaTranslationsFiltersProperties extends WaLanguageProperties {
33
+ search_term: string
34
+ show_only_missing: boolean
35
+ show_only_changes: boolean
36
+ }
37
+
38
+ // ── Email shared property interfaces ──
39
+
40
+ export interface EmailBaseProperties {
41
+ name: string
42
+ subject: string
43
+ }
44
+
45
+ export interface EmailDraftProperties extends EmailBaseProperties {
46
+ languages: string[]
47
+ widgets: string[]
48
+ is_internal: boolean
49
+ }
50
+
51
+ export interface EmailLanguageProperties extends EmailBaseProperties {
52
+ language: string
53
+ }
54
+
55
+ export interface EmailTranslationsFiltersProperties extends EmailLanguageProperties {
56
+ search_term: string
57
+ show_only_missing: boolean
58
+ show_only_changes: boolean
59
+ }
60
+
61
+ // ── Event map ──
62
+
63
+ export interface TrackingEventMap {
64
+ // === Global ===
65
+ 'Page View': { page_name: string }
66
+
67
+ // === Table_List ===
68
+ change_filters: {
69
+ search_term: string
70
+ category: string
71
+ status: string
72
+ messages_kind: MessagesKind
73
+ }
74
+ change_tab: { messages_kind: MessagesKind }
75
+ message_create: { message_kind: MessagesKind }
76
+ message_delete: MessageActionProperties
77
+ message_duplicate: MessageActionProperties
78
+ message_edit: MessageActionProperties
79
+ table_sorting: { messages_kind: MessagesKind; sort_column: string }
80
+
81
+ // === Whatsapp_create ===
82
+ 'wa_create.save_draft': WaDraftProperties
83
+ 'wa_create.request_approval': WaDraftProperties
84
+ 'wa_create.add_language': WaLanguageProperties
85
+ 'wa_create.remove_language': WaLanguageProperties
86
+ 'wa_create.auto_translate': WaLanguageProperties
87
+ 'wa_create.preview': WaLanguageProperties
88
+ 'wa_create.translations_filters': WaTranslationsFiltersProperties
89
+ 'wa_create.change_tab': WaBaseProperties & { tab: string }
90
+
91
+ // === Whatsapp_edit ===
92
+ 'wa_edit.save_as_new': WaDraftProperties
93
+ 'wa_edit.request_approval': WaDraftProperties
94
+ 'wa_edit.add_language': WaLanguageProperties
95
+ 'wa_edit.remove_language': WaLanguageProperties
96
+ 'wa_edit.auto_translate': WaLanguageProperties
97
+ 'wa_edit.preview': WaLanguageProperties
98
+ 'wa_edit.translations_filters': WaTranslationsFiltersProperties
99
+ 'wa_edit.change_tab': WaBaseProperties & { tab: string }
100
+
101
+ // === Email_create ===
102
+ 'email_create.save_draft': EmailDraftProperties
103
+ 'email_create.save': EmailDraftProperties
104
+ 'email_create.add_language': EmailLanguageProperties
105
+ 'email_create.remove_language': EmailLanguageProperties
106
+ 'email_create.auto_translate': EmailLanguageProperties
107
+ 'email_create.preview': EmailLanguageProperties
108
+ 'email_create.translations_filters': EmailTranslationsFiltersProperties
109
+ 'email_create.change_tab': EmailBaseProperties & { tab: string }
110
+ 'email_create.add_widget': EmailBaseProperties & { widget_type: string; adding_mode: string }
111
+ 'email_create.remove_widget': EmailBaseProperties & { widget_type: string }
112
+ 'email_create.sort_widget': EmailBaseProperties & {
113
+ widget_type: string
114
+ before_sort_position: number
115
+ new_position: number
116
+ }
117
+ 'email_create.duplicate_widget': EmailBaseProperties & { widget_type: string }
118
+ 'email_create.change_widget_tab': EmailBaseProperties & { tab: string }
119
+ 'email_create.send_test': EmailBaseProperties & {
120
+ widgets: string[]
121
+ to_recipients: number
122
+ language: string
123
+ }
124
+
125
+ // === Email_edit ===
126
+ 'email_edit.save_draft': EmailDraftProperties
127
+ 'email_edit.save': EmailDraftProperties
128
+ 'email_edit.add_language': EmailLanguageProperties
129
+ 'email_edit.remove_language': EmailLanguageProperties
130
+ 'email_edit.auto_translate': EmailLanguageProperties
131
+ 'email_edit.preview': EmailLanguageProperties
132
+ 'email_edit.translations_filters': EmailTranslationsFiltersProperties
133
+ 'email_edit.change_tab': EmailBaseProperties & { tab: string }
134
+ 'email_edit.add_widget': EmailBaseProperties & { widget_type: string; adding_mode: string }
135
+ 'email_edit.remove_widget': EmailBaseProperties & { widget_type: string }
136
+ 'email_edit.sort_widget': EmailBaseProperties & {
137
+ widget_type: string
138
+ before_sort_position: number
139
+ new_position: number
140
+ }
141
+ 'email_edit.duplicate_widget': EmailBaseProperties & { widget_type: string }
142
+ 'email_edit.change_widget_tab': EmailBaseProperties & { tab: string }
143
+ 'email_edit.send_test': EmailBaseProperties & {
144
+ widgets: string[]
145
+ to_recipients: number
146
+ language: string
147
+ }
148
+ }
@@ -0,0 +1,17 @@
1
+ import { managedLocales, type ManagedLocales } from '@dev.smartpricing/message-composer-utils/types'
2
+
3
+ export function isLocaleManaged(locale: string): locale is ManagedLocales {
4
+ return managedLocales.includes(locale as ManagedLocales)
5
+ }
6
+
7
+ export async function extractFromLocale(key: string, locale: string): Promise<string> {
8
+ const nuxtApp = useNuxtApp()
9
+ const { t, loadLocaleMessages } = nuxtApp.$i18n
10
+ let _locale: ManagedLocales = 'en'
11
+ if (isLocaleManaged(locale)) {
12
+ _locale = locale
13
+ }
14
+
15
+ await loadLocaleMessages(_locale)
16
+ return t(key, 1, { locale: _locale })
17
+ }
@@ -0,0 +1,7 @@
1
+ import { toRaw } from 'vue'
2
+ import { deepClone } from '@dev.smartpricing/message-composer-utils/utils'
3
+ import type { ParentNotificationType } from '@dev.smartpricing/message-composer-utils/types'
4
+
5
+ export function notifyParent(type: ParentNotificationType, data?: Record<string, unknown>) {
6
+ window.parent.postMessage({ type, data: data ? deepClone(toRaw(data)) : undefined }, '*')
7
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Resolves the default language to display from a messages record.
3
+ * Fallback chain: mainLanguage → 'en' → first available key → undefined
4
+ */
5
+ export function resolveDefaultLanguage(
6
+ messages: Record<string, unknown>,
7
+ mainLanguage: string,
8
+ ): string | undefined {
9
+ if (messages[mainLanguage]) return mainLanguage
10
+ if (messages['en']) return 'en'
11
+
12
+ const keys = Object.keys(messages)
13
+ return keys.length > 0 ? keys[0] : undefined
14
+ }
@@ -0,0 +1,42 @@
1
+ import type {
2
+ BrandSocials,
3
+ SocialLink,
4
+ SocialPlatform,
5
+ } from '@dev.smartpricing/message-composer-utils/types'
6
+ import { SOCIAL_PLATFORMS } from '@dev.smartpricing/message-composer-utils/types'
7
+
8
+ /**
9
+ * Builds block-level socials from brand defaults:
10
+ * - Platforms with a brand URL → enabled, empty url (cascades from brand)
11
+ * - Platforms without → disabled, empty url
12
+ */
13
+ export function applySocialDefaults(
14
+ brandSocials: BrandSocials | null,
15
+ ): Record<SocialPlatform, SocialLink> {
16
+ const result = {} as Record<SocialPlatform, SocialLink>
17
+ for (const platform of SOCIAL_PLATFORMS) {
18
+ const hasBrandUrl = !!brandSocials?.[platform]
19
+ result[platform] = { enabled: hasBrandUrl, url: '' }
20
+ }
21
+ return result
22
+ }
23
+
24
+ /**
25
+ * Normalizes brand socials from DB, handling old {enabled, url} format
26
+ * and converting to new string-only format.
27
+ */
28
+ export function normalizeBrandSocials(
29
+ raw: Record<string, unknown> | null | undefined,
30
+ ): BrandSocials | null {
31
+ if (!raw) return null
32
+ const result: BrandSocials = {}
33
+ for (const [key, value] of Object.entries(raw)) {
34
+ if (typeof value === 'string' && value) {
35
+ result[key as SocialPlatform] = value
36
+ } else if (value && typeof value === 'object' && 'url' in value) {
37
+ const url = (value as { url: string }).url
38
+ if (url) result[key as SocialPlatform] = url
39
+ }
40
+ }
41
+ return Object.keys(result).length > 0 ? result : null
42
+ }