@dev.smartpricing/message-composer-layer 4.0.2-templates.0 → 4.0.2-templates.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/templates.ts +7 -0
- package/app/components/TemplateList/PromoteModal.vue +69 -0
- package/app/pages/templates/email/create.vue +1 -13
- package/app/pages/templates/index.vue +19 -0
- package/app/pages/templates/whatsapp/create.vue +1 -13
- package/app/queries/templates.ts +13 -0
- package/i18n/locales/de.ts +1 -0
- package/i18n/locales/en.ts +12 -0
- package/i18n/locales/es.ts +1 -0
- package/i18n/locales/fr.ts +1 -0
- package/i18n/locales/it.ts +1 -0
- package/package.json +2 -2
package/app/api/templates.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
TemplateWithMessageSummary,
|
|
5
5
|
CreateTemplatePayload,
|
|
6
6
|
UpdateTemplatePayload,
|
|
7
|
+
PromoteTemplatePayload,
|
|
7
8
|
} from '@dev.smartpricing/message-composer-utils/types'
|
|
8
9
|
import { apiClient } from './client'
|
|
9
10
|
|
|
@@ -47,6 +48,12 @@ export const templatesApi = {
|
|
|
47
48
|
unpublish: (id: string) =>
|
|
48
49
|
apiClient<TemplateFromDb>(`/templates/${id}/unpublish`, { method: 'PUT' }),
|
|
49
50
|
|
|
51
|
+
promote: (id: string, data: PromoteTemplatePayload) =>
|
|
52
|
+
apiClient<TemplateFromDb>(`/templates/${id}/promote`, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
body: data,
|
|
55
|
+
}),
|
|
56
|
+
|
|
50
57
|
saveFromMessageGroup: (messageGroupId: string, name?: string) =>
|
|
51
58
|
apiClient<TemplateFromDb>(`/message-groups/${messageGroupId}/save-as-template`, {
|
|
52
59
|
method: 'POST',
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { TemplateWithMessageSummary } from '@dev.smartpricing/message-composer-utils/types'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
template: TemplateWithMessageSummary | null
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
const emit = defineEmits<{
|
|
9
|
+
confirm: [mode: 'clone' | 'convert']
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const open = defineModel<boolean>('open', { required: true })
|
|
13
|
+
|
|
14
|
+
const { t } = useI18n()
|
|
15
|
+
const { mutateAsync: promoteTemplate, isPending } = usePromoteTemplateMutation()
|
|
16
|
+
const toast = useToast()
|
|
17
|
+
|
|
18
|
+
const mode = ref<'clone' | 'convert'>('clone')
|
|
19
|
+
|
|
20
|
+
const items = computed(() => [
|
|
21
|
+
{
|
|
22
|
+
label: t('templates.dialogs.promote.clone_label'),
|
|
23
|
+
description: t('templates.dialogs.promote.clone_description'),
|
|
24
|
+
value: 'clone' as const,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: t('templates.dialogs.promote.convert_label'),
|
|
28
|
+
description: t('templates.dialogs.promote.convert_description'),
|
|
29
|
+
value: 'convert' as const,
|
|
30
|
+
},
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
async function handleConfirm() {
|
|
34
|
+
if (!props.template) return
|
|
35
|
+
await promoteTemplate({ id: props.template.id, data: { mode: mode.value } })
|
|
36
|
+
const key = mode.value === 'clone' ? 'success_clone' : 'success_convert'
|
|
37
|
+
toast.add({
|
|
38
|
+
title: t(`templates.dialogs.promote.${key}`, { name: props.template.name }),
|
|
39
|
+
color: 'success',
|
|
40
|
+
})
|
|
41
|
+
open.value = false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
watch(open, (v) => {
|
|
45
|
+
if (v) mode.value = 'clone'
|
|
46
|
+
})
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<UModal
|
|
51
|
+
v-model:open="open"
|
|
52
|
+
:title="$t('templates.dialogs.promote.title')"
|
|
53
|
+
:ui="{ footer: 'justify-end' }"
|
|
54
|
+
>
|
|
55
|
+
<template #body>
|
|
56
|
+
<URadioGroup v-model="mode" :items="items" variant="card" color="secondary" />
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<template #footer>
|
|
60
|
+
<UButton variant="outline" :label="$t('common.actions.cancel')" @click="open = false" />
|
|
61
|
+
<UButton
|
|
62
|
+
color="primary"
|
|
63
|
+
:label="$t('common.actions.confirm')"
|
|
64
|
+
:loading="isPending"
|
|
65
|
+
@click="handleConfirm"
|
|
66
|
+
/>
|
|
67
|
+
</template>
|
|
68
|
+
</UModal>
|
|
69
|
+
</template>
|
|
@@ -13,9 +13,6 @@ const toast = useToast()
|
|
|
13
13
|
const { t } = useI18n()
|
|
14
14
|
const { goBackOrFallback } = useGoBack()
|
|
15
15
|
|
|
16
|
-
const appContext = useAppContextStore()
|
|
17
|
-
const isSystem = ref(false)
|
|
18
|
-
|
|
19
16
|
const { mutateAsync: createTemplate } = useCreateTemplateMutation()
|
|
20
17
|
const saving = ref(false)
|
|
21
18
|
|
|
@@ -36,7 +33,6 @@ async function handleSave() {
|
|
|
36
33
|
name: store.name,
|
|
37
34
|
category: store.category,
|
|
38
35
|
messages,
|
|
39
|
-
...(appContext.isAdmin && isSystem.value ? { is_system: true } : {}),
|
|
40
36
|
})
|
|
41
37
|
|
|
42
38
|
toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
|
|
@@ -73,14 +69,6 @@ async function handleSave() {
|
|
|
73
69
|
/>
|
|
74
70
|
</template>
|
|
75
71
|
|
|
76
|
-
<ComposerEmailComposer ref="composerRef" mode="create"
|
|
77
|
-
<template #actions>
|
|
78
|
-
<UCheckbox
|
|
79
|
-
v-if="appContext.isAdmin"
|
|
80
|
-
v-model="isSystem"
|
|
81
|
-
:label="$t('templates.system_template')"
|
|
82
|
-
/>
|
|
83
|
-
</template>
|
|
84
|
-
</ComposerEmailComposer>
|
|
72
|
+
<ComposerEmailComposer ref="composerRef" mode="create" />
|
|
85
73
|
</LayoutBasePage>
|
|
86
74
|
</template>
|
|
@@ -38,6 +38,13 @@ const { data: templates, isPending } = useTemplatesQuery(
|
|
|
38
38
|
const { mutateAsync: deleteTemplate } = useDeleteTemplateMutation()
|
|
39
39
|
const { mutateAsync: publishTemplate } = usePublishTemplateMutation()
|
|
40
40
|
const { mutateAsync: unpublishTemplate } = useUnpublishTemplateMutation()
|
|
41
|
+
const promoteTarget = ref<TemplateWithMessageSummary | null>(null)
|
|
42
|
+
const isPromoteModalOpen = computed({
|
|
43
|
+
get: () => promoteTarget.value !== null,
|
|
44
|
+
set: (v) => {
|
|
45
|
+
if (!v) promoteTarget.value = null
|
|
46
|
+
},
|
|
47
|
+
})
|
|
41
48
|
|
|
42
49
|
const tabItems = computed(() => {
|
|
43
50
|
const items = []
|
|
@@ -117,6 +124,16 @@ function rowActions(tmpl: TemplateWithMessageSummary) {
|
|
|
117
124
|
]
|
|
118
125
|
|
|
119
126
|
if (appContext.isAdmin) {
|
|
127
|
+
if (tmpl.user_id !== SYSTEM_USER_ID) {
|
|
128
|
+
actions.push({
|
|
129
|
+
label: t('templates.dialogs.promote.title'),
|
|
130
|
+
icon: 'ph:arrow-fat-up',
|
|
131
|
+
onSelect: () => {
|
|
132
|
+
promoteTarget.value = tmpl
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
120
137
|
if (tmpl.visibility === 'internal') {
|
|
121
138
|
actions.push({
|
|
122
139
|
label: t('common.actions.publish'),
|
|
@@ -240,5 +257,7 @@ function createTemplate() {
|
|
|
240
257
|
</UTable>
|
|
241
258
|
</UCard>
|
|
242
259
|
</div>
|
|
260
|
+
|
|
261
|
+
<TemplateListPromoteModal v-model:open="isPromoteModalOpen" :template="promoteTarget" />
|
|
243
262
|
</LayoutBasePage>
|
|
244
263
|
</template>
|
|
@@ -13,9 +13,6 @@ const toast = useToast()
|
|
|
13
13
|
const { t } = useI18n()
|
|
14
14
|
const { goBackOrFallback } = useGoBack()
|
|
15
15
|
|
|
16
|
-
const appContext = useAppContextStore()
|
|
17
|
-
const isSystem = ref(false)
|
|
18
|
-
|
|
19
16
|
const { mutateAsync: createTemplate } = useCreateTemplateMutation()
|
|
20
17
|
const saving = ref(false)
|
|
21
18
|
|
|
@@ -36,7 +33,6 @@ async function handleSave() {
|
|
|
36
33
|
name: store.name,
|
|
37
34
|
category: store.category,
|
|
38
35
|
messages,
|
|
39
|
-
...(appContext.isAdmin && isSystem.value ? { is_system: true } : {}),
|
|
40
36
|
})
|
|
41
37
|
|
|
42
38
|
toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
|
|
@@ -73,14 +69,6 @@ async function handleSave() {
|
|
|
73
69
|
/>
|
|
74
70
|
</template>
|
|
75
71
|
|
|
76
|
-
<ComposerWhatsappComposer ref="composerRef" mode="create"
|
|
77
|
-
<template #actions>
|
|
78
|
-
<UCheckbox
|
|
79
|
-
v-if="appContext.isAdmin"
|
|
80
|
-
v-model="isSystem"
|
|
81
|
-
:label="$t('templates.system_template')"
|
|
82
|
-
/>
|
|
83
|
-
</template>
|
|
84
|
-
</ComposerWhatsappComposer>
|
|
72
|
+
<ComposerWhatsappComposer ref="composerRef" mode="create" />
|
|
85
73
|
</LayoutBasePage>
|
|
86
74
|
</template>
|
package/app/queries/templates.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
TemplateWithMessageSummary,
|
|
5
5
|
CreateTemplatePayload,
|
|
6
6
|
UpdateTemplatePayload,
|
|
7
|
+
PromoteTemplatePayload,
|
|
7
8
|
} from '@dev.smartpricing/message-composer-utils/types'
|
|
8
9
|
import { templatesApi } from '~/api/templates'
|
|
9
10
|
|
|
@@ -106,6 +107,18 @@ export function useUnpublishTemplateMutation() {
|
|
|
106
107
|
})
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
export function usePromoteTemplateMutation() {
|
|
111
|
+
const queryCache = useQueryCache()
|
|
112
|
+
|
|
113
|
+
return useMutation({
|
|
114
|
+
mutation: ({ id, data }: { id: string; data: PromoteTemplatePayload }) =>
|
|
115
|
+
templatesApi.promote(id, data),
|
|
116
|
+
onSuccess: () => {
|
|
117
|
+
queryCache.invalidateQueries({ key: ['templates'] })
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
109
122
|
export function useSaveAsTemplateMutation() {
|
|
110
123
|
const queryCache = useQueryCache()
|
|
111
124
|
|
package/i18n/locales/de.ts
CHANGED
package/i18n/locales/en.ts
CHANGED
|
@@ -43,6 +43,7 @@ export default {
|
|
|
43
43
|
save: 'Save',
|
|
44
44
|
remove: 'Remove',
|
|
45
45
|
reset_defaults: 'Reset to defaults',
|
|
46
|
+
confirm: 'Confirm',
|
|
46
47
|
},
|
|
47
48
|
internal: 'Internal',
|
|
48
49
|
imageUpload: {
|
|
@@ -860,6 +861,17 @@ These messages must be functional, not promotional.
|
|
|
860
861
|
message: 'Save this message as a reusable template?',
|
|
861
862
|
success: 'Template saved successfully.',
|
|
862
863
|
},
|
|
864
|
+
promote: {
|
|
865
|
+
title: 'Promote to System Template',
|
|
866
|
+
clone_label: 'Clone as System',
|
|
867
|
+
clone_description:
|
|
868
|
+
'Create an independent copy as a system template. The original template stays unchanged.',
|
|
869
|
+
convert_label: 'Convert to System',
|
|
870
|
+
convert_description:
|
|
871
|
+
'This template will become a system template. The original owner will lose ownership. This action cannot be undone.',
|
|
872
|
+
success_clone: '"{name}" cloned as system template.',
|
|
873
|
+
success_convert: '"{name}" promoted to system template.',
|
|
874
|
+
},
|
|
863
875
|
},
|
|
864
876
|
copy_success: 'Message created from template.',
|
|
865
877
|
},
|
package/i18n/locales/es.ts
CHANGED
package/i18n/locales/fr.ts
CHANGED
package/i18n/locales/it.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.smartpricing/message-composer-layer",
|
|
3
|
-
"version": "4.0.2-templates.
|
|
3
|
+
"version": "4.0.2-templates.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"vue-router": "^5.0.7",
|
|
39
39
|
"vue3-emoji-picker": "^1.1.8",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
|
-
"@dev.smartpricing/message-composer-utils": "4.0.3-templates.
|
|
41
|
+
"@dev.smartpricing/message-composer-utils": "4.0.3-templates.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@nuxt/eslint": "^1.15.2",
|