@dev.smartpricing/message-composer-layer 4.2.10 → 4.2.11-ux.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.
- package/app/api/meta.ts +9 -0
- package/app/components/Brand/BrandDrawer.vue +1 -0
- package/app/components/Brand/Steps/BrandStepVisual.vue +6 -1
- package/app/components/Common/LanguageList.vue +55 -1
- package/app/components/Common/MessageGroupSelect.vue +69 -9
- package/app/components/Composer/WhatsappComposer.vue +32 -1
- package/app/components/Composer/WhatsappTranslations.vue +2 -0
- package/app/components/Editor/RichTextEditor.vue +9 -4
- package/app/components/Email/Editor/Blocks/FooterBlock.vue +2 -0
- package/app/components/Email/Editor/Blocks/FooterSettings.vue +34 -0
- package/app/components/Email/Editor/Blocks/HeadingBlock.vue +2 -0
- package/app/components/Email/Editor/Blocks/HeadingSettings.vue +34 -0
- package/app/components/Email/Editor/Blocks/ParagraphBlock.vue +2 -0
- package/app/components/Email/Editor/Blocks/ParagraphSettings.vue +34 -0
- package/app/components/Email/Editor/Blocks/UnsubscribeLinkBlock.vue +2 -0
- package/app/components/Email/Editor/Blocks/UnsubscribeLinkSettings.vue +33 -0
- package/app/stores/metaSubmission.ts +26 -0
- package/app/types/tracking.ts +1 -0
- package/app/utils/testIds.const.ts +14 -2
- package/i18n/locales/de.ts +17 -0
- package/i18n/locales/en.ts +16 -0
- package/i18n/locales/es.ts +16 -0
- package/i18n/locales/fr.ts +16 -0
- package/i18n/locales/it.ts +16 -0
- package/package.json +2 -2
package/app/api/meta.ts
CHANGED
|
@@ -11,6 +11,15 @@ export const metaApi = {
|
|
|
11
11
|
body: {},
|
|
12
12
|
}),
|
|
13
13
|
|
|
14
|
+
submitMessage: (messageId: string) =>
|
|
15
|
+
apiClient<{ success: boolean; templateId?: string }>(
|
|
16
|
+
`/integrations/meta/submit-message/${messageId}`,
|
|
17
|
+
{
|
|
18
|
+
method: 'POST',
|
|
19
|
+
body: {},
|
|
20
|
+
},
|
|
21
|
+
),
|
|
22
|
+
|
|
14
23
|
getJobStatus: (jobId: string) =>
|
|
15
24
|
apiClient<SubmissionJob>(`/integrations/meta/submission-jobs/${jobId}`, {
|
|
16
25
|
method: 'GET',
|
|
@@ -169,7 +169,7 @@ function removeColor(index: number) {
|
|
|
169
169
|
<!-- Default email colors -->
|
|
170
170
|
<div class="space-y-2">
|
|
171
171
|
<p class="text-sm font-medium">{{ $t('pages.brands.fields.default_email_colors') }}</p>
|
|
172
|
-
<div class="grid grid-cols-1 sm:grid-cols-
|
|
172
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
173
173
|
<ColorInput
|
|
174
174
|
:brand-colors="colors"
|
|
175
175
|
v-model="defaultEmailSettings.backgroundColor"
|
|
@@ -185,6 +185,11 @@ function removeColor(index: number) {
|
|
|
185
185
|
v-model="defaultEmailSettings.textColor"
|
|
186
186
|
:label="$t('pages.brands.fields.email_text_color')"
|
|
187
187
|
/>
|
|
188
|
+
<ColorInput
|
|
189
|
+
:brand-colors="colors"
|
|
190
|
+
v-model="defaultEmailSettings.linkColor"
|
|
191
|
+
:label="$t('pages.brands.fields.email_link_color')"
|
|
192
|
+
/>
|
|
188
193
|
</div>
|
|
189
194
|
</div>
|
|
190
195
|
|
|
@@ -57,6 +57,14 @@
|
|
|
57
57
|
name="ph:check-circle-fill"
|
|
58
58
|
class="text-success-500 w-4 h-4"
|
|
59
59
|
/>
|
|
60
|
+
<UBadge
|
|
61
|
+
v-if="getMessageStatus(lang.id)"
|
|
62
|
+
:color="statusColor(getMessageStatus(lang.id)!)"
|
|
63
|
+
variant="subtle"
|
|
64
|
+
size="sm"
|
|
65
|
+
>
|
|
66
|
+
{{ t(`status.${getMessageStatus(lang.id)}`) }}
|
|
67
|
+
</UBadge>
|
|
60
68
|
</div>
|
|
61
69
|
</div>
|
|
62
70
|
<div class="flex items-center gap-2">
|
|
@@ -71,6 +79,16 @@
|
|
|
71
79
|
}}
|
|
72
80
|
</span>
|
|
73
81
|
</div>
|
|
82
|
+
<UButton
|
|
83
|
+
v-if="canRequestReview(lang.id)"
|
|
84
|
+
size="sm"
|
|
85
|
+
@click.stop="emit('requestReview', lang.id)"
|
|
86
|
+
color="primary"
|
|
87
|
+
variant="ghost"
|
|
88
|
+
icon="ph:paper-plane-tilt"
|
|
89
|
+
:title="t('language_list.request_review')"
|
|
90
|
+
:data-testid="`${languageListTestIds.requestReviewButton}-${lang.id}`"
|
|
91
|
+
/>
|
|
74
92
|
<UButton
|
|
75
93
|
size="sm"
|
|
76
94
|
:disabled="grouped.used.length <= 1 || lang.id === 'en' || lang.id === mainLanguageId"
|
|
@@ -134,7 +152,12 @@ const availableLanguages = computed(() => {
|
|
|
134
152
|
if (!languages.value) return { recommended: [], others: [] }
|
|
135
153
|
|
|
136
154
|
const used = Object.keys(messages.value)
|
|
137
|
-
|
|
155
|
+
let unused = languages.value.filter((lang) => !used.includes(lang.id))
|
|
156
|
+
|
|
157
|
+
// WhatsApp templates only support Meta-mapped languages; hide the rest
|
|
158
|
+
if (props.renderType === 'whatsapp_v1') {
|
|
159
|
+
unused = unused.filter((lang) => lang.meta_language_code != null)
|
|
160
|
+
}
|
|
138
161
|
|
|
139
162
|
const recommended = unused.filter((lang) => appContext.languages.includes(lang.id))
|
|
140
163
|
const others = unused.filter((lang) => !appContext.languages.includes(lang.id))
|
|
@@ -225,8 +248,39 @@ const language = defineModel<string>('language', {
|
|
|
225
248
|
const emit = defineEmits<{
|
|
226
249
|
addLanguage: [languageId: string]
|
|
227
250
|
removeLanguage: [languageId: string]
|
|
251
|
+
requestReview: [languageId: string]
|
|
228
252
|
}>()
|
|
229
253
|
|
|
254
|
+
// ── Per-message Meta review status (WhatsApp only) ────────────────
|
|
255
|
+
// Only surfaced for persisted (saved) WhatsApp messages — unsaved drafts in
|
|
256
|
+
// create mode / newly added languages have no Meta status to show yet.
|
|
257
|
+
function getMessageStatus(languageId: string): string | undefined {
|
|
258
|
+
const message = messages.value[languageId]
|
|
259
|
+
if (!message || message.render_type !== 'whatsapp_v1') return undefined
|
|
260
|
+
if (!('id' in message) || !message.id) return undefined
|
|
261
|
+
return message.status as string | undefined
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Mirrors the group rule, minus approved (approved is terminal here):
|
|
265
|
+
// a saved WhatsApp language can request review while draft or rejected.
|
|
266
|
+
function canRequestReview(languageId: string): boolean {
|
|
267
|
+
const status = getMessageStatus(languageId)
|
|
268
|
+
return status === 'draft' || status === 'rejected'
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function statusColor(status: string) {
|
|
272
|
+
switch (status) {
|
|
273
|
+
case 'approved':
|
|
274
|
+
return 'success' as const
|
|
275
|
+
case 'pending':
|
|
276
|
+
return 'warning' as const
|
|
277
|
+
case 'rejected':
|
|
278
|
+
return 'error' as const
|
|
279
|
+
default:
|
|
280
|
+
return 'neutral' as const
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
230
284
|
// Helper functions for change tracking
|
|
231
285
|
function hasLanguageChanges(languageId: string): boolean {
|
|
232
286
|
const message = messages.value[languageId]
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { RenderType } from '@dev.smartpricing/message-composer-utils/types'
|
|
2
|
+
import type { RenderType, MessageStatus } from '@dev.smartpricing/message-composer-utils/types'
|
|
3
3
|
import { useMessageGroupsQuery } from '~/queries/messageGroups'
|
|
4
4
|
|
|
5
|
-
defineOptions({ name: '
|
|
5
|
+
defineOptions({ name: 'MessageGroupSelect' })
|
|
6
6
|
|
|
7
7
|
const props = withDefaults(
|
|
8
8
|
defineProps<{
|
|
9
9
|
renderType?: RenderType
|
|
10
10
|
placeholder?: string
|
|
11
11
|
searchPlaceholder?: string
|
|
12
|
+
/**
|
|
13
|
+
* Map of message-group id -> reason text explaining why the group is not
|
|
14
|
+
* selectable (e.g. already linked to another newsletter by an external
|
|
15
|
+
* system). Presence of a key disables the group; the value is shown verbatim
|
|
16
|
+
* as the tooltip, so it must already be localized by the caller.
|
|
17
|
+
*
|
|
18
|
+
* NOTE: the caller is responsible for excluding the currently-selected group
|
|
19
|
+
* when editing, otherwise the current selection will render as disabled.
|
|
20
|
+
*/
|
|
21
|
+
disabledGroupReasons?: Record<string, string>
|
|
22
|
+
/** Overrides the "hide inactive" filter label. Defaults to the built-in translation. */
|
|
23
|
+
hideFilterLabel?: string
|
|
12
24
|
}>(),
|
|
13
25
|
{
|
|
14
|
-
placeholder: 'Select a
|
|
26
|
+
placeholder: 'Select a message group',
|
|
15
27
|
searchPlaceholder: 'Search...',
|
|
16
28
|
},
|
|
17
29
|
)
|
|
@@ -22,16 +34,48 @@ const emit = defineEmits<{
|
|
|
22
34
|
select: [item: { id: string; name: string }]
|
|
23
35
|
}>()
|
|
24
36
|
|
|
37
|
+
const { t } = useI18n()
|
|
38
|
+
|
|
25
39
|
const { data: messageGroups, isLoading } = useMessageGroupsQuery(() => ({
|
|
26
40
|
renderType: props.renderType,
|
|
27
41
|
}))
|
|
28
42
|
|
|
43
|
+
const hideInactive = ref(false)
|
|
44
|
+
|
|
45
|
+
function isGroupActive(messages: Array<{ status: MessageStatus }>): boolean {
|
|
46
|
+
return messages.length > 0 && messages.every((m) => m.status === 'approved')
|
|
47
|
+
}
|
|
48
|
+
|
|
29
49
|
const items = computed(() => {
|
|
30
50
|
if (!messageGroups.value) return []
|
|
31
|
-
return messageGroups.value.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
return messageGroups.value.reduce<
|
|
52
|
+
Array<{
|
|
53
|
+
label: string
|
|
54
|
+
value: string
|
|
55
|
+
disabled: boolean
|
|
56
|
+
tooltip?: string
|
|
57
|
+
chip: { color: 'success' | 'neutral' }
|
|
58
|
+
}>
|
|
59
|
+
>((acc, group) => {
|
|
60
|
+
const externalReason = props.disabledGroupReasons?.[group.id]
|
|
61
|
+
const externallyUsed = externalReason != null
|
|
62
|
+
const active = isGroupActive(group.messages)
|
|
63
|
+
const disabled = !active || externallyUsed
|
|
64
|
+
if (hideInactive.value && disabled) return acc
|
|
65
|
+
acc.push({
|
|
66
|
+
label: group.name,
|
|
67
|
+
value: group.id,
|
|
68
|
+
disabled,
|
|
69
|
+
// External reason wins over the inactive tooltip when both apply.
|
|
70
|
+
tooltip: externallyUsed
|
|
71
|
+
? externalReason
|
|
72
|
+
: !active
|
|
73
|
+
? t('common.messageGroupSelect.inactive_tooltip')
|
|
74
|
+
: undefined,
|
|
75
|
+
chip: { color: disabled ? 'neutral' : 'success' },
|
|
76
|
+
})
|
|
77
|
+
return acc
|
|
78
|
+
}, [])
|
|
35
79
|
})
|
|
36
80
|
|
|
37
81
|
function handleUpdate(value: string) {
|
|
@@ -50,7 +94,23 @@ function handleUpdate(value: string) {
|
|
|
50
94
|
searchable
|
|
51
95
|
:placeholder="placeholder"
|
|
52
96
|
:search-input="{ placeholder: searchPlaceholder }"
|
|
53
|
-
:data-testid="
|
|
97
|
+
:data-testid="messageGroupSelectTestIds.root"
|
|
54
98
|
@update:model-value="handleUpdate"
|
|
55
|
-
|
|
99
|
+
>
|
|
100
|
+
<template #item-label="{ item }">
|
|
101
|
+
<UTooltip v-if="item.disabled" :text="item.tooltip">
|
|
102
|
+
<span class="text-muted">{{ item.label }}</span>
|
|
103
|
+
</UTooltip>
|
|
104
|
+
<span v-else>{{ item.label }}</span>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<template #content-top>
|
|
108
|
+
<div class="flex items-center gap-2 px-2 py-1.5 border-b border-default">
|
|
109
|
+
<USwitch v-model="hideInactive" size="xs" />
|
|
110
|
+
<span class="text-xs text-muted">
|
|
111
|
+
{{ hideFilterLabel ?? t('common.messageGroupSelect.hide_inactive') }}
|
|
112
|
+
</span>
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
115
|
+
</USelectMenu>
|
|
56
116
|
</template>
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
import { useAppContextStore } from '@/stores/appContext'
|
|
10
10
|
import { useMetaSubmissionStore } from '@/stores/metaSubmission'
|
|
11
11
|
import { useMessageGroupQuery, useLanguagesQuery } from '~/queries'
|
|
12
|
+
import { messagesApi } from '~/api/messages'
|
|
12
13
|
import type { WaHeaderType } from '~/types/tracking'
|
|
13
14
|
|
|
14
15
|
const props = defineProps<{
|
|
@@ -25,7 +26,9 @@ const store = useWhatsappComposerStore()
|
|
|
25
26
|
const { mainLanguage } = storeToRefs(useAppContextStore())
|
|
26
27
|
const { trackEvent } = useTracking()
|
|
27
28
|
const { goBackOrFallback } = useGoBack()
|
|
28
|
-
const { submitToMeta } = useMetaSubmissionStore()
|
|
29
|
+
const { submitToMeta, submitMessageToMeta } = useMetaSubmissionStore()
|
|
30
|
+
const { confirm } = useConfirm()
|
|
31
|
+
const { t } = useI18n()
|
|
29
32
|
|
|
30
33
|
// ── Init ──────────────────────────────────────────────────────────
|
|
31
34
|
if (props.mode === 'create') {
|
|
@@ -260,6 +263,33 @@ async function requestApproval() {
|
|
|
260
263
|
}
|
|
261
264
|
}
|
|
262
265
|
|
|
266
|
+
// ── Per-language review request ───────────────────────────────────
|
|
267
|
+
async function onRequestReview(languageId: string) {
|
|
268
|
+
const message = store.messages[languageId] as (WhatsappMessage & { id?: string }) | undefined
|
|
269
|
+
if (!message?.id) return
|
|
270
|
+
|
|
271
|
+
const languageName = languages.value?.find((l) => l.id === languageId)?.name ?? languageId
|
|
272
|
+
|
|
273
|
+
confirm({
|
|
274
|
+
title: t('dialogs.request_review.title'),
|
|
275
|
+
message: t('dialogs.request_review.message', { language: languageName }),
|
|
276
|
+
confirmProps: { label: t('dialogs.request_review.confirm') },
|
|
277
|
+
cancelProps: { label: t('common.actions.cancel') },
|
|
278
|
+
action: async () => {
|
|
279
|
+
// Decision C: persist only this language's current edits, then submit it.
|
|
280
|
+
await messagesApi.update(message.id!, message)
|
|
281
|
+
await submitMessageToMeta(message.id!)
|
|
282
|
+
// Reflect pending locally instead of refetching the group, so unsaved
|
|
283
|
+
// edits in other languages are preserved.
|
|
284
|
+
store.messages[languageId] = { ...message, status: 'pending' }
|
|
285
|
+
track('request_review_language', {
|
|
286
|
+
...getWaBaseProps(),
|
|
287
|
+
language: languageId,
|
|
288
|
+
})
|
|
289
|
+
},
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
|
|
263
293
|
// ── Public action handlers ────────────────────────────────────────
|
|
264
294
|
async function handleSaveDraft() {
|
|
265
295
|
if (!(await validateDraft())) return
|
|
@@ -420,6 +450,7 @@ defineExpose({
|
|
|
420
450
|
:mode="mode"
|
|
421
451
|
@add-language="onAddLanguage"
|
|
422
452
|
@remove-language="onRemoveLanguage"
|
|
453
|
+
@request-review="onRequestReview"
|
|
423
454
|
@auto-translate-tracked="onAutoTranslateTracked"
|
|
424
455
|
@preview="onPreview"
|
|
425
456
|
@filters-changed="onFiltersChanged"
|
|
@@ -10,6 +10,7 @@ const props = defineProps<{
|
|
|
10
10
|
const emit = defineEmits<{
|
|
11
11
|
'add-language': [lang: string]
|
|
12
12
|
'remove-language': [lang: string]
|
|
13
|
+
'request-review': [lang: string]
|
|
13
14
|
'auto-translate-tracked': [lang: string]
|
|
14
15
|
preview: [lang: string]
|
|
15
16
|
'filters-changed': [
|
|
@@ -49,6 +50,7 @@ const testIds = computed(() =>
|
|
|
49
50
|
:main-language-id="store.language"
|
|
50
51
|
@add-language="emit('add-language', $event)"
|
|
51
52
|
@remove-language="emit('remove-language', $event)"
|
|
53
|
+
@request-review="emit('request-review', $event)"
|
|
52
54
|
/>
|
|
53
55
|
</div>
|
|
54
56
|
<div class="overflow-y-auto" v-if="store.currentMessage && store.targetMessage">
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
RefineTextResponse,
|
|
10
10
|
} from '@dev.smartpricing/message-composer-utils/types'
|
|
11
11
|
import {
|
|
12
|
+
buildLinkHTMLAttributes,
|
|
12
13
|
convertToWhatsappMarkdown,
|
|
13
14
|
getTipTapExtensions,
|
|
14
15
|
sanitizeContent,
|
|
@@ -39,6 +40,7 @@ const props = withDefaults(
|
|
|
39
40
|
horizontalRule?: boolean
|
|
40
41
|
alignment?: boolean
|
|
41
42
|
link?: boolean
|
|
43
|
+
linkColor?: string
|
|
42
44
|
emoji?: boolean
|
|
43
45
|
}>(),
|
|
44
46
|
{
|
|
@@ -134,9 +136,12 @@ const starterKitConfig = computed(() => {
|
|
|
134
136
|
link: props.link
|
|
135
137
|
? {
|
|
136
138
|
openOnClick: false,
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
// Callers that don't opt in with `linkColor` (e.g. ButtonSettings, whose
|
|
140
|
+
// links aren't part of the block-level linkColor feature) keep the old
|
|
141
|
+
// fixed styling instead of an unset `--link-color` custom property.
|
|
142
|
+
HTMLAttributes: props.linkColor
|
|
143
|
+
? { class: 'underline', ...buildLinkHTMLAttributes({ mode: 'live' }) }
|
|
144
|
+
: { class: 'text-primary-600 underline' },
|
|
140
145
|
}
|
|
141
146
|
: false,
|
|
142
147
|
heading: false,
|
|
@@ -373,7 +378,7 @@ defineExpose({
|
|
|
373
378
|
</script>
|
|
374
379
|
|
|
375
380
|
<template>
|
|
376
|
-
<div :data-testid="richTextEditorTestIds.root">
|
|
381
|
+
<div :data-testid="richTextEditorTestIds.root" :style="{ '--link-color': linkColor }">
|
|
377
382
|
<div class="rounded-md border border-accented overflow-hidden">
|
|
378
383
|
<UEditor
|
|
379
384
|
ref="editorRef"
|
|
@@ -18,6 +18,7 @@ const editor = useEditor({
|
|
|
18
18
|
extensions: getTipTapExtensions({
|
|
19
19
|
preset: 'email',
|
|
20
20
|
dynamicValues: true,
|
|
21
|
+
linkColor: { mode: 'live' },
|
|
21
22
|
}),
|
|
22
23
|
})
|
|
23
24
|
|
|
@@ -47,6 +48,7 @@ defineOptions({
|
|
|
47
48
|
fontFamily: block.settings.fontFamily ?? emailEditorStore.resolvedSettings.fontFamily,
|
|
48
49
|
fontSize: `${block.settings.fontSize}px`,
|
|
49
50
|
color: block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
51
|
+
'--link-color': block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
50
52
|
}"
|
|
51
53
|
>
|
|
52
54
|
<EditorContent :editor="editor" class="pointer-events-none" />
|
|
@@ -23,6 +23,19 @@ const content = computed({
|
|
|
23
23
|
},
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
+
const resolvedLinkColor = computed(
|
|
27
|
+
() => props.block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function matchTextColor() {
|
|
31
|
+
emailEditorStore.updateBlock(props.block.id, {
|
|
32
|
+
settings: {
|
|
33
|
+
...props.block.settings,
|
|
34
|
+
linkColor: props.block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
function resetTextStyle() {
|
|
27
40
|
emailEditorStore.updateBlock(props.block.id, {
|
|
28
41
|
settings: {
|
|
@@ -38,6 +51,7 @@ function resetColors() {
|
|
|
38
51
|
settings: {
|
|
39
52
|
...props.block.settings,
|
|
40
53
|
textColor: DEFAULT_FOOTER_SETTINGS.textColor,
|
|
54
|
+
linkColor: DEFAULT_FOOTER_SETTINGS.linkColor,
|
|
41
55
|
backgroundColor: DEFAULT_FOOTER_SETTINGS.backgroundColor,
|
|
42
56
|
},
|
|
43
57
|
})
|
|
@@ -63,6 +77,7 @@ defineOptions({
|
|
|
63
77
|
underline
|
|
64
78
|
alignment
|
|
65
79
|
link
|
|
80
|
+
:link-color="resolvedLinkColor"
|
|
66
81
|
emoji
|
|
67
82
|
dynamic-values
|
|
68
83
|
/>
|
|
@@ -113,6 +128,25 @@ defineOptions({
|
|
|
113
128
|
:default-value="emailEditorStore.resolvedSettings.textColor"
|
|
114
129
|
/>
|
|
115
130
|
|
|
131
|
+
<!-- Link Color -->
|
|
132
|
+
<ColorInput
|
|
133
|
+
v-model="block.settings.linkColor"
|
|
134
|
+
:label="$t('editor.email.blocks.heading.settings.link')"
|
|
135
|
+
:default-value="emailEditorStore.resolvedSettings.linkColor"
|
|
136
|
+
:data-testid="footerSettingsTestIds.linkColorInput"
|
|
137
|
+
>
|
|
138
|
+
<template #trailing>
|
|
139
|
+
<UButton
|
|
140
|
+
size="xs"
|
|
141
|
+
color="neutral"
|
|
142
|
+
variant="ghost"
|
|
143
|
+
:label="$t('editor.email.blocks.heading.settings.match_text_color')"
|
|
144
|
+
:data-testid="footerSettingsTestIds.matchTextColorButton"
|
|
145
|
+
@click.stop="matchTextColor"
|
|
146
|
+
/>
|
|
147
|
+
</template>
|
|
148
|
+
</ColorInput>
|
|
149
|
+
|
|
116
150
|
<!-- Background Color -->
|
|
117
151
|
<ColorInput
|
|
118
152
|
v-model="block.settings.backgroundColor"
|
|
@@ -18,6 +18,7 @@ const editor = useEditor({
|
|
|
18
18
|
extensions: getTipTapExtensions({
|
|
19
19
|
preset: 'email',
|
|
20
20
|
dynamicValues: true,
|
|
21
|
+
linkColor: { mode: 'live' },
|
|
21
22
|
}),
|
|
22
23
|
})
|
|
23
24
|
|
|
@@ -47,6 +48,7 @@ defineOptions({
|
|
|
47
48
|
fontFamily: block.settings.fontFamily ?? emailEditorStore.resolvedSettings.fontFamily,
|
|
48
49
|
fontSize: `${block.settings.fontSize}px`,
|
|
49
50
|
color: block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
51
|
+
'--link-color': block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
50
52
|
}"
|
|
51
53
|
>
|
|
52
54
|
<EditorContent :editor="editor" class="pointer-events-none" />
|
|
@@ -30,6 +30,19 @@ const content = computed({
|
|
|
30
30
|
},
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
+
const resolvedLinkColor = computed(
|
|
34
|
+
() => props.block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
function matchTextColor() {
|
|
38
|
+
emailEditorStore.updateBlock(props.block.id, {
|
|
39
|
+
settings: {
|
|
40
|
+
...props.block.settings,
|
|
41
|
+
linkColor: props.block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
const typeOptions = HEADING_TAGS.slice(0, 3).map((heading) => ({
|
|
34
47
|
value: heading,
|
|
35
48
|
label: t(`editor.email.blocks.text_types.${heading}`),
|
|
@@ -51,6 +64,7 @@ function resetColors() {
|
|
|
51
64
|
settings: {
|
|
52
65
|
...props.block.settings,
|
|
53
66
|
textColor: DEFAULT_HEADING_SETTINGS.textColor,
|
|
67
|
+
linkColor: DEFAULT_HEADING_SETTINGS.linkColor,
|
|
54
68
|
backgroundColor: DEFAULT_HEADING_SETTINGS.backgroundColor,
|
|
55
69
|
},
|
|
56
70
|
})
|
|
@@ -83,6 +97,7 @@ defineOptions({
|
|
|
83
97
|
underline
|
|
84
98
|
alignment
|
|
85
99
|
link
|
|
100
|
+
:link-color="resolvedLinkColor"
|
|
86
101
|
emoji
|
|
87
102
|
improve
|
|
88
103
|
generate
|
|
@@ -146,6 +161,25 @@ defineOptions({
|
|
|
146
161
|
:default-value="emailEditorStore.resolvedSettings.textColor"
|
|
147
162
|
/>
|
|
148
163
|
|
|
164
|
+
<!-- Link Color -->
|
|
165
|
+
<ColorInput
|
|
166
|
+
v-model="block.settings.linkColor"
|
|
167
|
+
:label="$t('editor.email.blocks.heading.settings.link')"
|
|
168
|
+
:default-value="emailEditorStore.resolvedSettings.linkColor"
|
|
169
|
+
:data-testid="headingSettingsTestIds.linkColorInput"
|
|
170
|
+
>
|
|
171
|
+
<template #trailing>
|
|
172
|
+
<UButton
|
|
173
|
+
size="xs"
|
|
174
|
+
color="neutral"
|
|
175
|
+
variant="ghost"
|
|
176
|
+
:label="$t('editor.email.blocks.heading.settings.match_text_color')"
|
|
177
|
+
:data-testid="headingSettingsTestIds.matchTextColorButton"
|
|
178
|
+
@click.stop="matchTextColor"
|
|
179
|
+
/>
|
|
180
|
+
</template>
|
|
181
|
+
</ColorInput>
|
|
182
|
+
|
|
149
183
|
<!-- Background Color -->
|
|
150
184
|
<ColorInput
|
|
151
185
|
v-model="block.settings.backgroundColor"
|
|
@@ -18,6 +18,7 @@ const editor = useEditor({
|
|
|
18
18
|
extensions: getTipTapExtensions({
|
|
19
19
|
preset: 'email',
|
|
20
20
|
dynamicValues: true,
|
|
21
|
+
linkColor: { mode: 'live' },
|
|
21
22
|
}),
|
|
22
23
|
})
|
|
23
24
|
|
|
@@ -47,6 +48,7 @@ defineOptions({
|
|
|
47
48
|
fontFamily: block.settings.fontFamily ?? emailEditorStore.resolvedSettings.fontFamily,
|
|
48
49
|
fontSize: `${block.settings.fontSize}px`,
|
|
49
50
|
color: block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
51
|
+
'--link-color': block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
50
52
|
}"
|
|
51
53
|
>
|
|
52
54
|
<EditorContent :editor="editor" class="pointer-events-none" />
|
|
@@ -30,6 +30,19 @@ const content = computed({
|
|
|
30
30
|
},
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
+
const resolvedLinkColor = computed(
|
|
34
|
+
() => props.block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
function matchTextColor() {
|
|
38
|
+
emailEditorStore.updateBlock(props.block.id, {
|
|
39
|
+
settings: {
|
|
40
|
+
...props.block.settings,
|
|
41
|
+
linkColor: props.block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
const typeOptions = TEXT_TAGS.map((tag) => ({
|
|
34
47
|
value: tag,
|
|
35
48
|
label: t(`editor.email.blocks.text_types.${tag}`),
|
|
@@ -51,6 +64,7 @@ function resetColors() {
|
|
|
51
64
|
settings: {
|
|
52
65
|
...props.block.settings,
|
|
53
66
|
textColor: DEFAULT_PARAGRAPH_SETTINGS.textColor,
|
|
67
|
+
linkColor: DEFAULT_PARAGRAPH_SETTINGS.linkColor,
|
|
54
68
|
backgroundColor: DEFAULT_PARAGRAPH_SETTINGS.backgroundColor,
|
|
55
69
|
},
|
|
56
70
|
})
|
|
@@ -85,6 +99,7 @@ defineOptions({
|
|
|
85
99
|
horizontal-rule
|
|
86
100
|
alignment
|
|
87
101
|
link
|
|
102
|
+
:link-color="resolvedLinkColor"
|
|
88
103
|
emoji
|
|
89
104
|
improve
|
|
90
105
|
generate
|
|
@@ -147,6 +162,25 @@ defineOptions({
|
|
|
147
162
|
:default-value="emailEditorStore.resolvedSettings.textColor"
|
|
148
163
|
/>
|
|
149
164
|
|
|
165
|
+
<!-- Link Color -->
|
|
166
|
+
<ColorInput
|
|
167
|
+
v-model="block.settings.linkColor"
|
|
168
|
+
:label="$t('editor.email.blocks.heading.settings.link')"
|
|
169
|
+
:default-value="emailEditorStore.resolvedSettings.linkColor"
|
|
170
|
+
:data-testid="paragraphSettingsTestIds.linkColorInput"
|
|
171
|
+
>
|
|
172
|
+
<template #trailing>
|
|
173
|
+
<UButton
|
|
174
|
+
size="xs"
|
|
175
|
+
color="neutral"
|
|
176
|
+
variant="ghost"
|
|
177
|
+
:label="$t('editor.email.blocks.heading.settings.match_text_color')"
|
|
178
|
+
:data-testid="paragraphSettingsTestIds.matchTextColorButton"
|
|
179
|
+
@click.stop="matchTextColor"
|
|
180
|
+
/>
|
|
181
|
+
</template>
|
|
182
|
+
</ColorInput>
|
|
183
|
+
|
|
150
184
|
<!-- Background Color -->
|
|
151
185
|
<ColorInput
|
|
152
186
|
v-model="block.settings.backgroundColor"
|
|
@@ -17,6 +17,7 @@ const editor = useEditor({
|
|
|
17
17
|
extensions: getTipTapExtensions({
|
|
18
18
|
preset: 'email',
|
|
19
19
|
dynamicValues: true,
|
|
20
|
+
linkColor: { mode: 'live' },
|
|
20
21
|
}),
|
|
21
22
|
})
|
|
22
23
|
|
|
@@ -45,6 +46,7 @@ defineOptions({
|
|
|
45
46
|
fontFamily: block.settings.fontFamily ?? emailEditorStore.resolvedSettings.fontFamily,
|
|
46
47
|
fontSize: `${block.settings.fontSize}px`,
|
|
47
48
|
color: block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
49
|
+
'--link-color': block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
48
50
|
textAlign: block.settings.alignment,
|
|
49
51
|
}"
|
|
50
52
|
>
|
|
@@ -24,6 +24,19 @@ const content = computed({
|
|
|
24
24
|
},
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
+
const resolvedLinkColor = computed(
|
|
28
|
+
() => props.block.settings.linkColor ?? emailEditorStore.resolvedSettings.linkColor,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
function matchTextColor() {
|
|
32
|
+
emailEditorStore.updateBlock(props.block.id, {
|
|
33
|
+
settings: {
|
|
34
|
+
...props.block.settings,
|
|
35
|
+
linkColor: props.block.settings.textColor ?? emailEditorStore.resolvedSettings.textColor,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
function resetTextStyle() {
|
|
28
41
|
emailEditorStore.updateBlock(props.block.id, {
|
|
29
42
|
settings: {
|
|
@@ -39,6 +52,7 @@ function resetColors() {
|
|
|
39
52
|
settings: {
|
|
40
53
|
...props.block.settings,
|
|
41
54
|
textColor: DEFAULT_UNSUBSCRIBE_LINK_SETTINGS.textColor,
|
|
55
|
+
linkColor: DEFAULT_UNSUBSCRIBE_LINK_SETTINGS.linkColor,
|
|
42
56
|
backgroundColor: DEFAULT_UNSUBSCRIBE_LINK_SETTINGS.backgroundColor,
|
|
43
57
|
},
|
|
44
58
|
})
|
|
@@ -63,6 +77,7 @@ defineOptions({
|
|
|
63
77
|
italic
|
|
64
78
|
underline
|
|
65
79
|
link
|
|
80
|
+
:link-color="resolvedLinkColor"
|
|
66
81
|
dynamic-values
|
|
67
82
|
:data-testid="unsubscribeLinkSettingsTestIds.contentEditor"
|
|
68
83
|
/>
|
|
@@ -113,6 +128,24 @@ defineOptions({
|
|
|
113
128
|
:data-testid="unsubscribeLinkSettingsTestIds.textColorInput"
|
|
114
129
|
/>
|
|
115
130
|
|
|
131
|
+
<ColorInput
|
|
132
|
+
v-model="block.settings.linkColor"
|
|
133
|
+
:label="$t('editor.email.blocks.heading.settings.link')"
|
|
134
|
+
:default-value="emailEditorStore.resolvedSettings.linkColor"
|
|
135
|
+
:data-testid="unsubscribeLinkSettingsTestIds.linkColorInput"
|
|
136
|
+
>
|
|
137
|
+
<template #trailing>
|
|
138
|
+
<UButton
|
|
139
|
+
size="xs"
|
|
140
|
+
color="neutral"
|
|
141
|
+
variant="ghost"
|
|
142
|
+
:label="$t('editor.email.blocks.heading.settings.match_text_color')"
|
|
143
|
+
:data-testid="unsubscribeLinkSettingsTestIds.matchTextColorButton"
|
|
144
|
+
@click.stop="matchTextColor"
|
|
145
|
+
/>
|
|
146
|
+
</template>
|
|
147
|
+
</ColorInput>
|
|
148
|
+
|
|
116
149
|
<ColorInput
|
|
117
150
|
v-model="block.settings.backgroundColor"
|
|
118
151
|
:label="$t('editor.email.blocks.heading.settings.backgroundBlock')"
|
|
@@ -35,6 +35,31 @@ export const useMetaSubmissionStore = () => {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// Submit a single message (one language) for Meta review. Synchronous:
|
|
39
|
+
// the endpoint submits inline and flips the message to `pending`, so there
|
|
40
|
+
// is no job to poll — unlike the group flow.
|
|
41
|
+
const submitMessageToMeta = async (messageId: string) => {
|
|
42
|
+
if (!isConfigured.value) {
|
|
43
|
+
throw new Error('Meta configuration not available')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await metaApi.submitMessage(messageId)
|
|
48
|
+
toast.add({
|
|
49
|
+
color: 'success',
|
|
50
|
+
title: t('meta_submission.message_success'),
|
|
51
|
+
})
|
|
52
|
+
return response
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Failed to submit message to Meta:', error)
|
|
55
|
+
toast.add({
|
|
56
|
+
color: 'error',
|
|
57
|
+
title: t('meta_submission.message_error'),
|
|
58
|
+
})
|
|
59
|
+
throw error
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
const startBackgroundPolling = (jobId: string, messageGroupId: string) => {
|
|
39
64
|
// Add job to active jobs
|
|
40
65
|
activeJobs.value.set(jobId, {
|
|
@@ -110,6 +135,7 @@ export const useMetaSubmissionStore = () => {
|
|
|
110
135
|
hasActiveJobs,
|
|
111
136
|
isConfigured,
|
|
112
137
|
submitToMeta,
|
|
138
|
+
submitMessageToMeta,
|
|
113
139
|
startBackgroundPolling,
|
|
114
140
|
stopPolling,
|
|
115
141
|
}
|
package/app/types/tracking.ts
CHANGED
|
@@ -105,6 +105,7 @@ export interface TrackingEventMap {
|
|
|
105
105
|
// === Whatsapp_edit ===
|
|
106
106
|
'wa_edit.save_as_new': WaDraftProperties
|
|
107
107
|
'wa_edit.request_approval': WaDraftProperties
|
|
108
|
+
'wa_edit.request_review_language': WaLanguageProperties
|
|
108
109
|
'wa_edit.add_language': WaLanguageProperties
|
|
109
110
|
'wa_edit.remove_language': WaLanguageProperties
|
|
110
111
|
'wa_edit.auto_translate': WaLanguageProperties
|
|
@@ -122,6 +122,7 @@ export const languageListTestIds = {
|
|
|
122
122
|
commandPalette: 'language-list-command-palette',
|
|
123
123
|
languageItem: 'language-list-item',
|
|
124
124
|
deleteButton: 'language-list-delete-button',
|
|
125
|
+
requestReviewButton: 'language-list-request-review-button',
|
|
125
126
|
} as const
|
|
126
127
|
|
|
127
128
|
export const loadingOverlayTestIds = {
|
|
@@ -614,6 +615,8 @@ export const footerSettingsTestIds = {
|
|
|
614
615
|
container: 'footer-settings-container',
|
|
615
616
|
fontSizeField: 'footer-settings-font-size-field',
|
|
616
617
|
fontSizeInput: 'footer-settings-font-size-input',
|
|
618
|
+
linkColorInput: 'footer-settings-link-color-input',
|
|
619
|
+
matchTextColorButton: 'footer-settings-match-text-color-button',
|
|
617
620
|
} as const
|
|
618
621
|
|
|
619
622
|
export const gridBlockTestIds = {
|
|
@@ -652,6 +655,8 @@ export const headingSettingsTestIds = {
|
|
|
652
655
|
tagSelect: 'heading-settings-tag-select',
|
|
653
656
|
fontSizeField: 'heading-settings-font-size-field',
|
|
654
657
|
fontSizeInput: 'heading-settings-font-size-input',
|
|
658
|
+
linkColorInput: 'heading-settings-link-color-input',
|
|
659
|
+
matchTextColorButton: 'heading-settings-match-text-color-button',
|
|
655
660
|
} as const
|
|
656
661
|
|
|
657
662
|
export const htmlBlockTestIds = {
|
|
@@ -690,6 +695,8 @@ export const paragraphSettingsTestIds = {
|
|
|
690
695
|
tagSelect: 'paragraph-settings-tag-select',
|
|
691
696
|
fontSizeField: 'paragraph-settings-font-size-field',
|
|
692
697
|
fontSizeInput: 'paragraph-settings-font-size-input',
|
|
698
|
+
linkColorInput: 'paragraph-settings-link-color-input',
|
|
699
|
+
matchTextColorButton: 'paragraph-settings-match-text-color-button',
|
|
693
700
|
} as const
|
|
694
701
|
|
|
695
702
|
export const socialsBlockTestIds = {
|
|
@@ -731,6 +738,8 @@ export const unsubscribeLinkSettingsTestIds = {
|
|
|
731
738
|
fontSizeInput: 'unsubscribe-link-settings-font-size-input',
|
|
732
739
|
textColorInput: 'unsubscribe-link-settings-text-color-input',
|
|
733
740
|
backgroundColorInput: 'unsubscribe-link-settings-background-color-input',
|
|
741
|
+
linkColorInput: 'unsubscribe-link-settings-link-color-input',
|
|
742
|
+
matchTextColorButton: 'unsubscribe-link-settings-match-text-color-button',
|
|
734
743
|
} as const
|
|
735
744
|
|
|
736
745
|
export const previewByIdTestIds = {
|
|
@@ -738,6 +747,9 @@ export const previewByIdTestIds = {
|
|
|
738
747
|
loading: 'preview-by-id-loading',
|
|
739
748
|
} as const
|
|
740
749
|
|
|
741
|
-
export const
|
|
742
|
-
root: '
|
|
750
|
+
export const messageGroupSelectTestIds = {
|
|
751
|
+
root: 'message-group-select-root',
|
|
743
752
|
} as const
|
|
753
|
+
|
|
754
|
+
/** @deprecated Use `messageGroupSelectTestIds` instead */
|
|
755
|
+
export const templateSelectTestIds = messageGroupSelectTestIds
|
package/i18n/locales/de.ts
CHANGED
|
@@ -54,6 +54,11 @@ export default {
|
|
|
54
54
|
search: 'Suchen...',
|
|
55
55
|
success: 'Erfolg',
|
|
56
56
|
translation_failed: 'Übersetzung fehlgeschlagen',
|
|
57
|
+
messageGroupSelect: {
|
|
58
|
+
inactive_tooltip:
|
|
59
|
+
'Diese Nachrichtengruppe enthält nicht genehmigte oder fehlende Nachrichten',
|
|
60
|
+
hide_inactive: 'Inaktive ausblenden',
|
|
61
|
+
},
|
|
57
62
|
view_less: 'Weniger anzeigen',
|
|
58
63
|
view_more: 'Mehr anzeigen',
|
|
59
64
|
},
|
|
@@ -96,6 +101,12 @@ export default {
|
|
|
96
101
|
success: '„{name}“ wurde veröffentlicht.',
|
|
97
102
|
title: 'Nachricht veröffentlichen',
|
|
98
103
|
},
|
|
104
|
+
request_review: {
|
|
105
|
+
confirm: 'Überprüfung anfordern',
|
|
106
|
+
message:
|
|
107
|
+
'Die {language}-Übersetzung zur Überprüfung einreichen? Sie können sie nicht bearbeiten, solange sie auf Genehmigung wartet.',
|
|
108
|
+
title: 'Überprüfung anfordern',
|
|
109
|
+
},
|
|
99
110
|
unpublish_message_group: {
|
|
100
111
|
message:
|
|
101
112
|
'Veröffentlichung von „{name}“ aufheben? Es ist dann nicht mehr für Kundinnen und Kunden sichtbar.',
|
|
@@ -255,6 +266,8 @@ export default {
|
|
|
255
266
|
color: 'Farbe',
|
|
256
267
|
content: 'Inhalt',
|
|
257
268
|
font: 'Schriftart',
|
|
269
|
+
link: 'Link',
|
|
270
|
+
match_text_color: 'An Textfarbe anpassen',
|
|
258
271
|
size: 'Größe',
|
|
259
272
|
text: 'Text',
|
|
260
273
|
textStyle: 'Textstil',
|
|
@@ -608,6 +621,7 @@ export default {
|
|
|
608
621
|
change: 'Änderung',
|
|
609
622
|
changes: 'Änderungen',
|
|
610
623
|
changes_count: '{count} Änderungen',
|
|
624
|
+
request_review: 'Überprüfung anfordern',
|
|
611
625
|
translated_percentage: '{percentage}% übersetzt',
|
|
612
626
|
unsaved_changes: 'Diese Übersetzung hat ungespeicherte Änderungen',
|
|
613
627
|
},
|
|
@@ -620,6 +634,8 @@ export default {
|
|
|
620
634
|
meta_submission: {
|
|
621
635
|
error: 'Meta-Übermittlung mit Fehlern abgeschlossen',
|
|
622
636
|
failed_count: 'Fehlgeschlagene Nachrichten: {count}',
|
|
637
|
+
message_error: 'Übersetzung konnte nicht zur Überprüfung eingereicht werden',
|
|
638
|
+
message_success: 'Übersetzung zur Überprüfung eingereicht',
|
|
623
639
|
success: 'Nachrichten an Meta übermittelt',
|
|
624
640
|
},
|
|
625
641
|
modals: {
|
|
@@ -679,6 +695,7 @@ export default {
|
|
|
679
695
|
default_font: 'Standardschriftart',
|
|
680
696
|
email_bg_color: 'Hintergrund',
|
|
681
697
|
email_content_bg_color: 'Inhalt-Hintergrund',
|
|
698
|
+
email_link_color: 'Link-Farbe',
|
|
682
699
|
email_text_color: 'Text',
|
|
683
700
|
extracting_colors: 'Farben werden aus dem Logo extrahiert...',
|
|
684
701
|
logo: 'Logo',
|
package/i18n/locales/en.ts
CHANGED
|
@@ -53,6 +53,10 @@ export default {
|
|
|
53
53
|
search: 'Search...',
|
|
54
54
|
success: 'Success',
|
|
55
55
|
translation_failed: 'Translation failed',
|
|
56
|
+
messageGroupSelect: {
|
|
57
|
+
inactive_tooltip: 'This message group has unapproved or missing messages',
|
|
58
|
+
hide_inactive: 'Hide inactive',
|
|
59
|
+
},
|
|
56
60
|
view_less: 'View less',
|
|
57
61
|
view_more: 'View more',
|
|
58
62
|
},
|
|
@@ -93,6 +97,12 @@ export default {
|
|
|
93
97
|
success: '"{name}" has been published.',
|
|
94
98
|
title: 'Publish message',
|
|
95
99
|
},
|
|
100
|
+
request_review: {
|
|
101
|
+
confirm: 'Request review',
|
|
102
|
+
message:
|
|
103
|
+
"Submit the {language} translation for review? You won't be able to edit it while it's pending approval.",
|
|
104
|
+
title: 'Request review',
|
|
105
|
+
},
|
|
96
106
|
unpublish_message_group: {
|
|
97
107
|
message: 'Unpublish "{name}"? It will no longer be visible to clients.',
|
|
98
108
|
success: '"{name}" has been unpublished.',
|
|
@@ -250,6 +260,8 @@ export default {
|
|
|
250
260
|
color: 'Color',
|
|
251
261
|
content: 'Content',
|
|
252
262
|
font: 'Font',
|
|
263
|
+
link: 'Link',
|
|
264
|
+
match_text_color: 'Match text color',
|
|
253
265
|
size: 'Size',
|
|
254
266
|
text: 'Text',
|
|
255
267
|
textStyle: 'Text style',
|
|
@@ -599,6 +611,7 @@ export default {
|
|
|
599
611
|
change: 'change',
|
|
600
612
|
changes: 'changes',
|
|
601
613
|
changes_count: '{count} changes',
|
|
614
|
+
request_review: 'Request review',
|
|
602
615
|
translated_percentage: '{percentage}% translated',
|
|
603
616
|
unsaved_changes: 'This translation has unsaved changes',
|
|
604
617
|
},
|
|
@@ -611,6 +624,8 @@ export default {
|
|
|
611
624
|
meta_submission: {
|
|
612
625
|
error: 'Meta submission completed with errors',
|
|
613
626
|
failed_count: 'Failed messages: {count}',
|
|
627
|
+
message_error: 'Failed to submit translation for review',
|
|
628
|
+
message_success: 'Translation submitted for review',
|
|
614
629
|
success: 'Messages submitted to Meta',
|
|
615
630
|
},
|
|
616
631
|
modals: {
|
|
@@ -669,6 +684,7 @@ export default {
|
|
|
669
684
|
default_font: 'Default font',
|
|
670
685
|
email_bg_color: 'Background',
|
|
671
686
|
email_content_bg_color: 'Content background',
|
|
687
|
+
email_link_color: 'Link color',
|
|
672
688
|
email_text_color: 'Text',
|
|
673
689
|
extracting_colors: 'Extracting colors from logo...',
|
|
674
690
|
logo: 'Logo',
|
package/i18n/locales/es.ts
CHANGED
|
@@ -54,6 +54,10 @@ export default {
|
|
|
54
54
|
search: 'Buscar...',
|
|
55
55
|
success: 'Éxito',
|
|
56
56
|
translation_failed: 'La traducción ha fallado',
|
|
57
|
+
messageGroupSelect: {
|
|
58
|
+
inactive_tooltip: 'Este grupo de mensajes tiene mensajes no aprobados o faltantes',
|
|
59
|
+
hide_inactive: 'Ocultar inactivos',
|
|
60
|
+
},
|
|
57
61
|
view_less: 'Ver menos',
|
|
58
62
|
view_more: 'Ver más',
|
|
59
63
|
},
|
|
@@ -94,6 +98,12 @@ export default {
|
|
|
94
98
|
success: '"{name}" se ha publicado.',
|
|
95
99
|
title: 'Publicar mensaje',
|
|
96
100
|
},
|
|
101
|
+
request_review: {
|
|
102
|
+
confirm: 'Solicitar revisión',
|
|
103
|
+
message:
|
|
104
|
+
'¿Enviar la traducción en {language} para revisión? No podrá editarla mientras esté pendiente de aprobación.',
|
|
105
|
+
title: 'Solicitar revisión',
|
|
106
|
+
},
|
|
97
107
|
unpublish_message_group: {
|
|
98
108
|
message: '¿Despublicar "{name}"? Ya no será visible para los clientes.',
|
|
99
109
|
success: '"{name}" se ha despublicado.',
|
|
@@ -251,6 +261,8 @@ export default {
|
|
|
251
261
|
color: 'Color',
|
|
252
262
|
content: 'Contenido',
|
|
253
263
|
font: 'Fuente',
|
|
264
|
+
link: 'Enlace',
|
|
265
|
+
match_text_color: 'Igualar al color del texto',
|
|
254
266
|
size: 'Tamaño',
|
|
255
267
|
text: 'Texto',
|
|
256
268
|
textStyle: 'Estilo del texto',
|
|
@@ -607,6 +619,7 @@ export default {
|
|
|
607
619
|
change: 'cambio',
|
|
608
620
|
changes: 'cambios',
|
|
609
621
|
changes_count: '{count} cambios',
|
|
622
|
+
request_review: 'Solicitar revisión',
|
|
610
623
|
translated_percentage: '{percentage}% traducido',
|
|
611
624
|
unsaved_changes: 'Esta traducción tiene cambios sin guardar',
|
|
612
625
|
},
|
|
@@ -619,6 +632,8 @@ export default {
|
|
|
619
632
|
meta_submission: {
|
|
620
633
|
error: 'Envío a Meta completado con errores',
|
|
621
634
|
failed_count: 'Mensajes fallidos: {count}',
|
|
635
|
+
message_error: 'No se pudo enviar la traducción para revisión',
|
|
636
|
+
message_success: 'Traducción enviada para revisión',
|
|
622
637
|
success: 'Mensajes enviados a Meta',
|
|
623
638
|
},
|
|
624
639
|
modals: {
|
|
@@ -678,6 +693,7 @@ export default {
|
|
|
678
693
|
default_font: 'Fuente predeterminada',
|
|
679
694
|
email_bg_color: 'Fondo',
|
|
680
695
|
email_content_bg_color: 'Fondo contenido',
|
|
696
|
+
email_link_color: 'Color de enlace',
|
|
681
697
|
email_text_color: 'Texto',
|
|
682
698
|
extracting_colors: 'Extrayendo colores del logo...',
|
|
683
699
|
logo: 'Logo',
|
package/i18n/locales/fr.ts
CHANGED
|
@@ -54,6 +54,10 @@ export default {
|
|
|
54
54
|
search: 'Rechercher...',
|
|
55
55
|
success: 'Succès',
|
|
56
56
|
translation_failed: 'Échec de la traduction',
|
|
57
|
+
messageGroupSelect: {
|
|
58
|
+
inactive_tooltip: 'Ce groupe de messages contient des messages non approuvés ou manquants',
|
|
59
|
+
hide_inactive: 'Masquer inactifs',
|
|
60
|
+
},
|
|
57
61
|
view_less: 'Afficher moins',
|
|
58
62
|
view_more: 'Afficher plus',
|
|
59
63
|
},
|
|
@@ -94,6 +98,12 @@ export default {
|
|
|
94
98
|
success: '« {name} » a été publié.',
|
|
95
99
|
title: 'Publier le message',
|
|
96
100
|
},
|
|
101
|
+
request_review: {
|
|
102
|
+
confirm: 'Demander une révision',
|
|
103
|
+
message:
|
|
104
|
+
'Envoyer la traduction {language} pour révision ? Vous ne pourrez pas la modifier tant qu’elle est en attente d’approbation.',
|
|
105
|
+
title: 'Demander une révision',
|
|
106
|
+
},
|
|
97
107
|
unpublish_message_group: {
|
|
98
108
|
message: 'Dépublier « {name} » ? Il ne sera plus visible aux clients.',
|
|
99
109
|
success: '« {name} » a été dépublié.',
|
|
@@ -252,6 +262,8 @@ export default {
|
|
|
252
262
|
color: 'Couleur',
|
|
253
263
|
content: 'Contenu',
|
|
254
264
|
font: 'Police',
|
|
265
|
+
link: 'Lien',
|
|
266
|
+
match_text_color: 'Assortir à la couleur du texte',
|
|
255
267
|
size: 'Taille',
|
|
256
268
|
text: 'Texte',
|
|
257
269
|
textStyle: 'Style de texte',
|
|
@@ -611,6 +623,7 @@ export default {
|
|
|
611
623
|
change: 'modification',
|
|
612
624
|
changes: 'modifications',
|
|
613
625
|
changes_count: '{count} modifications',
|
|
626
|
+
request_review: 'Demander une révision',
|
|
614
627
|
translated_percentage: '{percentage}% traduit',
|
|
615
628
|
unsaved_changes: 'Cette traduction contient des modifications non enregistrées',
|
|
616
629
|
},
|
|
@@ -623,6 +636,8 @@ export default {
|
|
|
623
636
|
meta_submission: {
|
|
624
637
|
error: 'Soumission à Meta terminée avec des erreurs',
|
|
625
638
|
failed_count: 'Messages en échec : {count}',
|
|
639
|
+
message_error: 'Échec de l’envoi de la traduction pour révision',
|
|
640
|
+
message_success: 'Traduction envoyée pour révision',
|
|
626
641
|
success: 'Messages soumis à Meta',
|
|
627
642
|
},
|
|
628
643
|
modals: {
|
|
@@ -682,6 +697,7 @@ export default {
|
|
|
682
697
|
default_font: 'Police par défaut',
|
|
683
698
|
email_bg_color: 'Fond',
|
|
684
699
|
email_content_bg_color: 'Fond contenu',
|
|
700
|
+
email_link_color: 'Couleur du lien',
|
|
685
701
|
email_text_color: 'Texte',
|
|
686
702
|
extracting_colors: 'Extraction des couleurs du logo...',
|
|
687
703
|
logo: 'Logo',
|
package/i18n/locales/it.ts
CHANGED
|
@@ -53,6 +53,10 @@ export default {
|
|
|
53
53
|
search: 'Cerca...',
|
|
54
54
|
success: 'Successo',
|
|
55
55
|
translation_failed: 'Traduzione non riuscita',
|
|
56
|
+
messageGroupSelect: {
|
|
57
|
+
inactive_tooltip: 'Questo gruppo di messaggi contiene messaggi non approvati o mancanti',
|
|
58
|
+
hide_inactive: 'Nascondi inattivi',
|
|
59
|
+
},
|
|
56
60
|
view_less: 'Mostra meno',
|
|
57
61
|
view_more: 'Mostra di più',
|
|
58
62
|
},
|
|
@@ -93,6 +97,12 @@ export default {
|
|
|
93
97
|
success: '"{name}" è stato pubblicato.',
|
|
94
98
|
title: 'Pubblica messaggio',
|
|
95
99
|
},
|
|
100
|
+
request_review: {
|
|
101
|
+
confirm: 'Richiedi revisione',
|
|
102
|
+
message:
|
|
103
|
+
'Inviare per la revisione la traduzione in {language}? Non potrai modificarla finché è in attesa di approvazione.',
|
|
104
|
+
title: 'Richiedi revisione',
|
|
105
|
+
},
|
|
96
106
|
unpublish_message_group: {
|
|
97
107
|
message: 'Annullare la pubblicazione di "{name}"? Non sarà più visibile ai clienti.',
|
|
98
108
|
success: 'La pubblicazione di "{name}" è stata annullata.',
|
|
@@ -251,6 +261,8 @@ export default {
|
|
|
251
261
|
color: 'Colore',
|
|
252
262
|
content: 'Contenuto',
|
|
253
263
|
font: 'Font',
|
|
264
|
+
link: 'Link',
|
|
265
|
+
match_text_color: 'Abbina al colore del testo',
|
|
254
266
|
size: 'Dimensione',
|
|
255
267
|
text: 'Testo',
|
|
256
268
|
textStyle: 'Stile testo',
|
|
@@ -604,6 +616,7 @@ export default {
|
|
|
604
616
|
change: 'modifica',
|
|
605
617
|
changes: 'modifiche',
|
|
606
618
|
changes_count: '{count} modifiche',
|
|
619
|
+
request_review: 'Richiedi revisione',
|
|
607
620
|
translated_percentage: '{percentage}% tradotto',
|
|
608
621
|
unsaved_changes: 'Questa traduzione ha modifiche non salvate',
|
|
609
622
|
},
|
|
@@ -616,6 +629,8 @@ export default {
|
|
|
616
629
|
meta_submission: {
|
|
617
630
|
error: 'Invio a Meta completato con errori',
|
|
618
631
|
failed_count: 'Messaggi non riusciti: {count}',
|
|
632
|
+
message_error: 'Impossibile inviare la traduzione per la revisione',
|
|
633
|
+
message_success: 'Traduzione inviata per la revisione',
|
|
619
634
|
success: 'Messaggi inviati a Meta',
|
|
620
635
|
},
|
|
621
636
|
modals: {
|
|
@@ -675,6 +690,7 @@ export default {
|
|
|
675
690
|
default_font: 'Font predefinito',
|
|
676
691
|
email_bg_color: 'Sfondo',
|
|
677
692
|
email_content_bg_color: 'Sfondo contenuto',
|
|
693
|
+
email_link_color: 'Colore link',
|
|
678
694
|
email_text_color: 'Testo',
|
|
679
695
|
extracting_colors: 'Estrazione dei colori dal logo...',
|
|
680
696
|
logo: 'Logo',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.smartpricing/message-composer-layer",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.11-ux.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"vue-router": "^5.0.7",
|
|
37
37
|
"vue3-emoji-picker": "^1.1.8",
|
|
38
38
|
"zod": "^4.4.3",
|
|
39
|
-
"@dev.smartpricing/message-composer-utils": "4.2.
|
|
39
|
+
"@dev.smartpricing/message-composer-utils": "4.2.11-ux.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@nuxt/eslint": "^1.15.2",
|