@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.
- package/app/api/index.ts +1 -1
- package/app/api/messageGroups.ts +7 -0
- 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/composables/useTemplateOperations.ts +10 -34
- 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/queries/messageGroups.ts +13 -0
- 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/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...',
|
package/i18n/locales/es.ts
CHANGED
|
@@ -236,7 +236,10 @@ Estos mensajes deben ser funcionales, no promocionales.
|
|
|
236
236
|
email: {
|
|
237
237
|
send_test: 'Enviar prueba',
|
|
238
238
|
send_test_success: 'Correo de prueba enviado correctamente.',
|
|
239
|
+
test_email_to: 'Para',
|
|
239
240
|
test_email_to_placeholder: 'Correo(s) del destinatario, separados por ;',
|
|
241
|
+
test_email_from: 'De',
|
|
242
|
+
test_email_from_placeholder: 'Dirección de email del remitente',
|
|
240
243
|
create_message_group: {
|
|
241
244
|
title: 'Crear mensaje',
|
|
242
245
|
save: 'Guardar',
|
|
@@ -830,47 +833,6 @@ Estos mensajes deben ser funcionales, no promocionales.
|
|
|
830
833
|
no_preview: 'No hay vista previa disponible',
|
|
831
834
|
subject: 'Asunto',
|
|
832
835
|
},
|
|
833
|
-
templates: {
|
|
834
|
-
title: 'Plantillas',
|
|
835
|
-
my_templates: 'Mis plantillas',
|
|
836
|
-
system_templates: 'Plantillas del sistema',
|
|
837
|
-
add_template: 'Nueva plantilla',
|
|
838
|
-
create_template: 'Crear plantilla',
|
|
839
|
-
edit_template: 'Editar plantilla',
|
|
840
|
-
use_template: 'Usar esta plantilla',
|
|
841
|
-
start_from_scratch: 'Empezar desde cero',
|
|
842
|
-
pick_template: 'Elegir una plantilla',
|
|
843
|
-
save_as_template: 'Guardar como plantilla',
|
|
844
|
-
system_template: 'Plantilla de sistema',
|
|
845
|
-
template_name: 'Nombre de plantilla',
|
|
846
|
-
template_name_placeholder: 'Ingrese nombre de plantilla',
|
|
847
|
-
no_templates: 'No hay plantillas disponibles',
|
|
848
|
-
new_message_email: 'Nuevo mensaje de email',
|
|
849
|
-
new_message_whatsapp: 'Nuevo mensaje de WhatsApp',
|
|
850
|
-
dialogs: {
|
|
851
|
-
delete: {
|
|
852
|
-
title: 'Eliminar plantilla',
|
|
853
|
-
message: 'Esta acción no se puede deshacer. ¿Está seguro de que desea eliminar {name}?',
|
|
854
|
-
success: '"{name}" ha sido eliminado.',
|
|
855
|
-
},
|
|
856
|
-
publish: {
|
|
857
|
-
title: 'Publicar plantilla',
|
|
858
|
-
message: '¿Publicar "{name}" para hacerla disponible a todos los usuarios?',
|
|
859
|
-
success: '"{name}" ha sido publicado.',
|
|
860
|
-
},
|
|
861
|
-
unpublish: {
|
|
862
|
-
title: 'Ocultar plantilla',
|
|
863
|
-
message: '¿Ocultar "{name}"? Ya no será visible para otros usuarios.',
|
|
864
|
-
success: '"{name}" ha sido ocultado.',
|
|
865
|
-
},
|
|
866
|
-
save_as_template: {
|
|
867
|
-
title: 'Guardar como plantilla',
|
|
868
|
-
message: '¿Guardar este mensaje como plantilla reutilizable?',
|
|
869
|
-
success: 'Plantilla guardada exitosamente.',
|
|
870
|
-
},
|
|
871
|
-
},
|
|
872
|
-
copy_success: 'Mensaje creado a partir de la plantilla.',
|
|
873
|
-
},
|
|
874
836
|
public: {
|
|
875
837
|
select_message: {
|
|
876
838
|
choose_message: 'Elige un mensaje...',
|
package/i18n/locales/fr.ts
CHANGED
|
@@ -236,7 +236,10 @@ Ces messages doivent être fonctionnels, et non promotionnels.
|
|
|
236
236
|
email: {
|
|
237
237
|
send_test: 'Envoyer un test',
|
|
238
238
|
send_test_success: 'E-mail de test envoyé avec succès.',
|
|
239
|
+
test_email_to: 'À',
|
|
239
240
|
test_email_to_placeholder: 'E-mail(s) du/des destinataire(s), séparé(s) par ;',
|
|
241
|
+
test_email_from: 'De',
|
|
242
|
+
test_email_from_placeholder: "Adresse e-mail de l'expéditeur",
|
|
240
243
|
create_message_group: {
|
|
241
244
|
title: 'Créer un message',
|
|
242
245
|
save: 'Enregistrer',
|
|
@@ -834,47 +837,6 @@ Ces messages doivent être fonctionnels, et non promotionnels.
|
|
|
834
837
|
no_preview: 'Aucun aperçu disponible',
|
|
835
838
|
subject: 'Objet',
|
|
836
839
|
},
|
|
837
|
-
templates: {
|
|
838
|
-
title: 'Modèles',
|
|
839
|
-
my_templates: 'Mes modèles',
|
|
840
|
-
system_templates: 'Modèles système',
|
|
841
|
-
add_template: 'Nouveau modèle',
|
|
842
|
-
create_template: 'Créer un modèle',
|
|
843
|
-
edit_template: 'Modifier le modèle',
|
|
844
|
-
use_template: 'Utiliser ce modèle',
|
|
845
|
-
start_from_scratch: 'Partir de zéro',
|
|
846
|
-
pick_template: 'Choisir un modèle',
|
|
847
|
-
save_as_template: 'Enregistrer comme modèle',
|
|
848
|
-
system_template: 'Modèle système',
|
|
849
|
-
template_name: 'Nom du modèle',
|
|
850
|
-
template_name_placeholder: 'Entrez le nom du modèle',
|
|
851
|
-
no_templates: 'Aucun modèle disponible',
|
|
852
|
-
new_message_email: 'Nouveau message email',
|
|
853
|
-
new_message_whatsapp: 'Nouveau message WhatsApp',
|
|
854
|
-
dialogs: {
|
|
855
|
-
delete: {
|
|
856
|
-
title: 'Supprimer le modèle',
|
|
857
|
-
message: 'Cette action est irréversible. Êtes-vous sûr de vouloir supprimer {name} ?',
|
|
858
|
-
success: '"{name}" a été supprimé.',
|
|
859
|
-
},
|
|
860
|
-
publish: {
|
|
861
|
-
title: 'Publier le modèle',
|
|
862
|
-
message: 'Publier "{name}" pour le rendre accessible à tous les utilisateurs ?',
|
|
863
|
-
success: '"{name}" a été publié.',
|
|
864
|
-
},
|
|
865
|
-
unpublish: {
|
|
866
|
-
title: 'Masquer le modèle',
|
|
867
|
-
message: 'Masquer "{name}" ? Il ne sera plus visible pour les autres utilisateurs.',
|
|
868
|
-
success: '"{name}" a été masqué.',
|
|
869
|
-
},
|
|
870
|
-
save_as_template: {
|
|
871
|
-
title: 'Enregistrer comme modèle',
|
|
872
|
-
message: 'Enregistrer ce message comme modèle réutilisable ?',
|
|
873
|
-
success: 'Modèle enregistré avec succès.',
|
|
874
|
-
},
|
|
875
|
-
},
|
|
876
|
-
copy_success: 'Message créé à partir du modèle.',
|
|
877
|
-
},
|
|
878
840
|
public: {
|
|
879
841
|
select_message: {
|
|
880
842
|
choose_message: 'Choisir un message...',
|
package/i18n/locales/it.ts
CHANGED
|
@@ -236,7 +236,10 @@ Questi messaggi devono essere funzionali, non promozionali.
|
|
|
236
236
|
email: {
|
|
237
237
|
send_test: 'Invia test',
|
|
238
238
|
send_test_success: 'Email di test inviata con successo.',
|
|
239
|
+
test_email_to: 'A',
|
|
239
240
|
test_email_to_placeholder: 'Email destinatario/i, separate da ;',
|
|
241
|
+
test_email_from: 'Da',
|
|
242
|
+
test_email_from_placeholder: 'Indirizzo email mittente',
|
|
240
243
|
create_message_group: {
|
|
241
244
|
title: 'Crea messaggio',
|
|
242
245
|
save: 'Salva',
|
|
@@ -828,47 +831,6 @@ Questi messaggi devono essere funzionali, non promozionali.
|
|
|
828
831
|
no_preview: 'Nessuna anteprima disponibile',
|
|
829
832
|
subject: 'Oggetto',
|
|
830
833
|
},
|
|
831
|
-
templates: {
|
|
832
|
-
title: 'Modelli',
|
|
833
|
-
my_templates: 'I miei modelli',
|
|
834
|
-
system_templates: 'Modelli di sistema',
|
|
835
|
-
add_template: 'Nuovo modello',
|
|
836
|
-
create_template: 'Crea modello',
|
|
837
|
-
edit_template: 'Modifica modello',
|
|
838
|
-
use_template: 'Usa questo modello',
|
|
839
|
-
start_from_scratch: 'Inizia da zero',
|
|
840
|
-
pick_template: 'Scegli un modello',
|
|
841
|
-
save_as_template: 'Salva come modello',
|
|
842
|
-
system_template: 'Modello di sistema',
|
|
843
|
-
template_name: 'Nome modello',
|
|
844
|
-
template_name_placeholder: 'Inserisci nome modello',
|
|
845
|
-
no_templates: 'Nessun modello disponibile',
|
|
846
|
-
new_message_email: 'Nuovo messaggio email',
|
|
847
|
-
new_message_whatsapp: 'Nuovo messaggio WhatsApp',
|
|
848
|
-
dialogs: {
|
|
849
|
-
delete: {
|
|
850
|
-
title: 'Elimina modello',
|
|
851
|
-
message: 'Questa azione non può essere annullata. Sei sicuro di voler eliminare {name}?',
|
|
852
|
-
success: '"{name}" è stato eliminato.',
|
|
853
|
-
},
|
|
854
|
-
publish: {
|
|
855
|
-
title: 'Pubblica modello',
|
|
856
|
-
message: 'Pubblicare "{name}" per renderlo disponibile a tutti gli utenti?',
|
|
857
|
-
success: '"{name}" è stato pubblicato.',
|
|
858
|
-
},
|
|
859
|
-
unpublish: {
|
|
860
|
-
title: 'Nascondi modello',
|
|
861
|
-
message: 'Nascondere "{name}"? Non sarà più visibile agli altri utenti.',
|
|
862
|
-
success: '"{name}" è stato nascosto.',
|
|
863
|
-
},
|
|
864
|
-
save_as_template: {
|
|
865
|
-
title: 'Salva come modello',
|
|
866
|
-
message: 'Salvare questo messaggio come modello riutilizzabile?',
|
|
867
|
-
success: 'Modello salvato con successo.',
|
|
868
|
-
},
|
|
869
|
-
},
|
|
870
|
-
copy_success: 'Messaggio creato dal modello.',
|
|
871
|
-
},
|
|
872
834
|
public: {
|
|
873
835
|
select_message: {
|
|
874
836
|
choose_message: 'Scegli un messaggio...',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.smartpricing/message-composer-layer",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
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.
|
|
41
|
+
"@dev.smartpricing/message-composer-utils": "4.0.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@nuxt/eslint": "^1.15.2",
|
package/app/api/templates.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { TemplateFromDb, RenderType } from '@dev.smartpricing/message-composer-utils/types'
|
|
2
|
-
import type {
|
|
3
|
-
TemplateWithMessages,
|
|
4
|
-
TemplateWithMessageSummary,
|
|
5
|
-
CreateTemplatePayload,
|
|
6
|
-
UpdateTemplatePayload,
|
|
7
|
-
} from '@dev.smartpricing/message-composer-utils/types'
|
|
8
|
-
import { apiClient } from './client'
|
|
9
|
-
|
|
10
|
-
export const templatesApi = {
|
|
11
|
-
getAll: (options?: {
|
|
12
|
-
renderType?: RenderType
|
|
13
|
-
scope?: 'system' | 'mine' | 'all'
|
|
14
|
-
tags?: string[]
|
|
15
|
-
tagsMode?: 'and' | 'or'
|
|
16
|
-
}) => {
|
|
17
|
-
const params = new URLSearchParams()
|
|
18
|
-
if (options?.renderType) params.set('render_type', options.renderType)
|
|
19
|
-
if (options?.scope) params.set('scope', options.scope)
|
|
20
|
-
if (options?.tags && options.tags.length > 0) {
|
|
21
|
-
options.tags.forEach((tag) => params.append('tags', tag))
|
|
22
|
-
}
|
|
23
|
-
if (options?.tagsMode) params.set('tags_mode', options.tagsMode)
|
|
24
|
-
|
|
25
|
-
const query = params.size ? `?${params.toString()}` : ''
|
|
26
|
-
return apiClient<TemplateWithMessageSummary[]>(`/templates${query}`)
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
getById: (id: string) => apiClient<TemplateWithMessages>(`/templates/${id}`),
|
|
30
|
-
|
|
31
|
-
create: (data: CreateTemplatePayload) =>
|
|
32
|
-
apiClient<TemplateFromDb & { tags: string[] }>('/templates', {
|
|
33
|
-
method: 'POST',
|
|
34
|
-
body: data,
|
|
35
|
-
}),
|
|
36
|
-
|
|
37
|
-
update: (id: string, data: UpdateTemplatePayload) =>
|
|
38
|
-
apiClient<TemplateFromDb>(`/templates/${id}`, {
|
|
39
|
-
method: 'PUT',
|
|
40
|
-
body: data,
|
|
41
|
-
}),
|
|
42
|
-
|
|
43
|
-
delete: (id: string) => apiClient(`/templates/${id}`, { method: 'DELETE' }),
|
|
44
|
-
|
|
45
|
-
publish: (id: string) => apiClient<TemplateFromDb>(`/templates/${id}/publish`, { method: 'PUT' }),
|
|
46
|
-
|
|
47
|
-
unpublish: (id: string) =>
|
|
48
|
-
apiClient<TemplateFromDb>(`/templates/${id}/unpublish`, { method: 'PUT' }),
|
|
49
|
-
|
|
50
|
-
saveFromMessageGroup: (messageGroupId: string, name?: string) =>
|
|
51
|
-
apiClient<TemplateFromDb>(`/message-groups/${messageGroupId}/save-as-template`, {
|
|
52
|
-
method: 'POST',
|
|
53
|
-
body: { name },
|
|
54
|
-
}),
|
|
55
|
-
}
|
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { SYSTEM_USER_ID } from '@dev.smartpricing/message-composer-utils/types'
|
|
3
|
-
import type {
|
|
4
|
-
RenderType,
|
|
5
|
-
TemplateWithMessageSummary,
|
|
6
|
-
PostEntity,
|
|
7
|
-
WhatsappMessage,
|
|
8
|
-
EmailMessage,
|
|
9
|
-
BrandFromDb,
|
|
10
|
-
} from '@dev.smartpricing/message-composer-utils/types'
|
|
11
|
-
import type { TemplateWithMessages } from '@dev.smartpricing/message-composer-utils/types'
|
|
12
|
-
import { getEmailEmpty, getWhatsappEmpty } from '@dev.smartpricing/message-composer-utils/utils'
|
|
13
|
-
import { templatesApi } from '~/api/templates'
|
|
14
|
-
|
|
15
|
-
const isOpen = defineModel<boolean>('open', { required: true })
|
|
16
|
-
|
|
17
|
-
const router = useRouter()
|
|
18
|
-
const { t, locale } = useI18n()
|
|
19
|
-
const { mainLanguage } = storeToRefs(useAppContextStore())
|
|
20
|
-
const { allowedRenderTypes, defaultRenderType } = useChannels()
|
|
21
|
-
|
|
22
|
-
const renderType = ref<RenderType>(defaultRenderType.value)
|
|
23
|
-
const selectedId = ref<string>() // undefined = "start from scratch"
|
|
24
|
-
const selectedTemplateData = ref<TemplateWithMessages>()
|
|
25
|
-
const loadingPreview = ref(false)
|
|
26
|
-
const brand = ref<BrandFromDb>()
|
|
27
|
-
|
|
28
|
-
const isFromScratch = computed(() => selectedId.value == null)
|
|
29
|
-
const isEmail = computed(() => renderType.value === 'email_v1')
|
|
30
|
-
|
|
31
|
-
const channelItems = computed(() =>
|
|
32
|
-
allowedRenderTypes.value.map((rt) => ({ label: t(`message.render_type.${rt}`), value: rt })),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
function renderTypeToChannel(rt: RenderType): 'email' | 'whatsapp' {
|
|
36
|
-
return rt === 'email_v1' ? 'email' : 'whatsapp'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Brands query (for email brand selector)
|
|
40
|
-
const { data: brands } = useBrandsQuery()
|
|
41
|
-
|
|
42
|
-
// Templates query
|
|
43
|
-
const { data: templates, isPending: templatesLoading } = useTemplatesQuery(
|
|
44
|
-
computed(() => ({ renderType: renderType.value })),
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
const systemTemplates = computed(() =>
|
|
48
|
-
(templates.value || []).filter((t) => t.user_id === SYSTEM_USER_ID),
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
const myTemplates = computed(() =>
|
|
52
|
-
(templates.value || []).filter((t) => t.user_id !== SYSTEM_USER_ID),
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
// Default empty message for "Start from scratch" preview
|
|
56
|
-
const scratchMessage = computed(() => {
|
|
57
|
-
if (isEmail.value) {
|
|
58
|
-
return getEmailEmpty(mainLanguage.value)
|
|
59
|
-
}
|
|
60
|
-
return getWhatsappEmpty(mainLanguage.value)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
// Preview message: scratch or selected template
|
|
64
|
-
const previewMessage = computed<PostEntity<EmailMessage> | PostEntity<WhatsappMessage> | undefined>(
|
|
65
|
-
() => {
|
|
66
|
-
if (isFromScratch.value) {
|
|
67
|
-
return scratchMessage.value
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!selectedTemplateData.value?.messages?.length) return undefined
|
|
71
|
-
const msgs = selectedTemplateData.value.messages
|
|
72
|
-
const msg =
|
|
73
|
-
msgs.find((m) => m.language_id === locale.value) ||
|
|
74
|
-
msgs.find((m) => m.language_id === 'en') ||
|
|
75
|
-
msgs[0]
|
|
76
|
-
if (!msg) return undefined
|
|
77
|
-
return {
|
|
78
|
-
render_type: msg.render_type,
|
|
79
|
-
body: msg.body,
|
|
80
|
-
metadata: msg.metadata || {},
|
|
81
|
-
language_id: msg.language_id,
|
|
82
|
-
message_group_id: '',
|
|
83
|
-
status: 'draft' as const,
|
|
84
|
-
owner: '',
|
|
85
|
-
user_id: '',
|
|
86
|
-
} as PostEntity<EmailMessage> | PostEntity<WhatsappMessage>
|
|
87
|
-
},
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
// Footer button label
|
|
91
|
-
const actionLabel = computed(() =>
|
|
92
|
-
isFromScratch.value ? t('templates.start_from_scratch') : t('templates.use_template'),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
// Reset on open — pre-select "Start from scratch"
|
|
96
|
-
watch(isOpen, (open) => {
|
|
97
|
-
if (open) {
|
|
98
|
-
selectedId.value = undefined
|
|
99
|
-
selectedTemplateData.value = undefined
|
|
100
|
-
brand.value = undefined
|
|
101
|
-
renderType.value = defaultRenderType.value
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// Reset selection when render type changes
|
|
106
|
-
watch(renderType, () => {
|
|
107
|
-
selectedId.value = undefined
|
|
108
|
-
selectedTemplateData.value = undefined
|
|
109
|
-
brand.value = undefined
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Fetch full template when selected
|
|
113
|
-
watch(selectedId, async (id) => {
|
|
114
|
-
if (!id) {
|
|
115
|
-
selectedTemplateData.value = undefined
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
loadingPreview.value = true
|
|
119
|
-
try {
|
|
120
|
-
selectedTemplateData.value = await templatesApi.getById(id)
|
|
121
|
-
} finally {
|
|
122
|
-
loadingPreview.value = false
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
function selectScratch() {
|
|
127
|
-
selectedId.value = undefined
|
|
128
|
-
selectedTemplateData.value = undefined
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function selectTemplate(tmpl: TemplateWithMessageSummary) {
|
|
132
|
-
selectedId.value = selectedId.value === tmpl.id ? undefined : tmpl.id
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function handleCreate() {
|
|
136
|
-
isOpen.value = false
|
|
137
|
-
const channel = renderTypeToChannel(renderType.value)
|
|
138
|
-
const params = new URLSearchParams()
|
|
139
|
-
if (selectedId.value) params.set('from_template', selectedId.value)
|
|
140
|
-
if (brand.value) params.set('brand_id', brand.value.id)
|
|
141
|
-
const query = params.size ? `?${params.toString()}` : ''
|
|
142
|
-
router.push(`/compose/${channel}/create${query}`)
|
|
143
|
-
}
|
|
144
|
-
</script>
|
|
145
|
-
|
|
146
|
-
<template>
|
|
147
|
-
<USlideover
|
|
148
|
-
v-model:open="isOpen"
|
|
149
|
-
:title="$t('pages.message_library.add_message_group')"
|
|
150
|
-
side="right"
|
|
151
|
-
:ui="{ content: 'max-w-5xl', body: 'sm:p-0 p-0', footer: 'justify-end' }"
|
|
152
|
-
>
|
|
153
|
-
<template #body>
|
|
154
|
-
<div class="grid grid-cols-[1fr_1fr] divide-x divide-muted min-h-full">
|
|
155
|
-
<!-- Left: Controls + Template list -->
|
|
156
|
-
<div class="overflow-y-auto p-6 space-y-4">
|
|
157
|
-
<!-- Channel selector -->
|
|
158
|
-
<USelect v-if="channelItems.length > 1" v-model="renderType" :items="channelItems" />
|
|
159
|
-
|
|
160
|
-
<!-- Brand selector (email only) -->
|
|
161
|
-
<UFormField
|
|
162
|
-
v-if="isEmail && brands?.length"
|
|
163
|
-
:label="$t('editor.email.generalStyle.brandSection')"
|
|
164
|
-
>
|
|
165
|
-
<USelectMenu v-model="brand" labelKey="name" :items="brands" />
|
|
166
|
-
</UFormField>
|
|
167
|
-
|
|
168
|
-
<!-- Start from scratch -->
|
|
169
|
-
<button
|
|
170
|
-
class="flex w-full items-center gap-3 rounded-lg border-2 border-dashed p-3 text-left text-sm transition"
|
|
171
|
-
:class="
|
|
172
|
-
isFromScratch
|
|
173
|
-
? 'border-(--ui-primary) bg-(--ui-primary)/5'
|
|
174
|
-
: 'border-(--ui-border-muted) hover:border-(--ui-border) hover:bg-(--ui-bg-elevated)'
|
|
175
|
-
"
|
|
176
|
-
@click="selectScratch"
|
|
177
|
-
>
|
|
178
|
-
<UIcon name="ph:plus-circle" class="text-xl text-(--ui-text-muted)" />
|
|
179
|
-
<span class="font-medium">{{ $t('templates.start_from_scratch') }}</span>
|
|
180
|
-
</button>
|
|
181
|
-
|
|
182
|
-
<!-- Loading -->
|
|
183
|
-
<div v-if="templatesLoading" class="flex justify-center py-4">
|
|
184
|
-
<UIcon name="ph:spinner" class="animate-spin text-xl text-(--ui-text-muted)" />
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
<template v-else>
|
|
188
|
-
<!-- My Templates -->
|
|
189
|
-
<div v-if="myTemplates.length > 0">
|
|
190
|
-
<h4 class="mb-2 text-xs font-semibold text-(--ui-text-muted) uppercase">
|
|
191
|
-
{{ $t('templates.my_templates') }}
|
|
192
|
-
</h4>
|
|
193
|
-
<div class="space-y-1">
|
|
194
|
-
<button
|
|
195
|
-
v-for="tmpl in myTemplates"
|
|
196
|
-
:key="tmpl.id"
|
|
197
|
-
class="flex w-full items-center justify-between rounded-md p-2.5 text-left text-sm transition"
|
|
198
|
-
:class="
|
|
199
|
-
selectedId === tmpl.id
|
|
200
|
-
? 'bg-(--ui-primary)/10 ring-1 ring-(--ui-primary)'
|
|
201
|
-
: 'hover:bg-(--ui-bg-elevated)'
|
|
202
|
-
"
|
|
203
|
-
@click="selectTemplate(tmpl)"
|
|
204
|
-
>
|
|
205
|
-
<div class="flex items-center gap-2">
|
|
206
|
-
<span>{{ tmpl.name }}</span>
|
|
207
|
-
<UBadge :label="tmpl.category" size="sm" color="neutral" variant="soft" />
|
|
208
|
-
</div>
|
|
209
|
-
<UBadge
|
|
210
|
-
:label="`${tmpl.messages.length} lang`"
|
|
211
|
-
size="sm"
|
|
212
|
-
color="info"
|
|
213
|
-
variant="soft"
|
|
214
|
-
/>
|
|
215
|
-
</button>
|
|
216
|
-
</div>
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
<!-- System Templates -->
|
|
220
|
-
<div v-if="systemTemplates.length > 0">
|
|
221
|
-
<h4 class="mb-2 text-xs font-semibold text-(--ui-text-muted) uppercase">
|
|
222
|
-
{{ $t('templates.system_templates') }}
|
|
223
|
-
</h4>
|
|
224
|
-
<div class="space-y-1">
|
|
225
|
-
<button
|
|
226
|
-
v-for="tmpl in systemTemplates"
|
|
227
|
-
:key="tmpl.id"
|
|
228
|
-
class="flex w-full items-center justify-between rounded-md p-2.5 text-left text-sm transition"
|
|
229
|
-
:class="
|
|
230
|
-
selectedId === tmpl.id
|
|
231
|
-
? 'bg-(--ui-primary)/10 ring-1 ring-(--ui-primary)'
|
|
232
|
-
: 'hover:bg-(--ui-bg-elevated)'
|
|
233
|
-
"
|
|
234
|
-
@click="selectTemplate(tmpl)"
|
|
235
|
-
>
|
|
236
|
-
<div class="flex items-center gap-2">
|
|
237
|
-
<span>{{ tmpl.name }}</span>
|
|
238
|
-
<UBadge :label="tmpl.category" size="sm" color="neutral" variant="soft" />
|
|
239
|
-
</div>
|
|
240
|
-
<UBadge
|
|
241
|
-
:label="`${tmpl.messages.length} lang`"
|
|
242
|
-
size="sm"
|
|
243
|
-
color="info"
|
|
244
|
-
variant="soft"
|
|
245
|
-
/>
|
|
246
|
-
</button>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</template>
|
|
250
|
-
</div>
|
|
251
|
-
|
|
252
|
-
<!-- Right: Preview -->
|
|
253
|
-
<div class="bg-neutral-50 overflow-y-auto">
|
|
254
|
-
<div v-if="loadingPreview" class="flex items-center justify-center h-full">
|
|
255
|
-
<UIcon name="ph:spinner" class="animate-spin text-xl text-(--ui-text-muted)" />
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
<div v-else-if="previewMessage && !isEmail" class="p-6">
|
|
259
|
-
<WhatsappPreview :message="previewMessage as PostEntity<WhatsappMessage>" />
|
|
260
|
-
</div>
|
|
261
|
-
|
|
262
|
-
<div v-else-if="previewMessage && isEmail" class="p-6">
|
|
263
|
-
<EmailInlinePreview
|
|
264
|
-
:message="previewMessage as PostEntity<EmailMessage>"
|
|
265
|
-
:brand="brand"
|
|
266
|
-
/>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
</template>
|
|
271
|
-
|
|
272
|
-
<template #footer>
|
|
273
|
-
<UButton :label="actionLabel" color="primary" @click="handleCreate" />
|
|
274
|
-
</template>
|
|
275
|
-
</USlideover>
|
|
276
|
-
</template>
|