@dev.smartpricing/message-composer-layer 4.0.2-tepmlates.0 → 4.0.3

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 (34) hide show
  1. package/app/api/index.ts +1 -1
  2. package/app/api/messageGroups.ts +7 -0
  3. package/app/api/organization.ts +5 -0
  4. package/app/components/Common/MessagePreviewSlideover.vue +0 -1
  5. package/app/components/Composer/EmailComposer.vue +1 -31
  6. package/app/components/Composer/MessageLibrary.vue +1 -70
  7. package/app/components/Composer/WhatsappComposer.vue +0 -24
  8. package/app/components/CreateTemplateButton.vue +45 -8
  9. package/app/components/Email/InlinePreview.vue +3 -26
  10. package/app/components/Email/SendTestEmailModal.vue +34 -2
  11. package/app/components/TemplateList/BaseTable.vue +0 -7
  12. package/app/composables/composerContext.ts +5 -0
  13. package/app/composables/useTemplateOperations.ts +10 -34
  14. package/app/pages/{compose → template}/email/create.vue +1 -10
  15. package/app/pages/{compose → template}/whatsapp/create.vue +1 -4
  16. package/app/queries/index.ts +0 -1
  17. package/app/queries/messageGroups.ts +13 -0
  18. package/app/utils/testIds.const.ts +0 -1
  19. package/i18n/locales/de.ts +3 -42
  20. package/i18n/locales/en.ts +3 -41
  21. package/i18n/locales/es.ts +3 -41
  22. package/i18n/locales/fr.ts +3 -41
  23. package/i18n/locales/it.ts +3 -41
  24. package/package.json +2 -2
  25. package/app/api/templates.ts +0 -55
  26. package/app/components/Common/NewMessageModal.vue +0 -276
  27. package/app/pages/templates/email/[id].vue +0 -82
  28. package/app/pages/templates/email/create.vue +0 -86
  29. package/app/pages/templates/index.vue +0 -245
  30. package/app/pages/templates/whatsapp/[id].vue +0 -82
  31. package/app/pages/templates/whatsapp/create.vue +0 -86
  32. package/app/queries/templates.ts +0 -119
  33. /package/app/pages/{compose → template}/email/[id].vue +0 -0
  34. /package/app/pages/{compose → template}/whatsapp/[id].vue +0 -0
@@ -1,82 +0,0 @@
1
- <script setup lang="ts">
2
- import type { EmailMessage, PostEntity } from '@dev.smartpricing/message-composer-utils/types'
3
-
4
- definePageMeta({
5
- name: 'email-template-edit',
6
- middleware: ['channel-guard'],
7
- channel: 'email',
8
- })
9
-
10
- const route = useRoute()
11
- const composerRef = useTemplateRef('composerRef')
12
- const store = useEmailComposerStore()
13
- const toast = useToast()
14
- const { t } = useI18n()
15
- const { goBackOrFallback } = useGoBack()
16
-
17
- const templateId = computed(() => route.params.id as string)
18
-
19
- const { mutateAsync: updateTemplate } = useUpdateTemplateMutation()
20
- const saving = ref(false)
21
-
22
- async function handleSave() {
23
- saving.value = true
24
- try {
25
- const messages = Object.values(store.messages).map((msg) => {
26
- const m = msg as PostEntity<EmailMessage>
27
- return {
28
- language_id: m.language_id,
29
- render_type: m.render_type,
30
- body: m.body,
31
- metadata: m.metadata || {},
32
- }
33
- })
34
-
35
- await updateTemplate({
36
- id: templateId.value,
37
- data: {
38
- name: store.name,
39
- category: store.category,
40
- messages,
41
- },
42
- })
43
-
44
- toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
45
- goBackOrFallback()
46
- } finally {
47
- saving.value = false
48
- }
49
- }
50
- </script>
51
-
52
- <template>
53
- <LayoutBasePage
54
- :title="$t('templates.edit_template')"
55
- :tabs="[
56
- { label: $t('pages.email.edit_message_group.tab_content'), value: 'content' },
57
- { label: $t('pages.email.edit_message_group.tab_translations'), value: 'translations' },
58
- ]"
59
- :active-tab="store.activeTab"
60
- @tab-change="store.activeTab = $event as 'content' | 'translations'"
61
- >
62
- <template #actions>
63
- <UButton
64
- @click="composerRef?.handleCancel()"
65
- :label="$t('common.actions.cancel')"
66
- color="primary"
67
- variant="ghost"
68
- :loading="saving || composerRef?.isTranslating"
69
- />
70
- <UButton
71
- @click="handleSave()"
72
- :label="$t('common.actions.save')"
73
- color="primary"
74
- :loading="saving || composerRef?.isTranslating"
75
- />
76
- </template>
77
-
78
- <ComposerEmailComposer ref="composerRef" mode="create" :from-template-id="templateId">
79
- <template #actions></template>
80
- </ComposerEmailComposer>
81
- </LayoutBasePage>
82
- </template>
@@ -1,86 +0,0 @@
1
- <script setup lang="ts">
2
- import type { EmailMessage, PostEntity } from '@dev.smartpricing/message-composer-utils/types'
3
-
4
- definePageMeta({
5
- name: 'email-template-create',
6
- middleware: ['channel-guard'],
7
- channel: 'email',
8
- })
9
-
10
- const composerRef = useTemplateRef('composerRef')
11
- const store = useEmailComposerStore()
12
- const toast = useToast()
13
- const { t } = useI18n()
14
- const { goBackOrFallback } = useGoBack()
15
-
16
- const appContext = useAppContextStore()
17
- const isSystem = ref(false)
18
-
19
- const { mutateAsync: createTemplate } = useCreateTemplateMutation()
20
- const saving = ref(false)
21
-
22
- async function handleSave() {
23
- saving.value = true
24
- try {
25
- const messages = Object.values(store.messages).map((msg) => {
26
- const m = msg as PostEntity<EmailMessage>
27
- return {
28
- language_id: m.language_id,
29
- render_type: m.render_type,
30
- body: m.body,
31
- metadata: m.metadata || {},
32
- }
33
- })
34
-
35
- await createTemplate({
36
- name: store.name,
37
- category: store.category,
38
- messages,
39
- ...(appContext.isAdmin && isSystem.value ? { is_system: true } : {}),
40
- })
41
-
42
- toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
43
- goBackOrFallback()
44
- } finally {
45
- saving.value = false
46
- }
47
- }
48
- </script>
49
-
50
- <template>
51
- <LayoutBasePage
52
- :title="$t('templates.create_template')"
53
- :tabs="[
54
- { label: $t('pages.email.create_message_group.tab_content'), value: 'content' },
55
- { label: $t('pages.email.create_message_group.tab_translations'), value: 'translations' },
56
- ]"
57
- :active-tab="store.activeTab"
58
- @tab-change="store.activeTab = $event as 'content' | 'translations'"
59
- >
60
- <template #actions>
61
- <UButton
62
- @click="composerRef?.handleCancel()"
63
- :label="$t('common.actions.cancel')"
64
- color="primary"
65
- variant="ghost"
66
- :loading="saving || composerRef?.isTranslating"
67
- />
68
- <UButton
69
- @click="handleSave()"
70
- :label="$t('common.actions.save')"
71
- color="primary"
72
- :loading="saving || composerRef?.isTranslating"
73
- />
74
- </template>
75
-
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>
85
- </LayoutBasePage>
86
- </template>
@@ -1,245 +0,0 @@
1
- <script setup lang="ts">
2
- import type { RenderType } from '@dev.smartpricing/message-composer-utils/types'
3
- import { SYSTEM_USER_ID } from '@dev.smartpricing/message-composer-utils/types'
4
- import type { TemplateWithMessageSummary } from '@dev.smartpricing/message-composer-utils/types'
5
- import { formatDate } from '@dev.smartpricing/message-composer-utils/utils'
6
-
7
- definePageMeta({
8
- name: 'template-library',
9
- })
10
-
11
- const router = useRouter()
12
- const { t, locale } = useI18n()
13
- const toast = useToast()
14
- const { hasWhatsapp, hasEmail, defaultRenderType, isRenderTypeAllowed } = useChannels()
15
- const appContext = useAppContextStore()
16
-
17
- // Render type with session persistence
18
- const RENDER_TYPE_KEY = 'template_library_render_type'
19
- const storedRenderType = sessionStorage.getItem(RENDER_TYPE_KEY) as RenderType | null
20
- const initialRenderType =
21
- storedRenderType && isRenderTypeAllowed(storedRenderType)
22
- ? storedRenderType
23
- : defaultRenderType.value
24
- const renderType = ref<RenderType>(initialRenderType)
25
-
26
- watch(renderType, (newType) => {
27
- sessionStorage.setItem(RENDER_TYPE_KEY, newType)
28
- })
29
-
30
- const scope = ref<'all' | 'mine' | 'system'>('all')
31
-
32
- const { data: templates, isPending } = useTemplatesQuery(
33
- computed(() => ({
34
- renderType: renderType.value,
35
- scope: scope.value,
36
- })),
37
- )
38
-
39
- const { mutateAsync: deleteTemplate } = useDeleteTemplateMutation()
40
- const { mutateAsync: publishTemplate } = usePublishTemplateMutation()
41
- const { mutateAsync: unpublishTemplate } = useUnpublishTemplateMutation()
42
-
43
- const tabItems = computed(() => {
44
- const items = []
45
- if (hasWhatsapp.value) {
46
- items.push({
47
- label: t('message.render_type.whatsapp_v1'),
48
- value: 'whatsapp_v1',
49
- slot: 'whatsapp_v1',
50
- })
51
- }
52
- if (hasEmail.value) {
53
- items.push({
54
- label: t('message.render_type.email_v1'),
55
- value: 'email_v1',
56
- slot: 'email_v1',
57
- })
58
- }
59
- return items
60
- })
61
-
62
- const scopeItems = [
63
- { label: 'All', value: 'all' as const },
64
- { label: 'My templates', value: 'mine' as const },
65
- { label: 'System', value: 'system' as const },
66
- ]
67
-
68
- function getLocalizedPreview(tmpl: TemplateWithMessageSummary) {
69
- const msg =
70
- tmpl.messages.find((m) => m.language === locale.value) ||
71
- tmpl.messages.find((m) => m.language === 'en') ||
72
- tmpl.messages[0]
73
- return msg?.preview || ''
74
- }
75
-
76
- function channelFromRenderType(rt: RenderType): 'email' | 'whatsapp' {
77
- return rt === 'email_v1' ? 'email' : 'whatsapp'
78
- }
79
-
80
- function editTemplate(tmpl: TemplateWithMessageSummary) {
81
- const channel = channelFromRenderType(tmpl.messages[0]?.render_type || renderType.value)
82
- router.push(`/templates/${channel}/${tmpl.id}`)
83
- }
84
-
85
- async function handleDelete(tmpl: TemplateWithMessageSummary) {
86
- await deleteTemplate(tmpl.id)
87
- toast.add({ title: t('templates.dialogs.delete.success', { name: tmpl.name }), color: 'success' })
88
- }
89
-
90
- async function handlePublish(tmpl: TemplateWithMessageSummary) {
91
- await publishTemplate(tmpl.id)
92
- toast.add({
93
- title: t('templates.dialogs.publish.success', { name: tmpl.name }),
94
- color: 'success',
95
- })
96
- }
97
-
98
- async function handleUnpublish(tmpl: TemplateWithMessageSummary) {
99
- await unpublishTemplate(tmpl.id)
100
- toast.add({
101
- title: t('templates.dialogs.unpublish.success', { name: tmpl.name }),
102
- color: 'success',
103
- })
104
- }
105
-
106
- function handleUse(tmpl: TemplateWithMessageSummary) {
107
- const channel = channelFromRenderType(tmpl.messages[0]?.render_type || renderType.value)
108
- router.push(`/compose/${channel}/create?from_template=${tmpl.id}`)
109
- }
110
-
111
- function rowActions(tmpl: TemplateWithMessageSummary) {
112
- const actions = [
113
- {
114
- label: t('common.actions.edit'),
115
- icon: 'ph:pencil-simple-line',
116
- onSelect: () => editTemplate(tmpl),
117
- },
118
- ]
119
-
120
- if (appContext.isAdmin) {
121
- if (tmpl.visibility === 'internal') {
122
- actions.push({
123
- label: t('common.actions.publish'),
124
- icon: 'ph:globe',
125
- onSelect: () => handlePublish(tmpl),
126
- })
127
- } else {
128
- actions.push({
129
- label: t('common.actions.unpublish'),
130
- icon: 'ph:globe-x',
131
- onSelect: () => handleUnpublish(tmpl),
132
- })
133
- }
134
- }
135
-
136
- actions.push(
137
- { label: t('templates.use_template'), icon: 'ph:arrow-right', onSelect: () => handleUse(tmpl) },
138
- { label: t('common.actions.delete'), icon: 'ph:trash', onSelect: () => handleDelete(tmpl) },
139
- )
140
-
141
- return actions
142
- }
143
-
144
- function createTemplate() {
145
- const channel = channelFromRenderType(renderType.value)
146
- router.push(`/templates/${channel}/create`)
147
- }
148
- </script>
149
-
150
- <template>
151
- <LayoutBasePage
152
- :title="$t('templates.title')"
153
- :tabs="tabItems.length > 1 ? tabItems : undefined"
154
- :active-tab="renderType"
155
- @tab-change="renderType = $event as RenderType"
156
- >
157
- <template #actions>
158
- <UButton :label="$t('templates.add_template')" color="primary" @click="createTemplate" />
159
- </template>
160
-
161
- <div class="flex-1 space-y-2.5 min-h-0 flex flex-col">
162
- <div class="flex gap-2">
163
- <USelect v-model="scope" :items="scopeItems" class="max-w-48" />
164
- </div>
165
-
166
- <UCard
167
- :ui="{
168
- root: 'flex-1 min-h-0 flex flex-col',
169
- body: 'overflow-auto relative flex-1 p-0 sm:p-0',
170
- }"
171
- >
172
- <UTable
173
- :loading="isPending"
174
- class="flex-1 bg-white"
175
- :ui="{ tr: 'hover:bg-muted', root: 'overflow-visible static' }"
176
- :data="templates || []"
177
- :columns="[
178
- { id: 'name', accessorKey: 'name', header: $t('pages.message_library.headers.name') },
179
- {
180
- id: 'category',
181
- accessorKey: 'category',
182
- header: $t('pages.message_library.headers.category'),
183
- },
184
- {
185
- id: 'preview',
186
- accessorFn: (row: TemplateWithMessageSummary) => getLocalizedPreview(row),
187
- header: $t('pages.message_library.headers.preview'),
188
- },
189
- {
190
- id: 'languages',
191
- accessorFn: (row: TemplateWithMessageSummary) => `${row.messages.length} lang`,
192
- header: 'Languages',
193
- },
194
- {
195
- id: 'updated_at',
196
- accessorFn: (row: TemplateWithMessageSummary) => formatDate(row.updated_at),
197
- header: $t('pages.message_library.headers.updated_at'),
198
- },
199
- {
200
- id: 'actions',
201
- header: '',
202
- enableSorting: false,
203
- meta: { class: { th: 'w-[66px]', td: 'w-[66px]' } },
204
- },
205
- ]"
206
- sticky
207
- >
208
- <template #name-cell="{ row }">
209
- <div class="flex items-center gap-2">
210
- <span>{{ row.original.name }}</span>
211
- <UBadge
212
- v-if="row.original.user_id === SYSTEM_USER_ID"
213
- label="System"
214
- size="sm"
215
- color="info"
216
- variant="soft"
217
- />
218
- <UBadge
219
- v-if="row.original.visibility === 'internal'"
220
- :label="$t('common.internal')"
221
- size="sm"
222
- color="warning"
223
- variant="soft"
224
- />
225
- </div>
226
- </template>
227
-
228
- <template #category-cell="{ row }">
229
- <UBadge :label="row.original.category" size="md" color="neutral" variant="soft" />
230
- </template>
231
-
232
- <template #preview-cell="{ row }">
233
- <div class="line-clamp-2 max-w-[200px] truncate">
234
- {{ getLocalizedPreview(row.original) }}
235
- </div>
236
- </template>
237
-
238
- <template #actions-cell="{ row }">
239
- <SMoreActions :actions="rowActions(row.original)" />
240
- </template>
241
- </UTable>
242
- </UCard>
243
- </div>
244
- </LayoutBasePage>
245
- </template>
@@ -1,82 +0,0 @@
1
- <script setup lang="ts">
2
- import type { WhatsappMessage, PostEntity } from '@dev.smartpricing/message-composer-utils/types'
3
-
4
- definePageMeta({
5
- name: 'whatsapp-template-edit',
6
- middleware: ['channel-guard'],
7
- channel: 'whatsapp',
8
- })
9
-
10
- const route = useRoute()
11
- const composerRef = useTemplateRef('composerRef')
12
- const store = useWhatsappComposerStore()
13
- const toast = useToast()
14
- const { t } = useI18n()
15
- const { goBackOrFallback } = useGoBack()
16
-
17
- const templateId = computed(() => route.params.id as string)
18
-
19
- const { mutateAsync: updateTemplate } = useUpdateTemplateMutation()
20
- const saving = ref(false)
21
-
22
- async function handleSave() {
23
- saving.value = true
24
- try {
25
- const messages = Object.values(store.messages).map((msg) => {
26
- const m = msg as PostEntity<WhatsappMessage>
27
- return {
28
- language_id: m.language_id,
29
- render_type: m.render_type,
30
- body: m.body,
31
- metadata: m.metadata || {},
32
- }
33
- })
34
-
35
- await updateTemplate({
36
- id: templateId.value,
37
- data: {
38
- name: store.name,
39
- category: store.category,
40
- messages,
41
- },
42
- })
43
-
44
- toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
45
- goBackOrFallback()
46
- } finally {
47
- saving.value = false
48
- }
49
- }
50
- </script>
51
-
52
- <template>
53
- <LayoutBasePage
54
- :title="$t('templates.edit_template')"
55
- :tabs="[
56
- { label: $t('pages.whatsapp.tabs.content'), value: 'content' },
57
- { label: $t('pages.whatsapp.tabs.translations'), value: 'translations' },
58
- ]"
59
- :active-tab="store.activeTab"
60
- @tab-change="store.activeTab = $event as 'content' | 'translations'"
61
- >
62
- <template #actions>
63
- <UButton
64
- @click="composerRef?.handleCancel()"
65
- :label="$t('common.actions.cancel')"
66
- color="primary"
67
- variant="ghost"
68
- :loading="saving || composerRef?.isTranslating"
69
- />
70
- <UButton
71
- @click="handleSave()"
72
- :label="$t('common.actions.save')"
73
- color="primary"
74
- :loading="saving || composerRef?.isTranslating"
75
- />
76
- </template>
77
-
78
- <ComposerWhatsappComposer ref="composerRef" mode="create" :from-template-id="templateId">
79
- <template #actions></template>
80
- </ComposerWhatsappComposer>
81
- </LayoutBasePage>
82
- </template>
@@ -1,86 +0,0 @@
1
- <script setup lang="ts">
2
- import type { WhatsappMessage, PostEntity } from '@dev.smartpricing/message-composer-utils/types'
3
-
4
- definePageMeta({
5
- name: 'whatsapp-template-create',
6
- middleware: ['channel-guard'],
7
- channel: 'whatsapp',
8
- })
9
-
10
- const composerRef = useTemplateRef('composerRef')
11
- const store = useWhatsappComposerStore()
12
- const toast = useToast()
13
- const { t } = useI18n()
14
- const { goBackOrFallback } = useGoBack()
15
-
16
- const appContext = useAppContextStore()
17
- const isSystem = ref(false)
18
-
19
- const { mutateAsync: createTemplate } = useCreateTemplateMutation()
20
- const saving = ref(false)
21
-
22
- async function handleSave() {
23
- saving.value = true
24
- try {
25
- const messages = Object.values(store.messages).map((msg) => {
26
- const m = msg as PostEntity<WhatsappMessage>
27
- return {
28
- language_id: m.language_id,
29
- render_type: m.render_type,
30
- body: m.body,
31
- metadata: m.metadata || {},
32
- }
33
- })
34
-
35
- await createTemplate({
36
- name: store.name,
37
- category: store.category,
38
- messages,
39
- ...(appContext.isAdmin && isSystem.value ? { is_system: true } : {}),
40
- })
41
-
42
- toast.add({ title: t('templates.dialogs.save_as_template.success'), color: 'success' })
43
- goBackOrFallback()
44
- } finally {
45
- saving.value = false
46
- }
47
- }
48
- </script>
49
-
50
- <template>
51
- <LayoutBasePage
52
- :title="$t('templates.create_template')"
53
- :tabs="[
54
- { label: $t('pages.whatsapp.tabs.content'), value: 'content' },
55
- { label: $t('pages.whatsapp.tabs.translations'), value: 'translations' },
56
- ]"
57
- :active-tab="store.activeTab"
58
- @tab-change="store.activeTab = $event as 'content' | 'translations'"
59
- >
60
- <template #actions>
61
- <UButton
62
- @click="composerRef?.handleCancel()"
63
- :label="$t('common.actions.cancel')"
64
- color="primary"
65
- variant="ghost"
66
- :loading="saving || composerRef?.isTranslating"
67
- />
68
- <UButton
69
- @click="handleSave()"
70
- :label="$t('common.actions.save')"
71
- color="primary"
72
- :loading="saving || composerRef?.isTranslating"
73
- />
74
- </template>
75
-
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>
85
- </LayoutBasePage>
86
- </template>
@@ -1,119 +0,0 @@
1
- import { useQuery, useMutation, useQueryCache } from '@pinia/colada'
2
- import type { RenderType } from '@dev.smartpricing/message-composer-utils/types'
3
- import type {
4
- TemplateWithMessageSummary,
5
- CreateTemplatePayload,
6
- UpdateTemplatePayload,
7
- } from '@dev.smartpricing/message-composer-utils/types'
8
- import { templatesApi } from '~/api/templates'
9
-
10
- // QUERIES
11
-
12
- export function useTemplatesQuery(
13
- options?: MaybeRefOrGetter<{
14
- renderType?: RenderType
15
- scope?: 'system' | 'mine' | 'all'
16
- tags?: string[]
17
- tagsMode?: 'and' | 'or'
18
- }>,
19
- ) {
20
- return useQuery({
21
- key: () => ['templates', JSON.stringify(toValue(options))],
22
- query: () => templatesApi.getAll(toValue(options)),
23
- staleTime: 0,
24
- })
25
- }
26
-
27
- export function useTemplateQuery(id: MaybeRefOrGetter<string>) {
28
- return useQuery({
29
- key: () => ['templates', toValue(id)],
30
- query: () => templatesApi.getById(toValue(id)),
31
- staleTime: 2 * 60 * 1000,
32
- })
33
- }
34
-
35
- // MUTATIONS
36
-
37
- export function useCreateTemplateMutation() {
38
- const queryCache = useQueryCache()
39
-
40
- return useMutation({
41
- mutation: (data: CreateTemplatePayload) => templatesApi.create(data),
42
- onSuccess: () => {
43
- queryCache.invalidateQueries({ key: ['templates'] })
44
- },
45
- })
46
- }
47
-
48
- export function useUpdateTemplateMutation() {
49
- const queryCache = useQueryCache()
50
-
51
- return useMutation({
52
- mutation: ({ id, data }: { id: string; data: UpdateTemplatePayload }) =>
53
- templatesApi.update(id, data),
54
- onSuccess: (_, { id }) => {
55
- queryCache.invalidateQueries({ key: ['templates', id] })
56
- queryCache.invalidateQueries({ key: ['templates'] })
57
- },
58
- })
59
- }
60
-
61
- export function useDeleteTemplateMutation() {
62
- const queryCache = useQueryCache()
63
-
64
- return useMutation({
65
- mutation: templatesApi.delete,
66
- onMutate: async (id) => {
67
- queryCache.cancelQueries({ key: ['templates'] })
68
- const previous = queryCache.getQueryData(['templates'])
69
-
70
- queryCache.setQueryData(['templates'], (old: TemplateWithMessageSummary[] | undefined) =>
71
- old?.filter((t) => t.id !== id),
72
- )
73
-
74
- return { previous }
75
- },
76
- onError: (_, __, context) => {
77
- if (context?.previous) {
78
- queryCache.setQueryData(['templates'], context.previous)
79
- }
80
- },
81
- onSuccess: () => {
82
- queryCache.invalidateQueries({ key: ['templates'] })
83
- },
84
- })
85
- }
86
-
87
- export function usePublishTemplateMutation() {
88
- const queryCache = useQueryCache()
89
-
90
- return useMutation({
91
- mutation: templatesApi.publish,
92
- onSuccess: () => {
93
- queryCache.invalidateQueries({ key: ['templates'] })
94
- },
95
- })
96
- }
97
-
98
- export function useUnpublishTemplateMutation() {
99
- const queryCache = useQueryCache()
100
-
101
- return useMutation({
102
- mutation: templatesApi.unpublish,
103
- onSuccess: () => {
104
- queryCache.invalidateQueries({ key: ['templates'] })
105
- },
106
- })
107
- }
108
-
109
- export function useSaveAsTemplateMutation() {
110
- const queryCache = useQueryCache()
111
-
112
- return useMutation({
113
- mutation: ({ messageGroupId, name }: { messageGroupId: string; name?: string }) =>
114
- templatesApi.saveFromMessageGroup(messageGroupId, name),
115
- onSuccess: () => {
116
- queryCache.invalidateQueries({ key: ['templates'] })
117
- },
118
- })
119
- }
File without changes