@dev.smartpricing/message-composer-layer 4.0.2-tepmlates.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/api/index.ts +1 -1
- package/app/api/organization.ts +5 -0
- package/app/components/Common/MessagePreviewSlideover.vue +0 -1
- package/app/components/Composer/EmailComposer.vue +1 -31
- package/app/components/Composer/MessageLibrary.vue +1 -70
- package/app/components/Composer/WhatsappComposer.vue +0 -24
- package/app/components/CreateTemplateButton.vue +45 -8
- package/app/components/Email/InlinePreview.vue +3 -26
- package/app/components/Email/SendTestEmailModal.vue +34 -2
- package/app/components/TemplateList/BaseTable.vue +0 -7
- package/app/composables/composerContext.ts +5 -0
- package/app/pages/{compose → template}/email/create.vue +1 -10
- package/app/pages/{compose → template}/whatsapp/create.vue +1 -4
- package/app/queries/index.ts +0 -1
- package/app/utils/testIds.const.ts +0 -1
- package/i18n/locales/de.ts +3 -42
- package/i18n/locales/en.ts +3 -41
- package/i18n/locales/es.ts +3 -41
- package/i18n/locales/fr.ts +3 -41
- package/i18n/locales/it.ts +3 -41
- package/package.json +2 -2
- package/app/api/templates.ts +0 -55
- package/app/components/Common/NewMessageModal.vue +0 -276
- package/app/pages/templates/email/[id].vue +0 -82
- package/app/pages/templates/email/create.vue +0 -86
- package/app/pages/templates/index.vue +0 -245
- package/app/pages/templates/whatsapp/[id].vue +0 -82
- package/app/pages/templates/whatsapp/create.vue +0 -86
- package/app/queries/templates.ts +0 -119
- /package/app/pages/{compose → template}/email/[id].vue +0 -0
- /package/app/pages/{compose → template}/whatsapp/[id].vue +0 -0
package/app/api/index.ts
CHANGED
|
@@ -8,13 +8,10 @@ import {
|
|
|
8
8
|
} from '@dev.smartpricing/message-composer-utils/utils'
|
|
9
9
|
import { useAppContextStore } from '@/stores/appContext'
|
|
10
10
|
import { useMessageGroupQuery, useLanguagesQuery } from '~/queries'
|
|
11
|
-
import { templatesApi } from '~/api/templates'
|
|
12
11
|
|
|
13
12
|
const props = defineProps<{
|
|
14
13
|
mode: 'create' | 'edit'
|
|
15
14
|
messageGroupId?: string
|
|
16
|
-
fromTemplateId?: string
|
|
17
|
-
brandId?: string
|
|
18
15
|
}>()
|
|
19
16
|
|
|
20
17
|
const emit = defineEmits<{
|
|
@@ -31,34 +28,7 @@ const { goBackOrFallback } = useGoBack()
|
|
|
31
28
|
// ── Init ──────────────────────────────────────────────────────────
|
|
32
29
|
if (props.mode === 'create') {
|
|
33
30
|
store.initCreate(mainLanguage.value)
|
|
34
|
-
emailEditorStore.initBrand(
|
|
35
|
-
|
|
36
|
-
// Pre-fill from template if provided
|
|
37
|
-
if (props.fromTemplateId) {
|
|
38
|
-
templatesApi.getById(props.fromTemplateId).then((template) => {
|
|
39
|
-
if (!template?.messages?.length) return
|
|
40
|
-
store.name = template.name
|
|
41
|
-
store.category = template.category
|
|
42
|
-
for (const msg of template.messages) {
|
|
43
|
-
if (msg.render_type !== 'email_v1') continue
|
|
44
|
-
store.messages[msg.language_id] = {
|
|
45
|
-
render_type: msg.render_type,
|
|
46
|
-
body: msg.body,
|
|
47
|
-
metadata: {},
|
|
48
|
-
language_id: msg.language_id,
|
|
49
|
-
message_group_id: '',
|
|
50
|
-
status: 'draft',
|
|
51
|
-
owner: '',
|
|
52
|
-
user_id: '',
|
|
53
|
-
} as PostEntity<EmailMessage>
|
|
54
|
-
}
|
|
55
|
-
// Reload editor with first message
|
|
56
|
-
const currentMessage = store.currentMessage
|
|
57
|
-
if (currentMessage) {
|
|
58
|
-
emailEditorStore.loadFromData(currentMessage as PostEntity<EmailMessage>)
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
}
|
|
31
|
+
emailEditorStore.initBrand()
|
|
62
32
|
} else {
|
|
63
33
|
// Edit mode: data loaded via watcher below
|
|
64
34
|
}
|
|
@@ -4,14 +4,13 @@ import {
|
|
|
4
4
|
useDeleteMessageGroupMutation,
|
|
5
5
|
usePublishMessageGroupMutation,
|
|
6
6
|
useUnpublishMessageGroupMutation,
|
|
7
|
-
useSaveAsTemplateMutation,
|
|
8
7
|
} from '~/queries'
|
|
9
8
|
import type {
|
|
10
9
|
MessageGroupWithMessageSummary,
|
|
11
10
|
RenderType,
|
|
12
11
|
} from '@dev.smartpricing/message-composer-utils/types'
|
|
13
12
|
import type { MessageActionProperties, MessagesKind } from '@/types/tracking'
|
|
14
|
-
import { computed
|
|
13
|
+
import { computed } from 'vue'
|
|
15
14
|
import BaseTable from '@/components/TemplateList/BaseTable.vue'
|
|
16
15
|
|
|
17
16
|
const renderType = defineModel<RenderType>('renderType', { required: true })
|
|
@@ -43,34 +42,6 @@ const { confirm } = useConfirm()
|
|
|
43
42
|
const { mutateAsync: deleteGroup } = useDeleteMessageGroupMutation()
|
|
44
43
|
const { mutateAsync: publishGroup } = usePublishMessageGroupMutation()
|
|
45
44
|
const { mutateAsync: unpublishGroup } = useUnpublishMessageGroupMutation()
|
|
46
|
-
const { mutateAsync: saveAsTemplate, isPending: isSavingAsTemplate } = useSaveAsTemplateMutation()
|
|
47
|
-
|
|
48
|
-
// Save as template modal state
|
|
49
|
-
const saveAsTemplateModalOpen = ref(false)
|
|
50
|
-
const saveAsTemplateName = ref('')
|
|
51
|
-
const saveAsTemplateTarget = ref<MessageGroupWithMessageSummary | null>(null)
|
|
52
|
-
|
|
53
|
-
function openSaveAsTemplateModal(row: MessageGroupWithMessageSummary) {
|
|
54
|
-
saveAsTemplateTarget.value = row
|
|
55
|
-
saveAsTemplateName.value = row.name
|
|
56
|
-
saveAsTemplateModalOpen.value = true
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function confirmSaveAsTemplate() {
|
|
60
|
-
if (!saveAsTemplateTarget.value) return
|
|
61
|
-
|
|
62
|
-
const row = saveAsTemplateTarget.value
|
|
63
|
-
const name = saveAsTemplateName.value.trim() || row.name
|
|
64
|
-
|
|
65
|
-
await saveAsTemplate({ messageGroupId: row.id, name })
|
|
66
|
-
|
|
67
|
-
useToast().add({
|
|
68
|
-
title: t('templates.dialogs.save_as_template.success'),
|
|
69
|
-
color: 'success',
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
saveAsTemplateModalOpen.value = false
|
|
73
|
-
}
|
|
74
45
|
|
|
75
46
|
function getMessageTrackingProps(row: MessageGroupWithMessageSummary): MessageActionProperties {
|
|
76
47
|
return {
|
|
@@ -180,45 +151,5 @@ defineExpose({ execute })
|
|
|
180
151
|
@duplicate="handleDuplicate"
|
|
181
152
|
@publish="askPublishGroup"
|
|
182
153
|
@unpublish="askUnpublishGroup"
|
|
183
|
-
@save-as-template="openSaveAsTemplateModal"
|
|
184
154
|
/>
|
|
185
|
-
|
|
186
|
-
<UModal
|
|
187
|
-
v-model:open="saveAsTemplateModalOpen"
|
|
188
|
-
:title="t('templates.dialogs.save_as_template.title')"
|
|
189
|
-
close-icon="ph:x"
|
|
190
|
-
>
|
|
191
|
-
<template #body>
|
|
192
|
-
<div class="flex flex-col gap-4">
|
|
193
|
-
<p class="text-sm text-muted">
|
|
194
|
-
{{ t('templates.dialogs.save_as_template.message') }}
|
|
195
|
-
</p>
|
|
196
|
-
<UFormField :label="t('templates.template_name')">
|
|
197
|
-
<UInput
|
|
198
|
-
v-model="saveAsTemplateName"
|
|
199
|
-
:placeholder="t('templates.template_name_placeholder')"
|
|
200
|
-
class="w-full"
|
|
201
|
-
autofocus
|
|
202
|
-
@keydown.enter="confirmSaveAsTemplate"
|
|
203
|
-
/>
|
|
204
|
-
</UFormField>
|
|
205
|
-
</div>
|
|
206
|
-
</template>
|
|
207
|
-
|
|
208
|
-
<template #footer>
|
|
209
|
-
<div class="flex gap-2 justify-end w-full">
|
|
210
|
-
<UButton variant="outline" color="neutral" @click="saveAsTemplateModalOpen = false">
|
|
211
|
-
{{ t('common.actions.cancel') }}
|
|
212
|
-
</UButton>
|
|
213
|
-
<UButton
|
|
214
|
-
color="primary"
|
|
215
|
-
:loading="isSavingAsTemplate"
|
|
216
|
-
:disabled="!saveAsTemplateName.trim()"
|
|
217
|
-
@click="confirmSaveAsTemplate"
|
|
218
|
-
>
|
|
219
|
-
{{ t('templates.save_as_template') }}
|
|
220
|
-
</UButton>
|
|
221
|
-
</div>
|
|
222
|
-
</template>
|
|
223
|
-
</UModal>
|
|
224
155
|
</template>
|
|
@@ -9,13 +9,11 @@ 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 { templatesApi } from '~/api/templates'
|
|
13
12
|
import type { WaHeaderType } from '~/types/tracking'
|
|
14
13
|
|
|
15
14
|
const props = defineProps<{
|
|
16
15
|
mode: 'create' | 'edit'
|
|
17
16
|
messageGroupId?: string
|
|
18
|
-
fromTemplateId?: string
|
|
19
17
|
}>()
|
|
20
18
|
|
|
21
19
|
const emit = defineEmits<{
|
|
@@ -32,28 +30,6 @@ const { submitToMeta } = useMetaSubmissionStore()
|
|
|
32
30
|
// ── Init ──────────────────────────────────────────────────────────
|
|
33
31
|
if (props.mode === 'create') {
|
|
34
32
|
store.initCreate(mainLanguage.value)
|
|
35
|
-
|
|
36
|
-
// Pre-fill from template if provided
|
|
37
|
-
if (props.fromTemplateId) {
|
|
38
|
-
templatesApi.getById(props.fromTemplateId).then((template) => {
|
|
39
|
-
if (!template?.messages?.length) return
|
|
40
|
-
store.name = template.name
|
|
41
|
-
store.category = template.category
|
|
42
|
-
for (const msg of template.messages) {
|
|
43
|
-
if (msg.render_type !== 'whatsapp_v1') continue
|
|
44
|
-
store.messages[msg.language_id] = {
|
|
45
|
-
render_type: msg.render_type,
|
|
46
|
-
body: msg.body,
|
|
47
|
-
metadata: {},
|
|
48
|
-
language_id: msg.language_id,
|
|
49
|
-
message_group_id: '',
|
|
50
|
-
status: 'draft',
|
|
51
|
-
owner: '',
|
|
52
|
-
user_id: '',
|
|
53
|
-
} as PostEntity<WhatsappMessage>
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
33
|
}
|
|
58
34
|
|
|
59
35
|
// ── Edit mode: fetch message group ────────────────────────────────
|
|
@@ -1,22 +1,59 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useRouter } from 'vue-router'
|
|
3
4
|
|
|
5
|
+
const router = useRouter()
|
|
6
|
+
const { hasWhatsapp, hasEmail } = useChannels()
|
|
7
|
+
const { t } = useI18n()
|
|
4
8
|
const { trackEvent } = useTracking()
|
|
5
|
-
const modalOpen = ref(false)
|
|
6
9
|
|
|
7
|
-
function
|
|
8
|
-
trackEvent('message_create', { message_kind:
|
|
9
|
-
|
|
10
|
+
function createTemplate(type: 'whatsapp' | 'email') {
|
|
11
|
+
trackEvent('message_create', { message_kind: type })
|
|
12
|
+
router.push({ name: `${type}-message-create` })
|
|
10
13
|
}
|
|
14
|
+
|
|
15
|
+
const templateOptions = computed(() => {
|
|
16
|
+
const options = []
|
|
17
|
+
if (hasWhatsapp.value) {
|
|
18
|
+
options.push({
|
|
19
|
+
label: t('message.render_type.whatsapp_v1'),
|
|
20
|
+
onSelect: () => createTemplate('whatsapp'),
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
if (hasEmail.value) {
|
|
24
|
+
options.push({
|
|
25
|
+
label: t('message.render_type.email_v1'),
|
|
26
|
+
onSelect: () => createTemplate('email'),
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
return options
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const singleChannelType = computed(() => {
|
|
33
|
+
if (hasWhatsapp.value && !hasEmail.value) return 'whatsapp'
|
|
34
|
+
if (hasEmail.value && !hasWhatsapp.value) return 'email'
|
|
35
|
+
return null
|
|
36
|
+
})
|
|
11
37
|
</script>
|
|
12
38
|
|
|
13
39
|
<template>
|
|
14
40
|
<UButton
|
|
41
|
+
v-if="singleChannelType"
|
|
15
42
|
:label="$t('pages.message_library.add_message_group')"
|
|
16
43
|
color="primary"
|
|
17
44
|
:data-testid="homeTestIds.createTemplateButton"
|
|
18
|
-
@click="
|
|
45
|
+
@click="createTemplate(singleChannelType)"
|
|
19
46
|
/>
|
|
20
|
-
|
|
21
|
-
|
|
47
|
+
<UDropdownMenu
|
|
48
|
+
v-else
|
|
49
|
+
:items="templateOptions"
|
|
50
|
+
:popper="{ placement: 'bottom-end' }"
|
|
51
|
+
:data-testid="homeTestIds.createTemplateDropdown"
|
|
52
|
+
>
|
|
53
|
+
<UButton
|
|
54
|
+
:label="$t('pages.message_library.add_message_group')"
|
|
55
|
+
color="primary"
|
|
56
|
+
:data-testid="homeTestIds.createTemplateButton"
|
|
57
|
+
/>
|
|
58
|
+
</UDropdownMenu>
|
|
22
59
|
</template>
|
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
PostEntity,
|
|
5
5
|
BrandFromDb,
|
|
6
6
|
} from '@dev.smartpricing/message-composer-utils/types'
|
|
7
|
-
import { extractEmailParameters } from '@dev.smartpricing/message-composer-utils/utils'
|
|
8
7
|
import { ref, computed, watch } from 'vue'
|
|
9
8
|
import { useDebounceFn } from '@vueuse/core'
|
|
10
9
|
import HtmlPreviewIframe from '@/components/Common/HtmlPreviewIframe.vue'
|
|
@@ -16,7 +15,6 @@ const props = withDefaults(
|
|
|
16
15
|
defineProps<{
|
|
17
16
|
message: PostEntity<EmailMessage> | EmailMessage
|
|
18
17
|
brand?: BrandFromDb | null
|
|
19
|
-
dynamicData?: Record<string, string>
|
|
20
18
|
view?: 'desktop' | 'mobile'
|
|
21
19
|
showSubject?: boolean
|
|
22
20
|
}>(),
|
|
@@ -27,16 +25,11 @@ const iframeWidth = computed(() => {
|
|
|
27
25
|
return props.view === 'mobile' ? '400px' : '600px'
|
|
28
26
|
})
|
|
29
27
|
|
|
30
|
-
// Extract parameters client-side
|
|
31
|
-
const parameters = computed(() => extractEmailParameters(props.message))
|
|
32
|
-
|
|
33
|
-
const parameterValues = ref<Record<string, string>>({})
|
|
34
28
|
const { mutate: preview, data: previewed, isLoading: isPreviewing } = usePreviewEmailMutation()
|
|
35
29
|
|
|
36
30
|
const previewEmail = useDebounceFn(() => {
|
|
37
31
|
preview({
|
|
38
32
|
message: props.message as any,
|
|
39
|
-
parameters: parameterValues.value,
|
|
40
33
|
brand: props.brand
|
|
41
34
|
? {
|
|
42
35
|
default_email_settings: props.brand.default_email_settings,
|
|
@@ -44,32 +37,16 @@ const previewEmail = useDebounceFn(() => {
|
|
|
44
37
|
default_socials: normalizeBrandSocials(props.brand.default_socials),
|
|
45
38
|
logo_url: props.brand.logo_url,
|
|
46
39
|
}
|
|
47
|
-
:
|
|
40
|
+
: null,
|
|
48
41
|
})
|
|
49
42
|
}, 0)
|
|
50
43
|
|
|
51
44
|
watch(
|
|
52
|
-
|
|
53
|
-
(params) => {
|
|
54
|
-
const defaults = props.dynamicData || {}
|
|
55
|
-
parameterValues.value = params.reduce(
|
|
56
|
-
(acc, param) => {
|
|
57
|
-
acc[param] = defaults[param] || `Sample ${param}`
|
|
58
|
-
return acc
|
|
59
|
-
},
|
|
60
|
-
{} as Record<string, string>,
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
previewEmail()
|
|
64
|
-
},
|
|
65
|
-
{ immediate: true },
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
watch(
|
|
69
|
-
() => props.brand,
|
|
45
|
+
() => props.message,
|
|
70
46
|
() => {
|
|
71
47
|
previewEmail()
|
|
72
48
|
},
|
|
49
|
+
{ immediate: true, deep: true },
|
|
73
50
|
)
|
|
74
51
|
|
|
75
52
|
const iframeContent = ref<string>('')
|
|
@@ -5,6 +5,7 @@ import { useQuery } from '@pinia/colada'
|
|
|
5
5
|
import { useSendTestEmailMutation } from '~/queries'
|
|
6
6
|
import { messageGroupsApi, messagesApi } from '~/api'
|
|
7
7
|
import { useEmailEditorStore } from '~/stores/emailEditor'
|
|
8
|
+
import { useComposerContext } from '~/composables/composerContext'
|
|
8
9
|
import { z } from 'zod'
|
|
9
10
|
|
|
10
11
|
defineOptions({
|
|
@@ -83,12 +84,28 @@ const isResolvingMessage = computed(
|
|
|
83
84
|
const { t } = useI18n()
|
|
84
85
|
const toast = useToast()
|
|
85
86
|
const emailEditorStore = useEmailEditorStore()
|
|
87
|
+
const composerContext = useComposerContext()
|
|
86
88
|
const { mutate: sendTest, isLoading: isSending, status } = useSendTestEmailMutation()
|
|
87
89
|
|
|
90
|
+
const defaultSenderEmail = computed(
|
|
91
|
+
() => composerContext.organizationData?.value?.senderEmail ?? '',
|
|
92
|
+
)
|
|
93
|
+
|
|
88
94
|
const state = ref<Schema>({
|
|
89
95
|
to: '',
|
|
96
|
+
from: '',
|
|
90
97
|
})
|
|
91
98
|
|
|
99
|
+
watch(
|
|
100
|
+
defaultSenderEmail,
|
|
101
|
+
(email) => {
|
|
102
|
+
if (!state.value.from) {
|
|
103
|
+
state.value.from = email
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{ immediate: true },
|
|
107
|
+
)
|
|
108
|
+
|
|
92
109
|
const schema = z.object({
|
|
93
110
|
to: z
|
|
94
111
|
.string()
|
|
@@ -103,6 +120,9 @@ const schema = z.object({
|
|
|
103
120
|
},
|
|
104
121
|
{ message: t('editor.validation.error.emailInvalid') },
|
|
105
122
|
),
|
|
123
|
+
from: z.string().refine((value) => !value || isEmail(value), {
|
|
124
|
+
message: t('editor.validation.error.emailInvalid'),
|
|
125
|
+
}),
|
|
106
126
|
})
|
|
107
127
|
|
|
108
128
|
type Schema = z.output<typeof schema>
|
|
@@ -117,6 +137,7 @@ function onSubmit() {
|
|
|
117
137
|
message: resolvedMessage.value,
|
|
118
138
|
to: state.value.to,
|
|
119
139
|
brand_id: resolvedBrandId.value,
|
|
140
|
+
from: state.value.from || undefined,
|
|
120
141
|
})
|
|
121
142
|
}
|
|
122
143
|
|
|
@@ -161,14 +182,25 @@ watch(status, (newStatus) => {
|
|
|
161
182
|
</slot>
|
|
162
183
|
|
|
163
184
|
<template #body>
|
|
164
|
-
<UForm ref="formRef" :schema="schema" :state="state" @submit="onSubmit">
|
|
165
|
-
<UFormField
|
|
185
|
+
<UForm ref="formRef" :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
|
186
|
+
<UFormField
|
|
187
|
+
name="to"
|
|
188
|
+
:label="$t('pages.email.test_email_to')"
|
|
189
|
+
:data-testid="sendTestEmailModalTestIds.toFormField"
|
|
190
|
+
>
|
|
166
191
|
<UInput
|
|
167
192
|
v-model="state.to"
|
|
168
193
|
:placeholder="$t('pages.email.test_email_to_placeholder')"
|
|
169
194
|
:data-testid="sendTestEmailModalTestIds.toInput"
|
|
170
195
|
/>
|
|
171
196
|
</UFormField>
|
|
197
|
+
<UFormField name="from" :label="$t('pages.email.test_email_from')">
|
|
198
|
+
<UInput
|
|
199
|
+
v-model="state.from"
|
|
200
|
+
type="email"
|
|
201
|
+
:placeholder="$t('pages.email.test_email_from_placeholder')"
|
|
202
|
+
/>
|
|
203
|
+
</UFormField>
|
|
172
204
|
</UForm>
|
|
173
205
|
</template>
|
|
174
206
|
|
|
@@ -18,7 +18,6 @@ const emit = defineEmits<{
|
|
|
18
18
|
duplicate: [MessageGroupWithMessageSummary]
|
|
19
19
|
publish: [MessageGroupWithMessageSummary]
|
|
20
20
|
unpublish: [MessageGroupWithMessageSummary]
|
|
21
|
-
saveAsTemplate: [MessageGroupWithMessageSummary]
|
|
22
21
|
}>()
|
|
23
22
|
|
|
24
23
|
const appContext = useAppContextStore()
|
|
@@ -77,12 +76,6 @@ function rowActions(row: MessageGroupWithMessageSummary) {
|
|
|
77
76
|
onSelect: () => emit('duplicate', row),
|
|
78
77
|
'data-testid': `${templateListTableTestIds.rowDuplicateAction}-${row.id}`,
|
|
79
78
|
},
|
|
80
|
-
{
|
|
81
|
-
label: t('templates.save_as_template'),
|
|
82
|
-
icon: 'ph:bookmark-simple',
|
|
83
|
-
onSelect: () => emit('saveAsTemplate', row),
|
|
84
|
-
'data-testid': `${templateListTableTestIds.rowSaveAsTemplateAction}-${row.id}`,
|
|
85
|
-
},
|
|
86
79
|
{
|
|
87
80
|
label: t('common.actions.delete'),
|
|
88
81
|
icon: 'ph:trash',
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { InjectionKey, Ref } from 'vue'
|
|
2
2
|
import type { AppContextConfig } from '@dev.smartpricing/message-composer-utils/types'
|
|
3
3
|
|
|
4
|
+
export interface OrganizationData {
|
|
5
|
+
senderEmail: string
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
export interface ComposerContext {
|
|
5
9
|
authenticationToken: Ref<string>
|
|
6
10
|
owner_id?: Ref<string>
|
|
@@ -14,6 +18,7 @@ export interface ComposerContext {
|
|
|
14
18
|
metaWabaId?: Ref<string>
|
|
15
19
|
metaAccessToken?: Ref<string>
|
|
16
20
|
isAdmin?: Ref<boolean>
|
|
21
|
+
organizationData?: Ref<OrganizationData>
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
export const COMPOSER_CONTEXT_KEY: InjectionKey<ComposerContext> = Symbol.for('composer-context')
|
|
@@ -5,12 +5,8 @@ definePageMeta({
|
|
|
5
5
|
channel: 'email',
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
-
const route = useRoute()
|
|
9
8
|
const composerRef = useTemplateRef('composerRef')
|
|
10
9
|
const store = useEmailComposerStore()
|
|
11
|
-
|
|
12
|
-
const fromTemplateId = computed(() => route.query.from_template as string | undefined)
|
|
13
|
-
const brandId = computed(() => route.query.brand_id as string | undefined)
|
|
14
10
|
</script>
|
|
15
11
|
|
|
16
12
|
<template>
|
|
@@ -56,12 +52,7 @@ const brandId = computed(() => route.query.brand_id as string | undefined)
|
|
|
56
52
|
/>
|
|
57
53
|
</template>
|
|
58
54
|
|
|
59
|
-
<ComposerEmailComposer
|
|
60
|
-
ref="composerRef"
|
|
61
|
-
mode="create"
|
|
62
|
-
:from-template-id="fromTemplateId"
|
|
63
|
-
:brand-id="brandId"
|
|
64
|
-
>
|
|
55
|
+
<ComposerEmailComposer ref="composerRef" mode="create">
|
|
65
56
|
<template #actions></template>
|
|
66
57
|
</ComposerEmailComposer>
|
|
67
58
|
</LayoutBasePage>
|
|
@@ -5,11 +5,8 @@ definePageMeta({
|
|
|
5
5
|
channel: 'whatsapp',
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
-
const route = useRoute()
|
|
9
8
|
const composerRef = useTemplateRef('composerRef')
|
|
10
9
|
const store = useWhatsappComposerStore()
|
|
11
|
-
|
|
12
|
-
const fromTemplateId = computed(() => route.query.from_template as string | undefined)
|
|
13
10
|
</script>
|
|
14
11
|
|
|
15
12
|
<template>
|
|
@@ -49,7 +46,7 @@ const fromTemplateId = computed(() => route.query.from_template as string | unde
|
|
|
49
46
|
/>
|
|
50
47
|
</template>
|
|
51
48
|
|
|
52
|
-
<ComposerWhatsappComposer ref="composerRef" mode="create"
|
|
49
|
+
<ComposerWhatsappComposer ref="composerRef" mode="create">
|
|
53
50
|
<template #actions></template>
|
|
54
51
|
</ComposerWhatsappComposer>
|
|
55
52
|
</LayoutBasePage>
|
package/app/queries/index.ts
CHANGED
|
@@ -520,7 +520,6 @@ export const templateListTableTestIds = {
|
|
|
520
520
|
rowDuplicateAction: 'template-list-table-row-duplicate',
|
|
521
521
|
rowPublishAction: 'template-list-table-row-publish',
|
|
522
522
|
rowUnpublishAction: 'template-list-table-row-unpublish',
|
|
523
|
-
rowSaveAsTemplateAction: 'template-list-table-row-save-as-template',
|
|
524
523
|
} as const
|
|
525
524
|
|
|
526
525
|
export const templateListStatusCellTestIds = {
|
package/i18n/locales/de.ts
CHANGED
|
@@ -239,7 +239,10 @@ Diese Nachrichten müssen funktional sein, nicht werblich.
|
|
|
239
239
|
email: {
|
|
240
240
|
send_test: 'Test senden',
|
|
241
241
|
send_test_success: 'Test-E-Mail erfolgreich gesendet.',
|
|
242
|
+
test_email_to: 'An',
|
|
242
243
|
test_email_to_placeholder: 'Empfänger-E-Mail(s), getrennt durch ;',
|
|
244
|
+
test_email_from: 'Von',
|
|
245
|
+
test_email_from_placeholder: 'Absender-E-Mail-Adresse',
|
|
243
246
|
create_message_group: {
|
|
244
247
|
title: 'Nachricht erstellen',
|
|
245
248
|
save: 'Speichern',
|
|
@@ -831,48 +834,6 @@ Diese Nachrichten müssen funktional sein, nicht werblich.
|
|
|
831
834
|
no_preview: 'Keine Vorschau verfügbar',
|
|
832
835
|
subject: 'Betreff',
|
|
833
836
|
},
|
|
834
|
-
templates: {
|
|
835
|
-
title: 'Vorlagen',
|
|
836
|
-
my_templates: 'Meine Vorlagen',
|
|
837
|
-
system_templates: 'Systemvorlagen',
|
|
838
|
-
add_template: 'Neue Vorlage',
|
|
839
|
-
create_template: 'Vorlage erstellen',
|
|
840
|
-
edit_template: 'Vorlage bearbeiten',
|
|
841
|
-
use_template: 'Diese Vorlage verwenden',
|
|
842
|
-
start_from_scratch: 'Neu beginnen',
|
|
843
|
-
pick_template: 'Vorlage auswählen',
|
|
844
|
-
save_as_template: 'Als Vorlage speichern',
|
|
845
|
-
system_template: 'Systemvorlage',
|
|
846
|
-
template_name: 'Vorlagenname',
|
|
847
|
-
template_name_placeholder: 'Vorlagenname eingeben',
|
|
848
|
-
no_templates: 'Keine Vorlagen verfügbar',
|
|
849
|
-
new_message_email: 'Neue E-Mail-Nachricht',
|
|
850
|
-
new_message_whatsapp: 'Neue WhatsApp-Nachricht',
|
|
851
|
-
dialogs: {
|
|
852
|
-
delete: {
|
|
853
|
-
title: 'Vorlage löschen',
|
|
854
|
-
message:
|
|
855
|
-
'Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie {name} wirklich löschen?',
|
|
856
|
-
success: '"{name}" wurde gelöscht.',
|
|
857
|
-
},
|
|
858
|
-
publish: {
|
|
859
|
-
title: 'Vorlage veröffentlichen',
|
|
860
|
-
message: '"{name}" veröffentlichen, um sie allen Benutzern zugänglich zu machen?',
|
|
861
|
-
success: '"{name}" wurde veröffentlicht.',
|
|
862
|
-
},
|
|
863
|
-
unpublish: {
|
|
864
|
-
title: 'Vorlage verbergen',
|
|
865
|
-
message: '"{name}" verbergen? Sie wird für andere Benutzer nicht mehr sichtbar sein.',
|
|
866
|
-
success: '"{name}" wurde verborgen.',
|
|
867
|
-
},
|
|
868
|
-
save_as_template: {
|
|
869
|
-
title: 'Als Vorlage speichern',
|
|
870
|
-
message: 'Diese Nachricht als wiederverwendbare Vorlage speichern?',
|
|
871
|
-
success: 'Vorlage erfolgreich gespeichert.',
|
|
872
|
-
},
|
|
873
|
-
},
|
|
874
|
-
copy_success: 'Nachricht aus Vorlage erstellt.',
|
|
875
|
-
},
|
|
876
837
|
public: {
|
|
877
838
|
select_message: {
|
|
878
839
|
choose_message: 'Nachricht auswählen...',
|
package/i18n/locales/en.ts
CHANGED
|
@@ -236,7 +236,10 @@ These messages must be functional, not promotional.
|
|
|
236
236
|
email: {
|
|
237
237
|
send_test: 'Send test',
|
|
238
238
|
send_test_success: 'Test email sent successfully.',
|
|
239
|
+
test_email_to: 'To',
|
|
239
240
|
test_email_to_placeholder: 'Recipient email(s), separated by ;',
|
|
241
|
+
test_email_from: 'From',
|
|
242
|
+
test_email_from_placeholder: 'Sender email address',
|
|
240
243
|
create_message_group: {
|
|
241
244
|
title: 'Create message',
|
|
242
245
|
save: 'Save',
|
|
@@ -822,47 +825,6 @@ These messages must be functional, not promotional.
|
|
|
822
825
|
no_preview: 'No preview available',
|
|
823
826
|
subject: 'Subject',
|
|
824
827
|
},
|
|
825
|
-
templates: {
|
|
826
|
-
title: 'Templates',
|
|
827
|
-
my_templates: 'My templates',
|
|
828
|
-
system_templates: 'System templates',
|
|
829
|
-
add_template: 'New template',
|
|
830
|
-
create_template: 'Create template',
|
|
831
|
-
edit_template: 'Edit template',
|
|
832
|
-
use_template: 'Use this template',
|
|
833
|
-
start_from_scratch: 'Start from scratch',
|
|
834
|
-
pick_template: 'Choose a template',
|
|
835
|
-
save_as_template: 'Save as template',
|
|
836
|
-
system_template: 'System template',
|
|
837
|
-
template_name: 'Template name',
|
|
838
|
-
template_name_placeholder: 'Enter template name',
|
|
839
|
-
no_templates: 'No templates available',
|
|
840
|
-
new_message_email: 'New email message',
|
|
841
|
-
new_message_whatsapp: 'New WhatsApp message',
|
|
842
|
-
dialogs: {
|
|
843
|
-
delete: {
|
|
844
|
-
title: 'Delete template',
|
|
845
|
-
message: "This action can't be undone. Are you sure you want to delete {name}?",
|
|
846
|
-
success: '"{name}" has been deleted.',
|
|
847
|
-
},
|
|
848
|
-
publish: {
|
|
849
|
-
title: 'Publish template',
|
|
850
|
-
message: 'Publish "{name}" to make it available to all users?',
|
|
851
|
-
success: '"{name}" has been published.',
|
|
852
|
-
},
|
|
853
|
-
unpublish: {
|
|
854
|
-
title: 'Unpublish template',
|
|
855
|
-
message: 'Unpublish "{name}"? It will no longer be visible to other users.',
|
|
856
|
-
success: '"{name}" has been unpublished.',
|
|
857
|
-
},
|
|
858
|
-
save_as_template: {
|
|
859
|
-
title: 'Save as template',
|
|
860
|
-
message: 'Save this message as a reusable template?',
|
|
861
|
-
success: 'Template saved successfully.',
|
|
862
|
-
},
|
|
863
|
-
},
|
|
864
|
-
copy_success: 'Message created from template.',
|
|
865
|
-
},
|
|
866
828
|
public: {
|
|
867
829
|
select_message: {
|
|
868
830
|
choose_message: 'Choose a message...',
|