feat(scheduled-messages): add WhatsApp templates (#205)
* feat(scheduled-messages): add WhatsApp templates * fix: update inboxId prop type to accept both Number and String; localize template labels in conversation.json
This commit is contained in:
parent
e84875ca04
commit
da466c88a6
@ -109,6 +109,8 @@ const templateName = computed(() => {
|
||||
return templateParams.name || templateParams.id;
|
||||
});
|
||||
|
||||
const hasTemplate = computed(() => Boolean(templateName.value));
|
||||
|
||||
const attachment = computed(() => props.scheduledMessage?.attachment);
|
||||
const attachmentName = computed(() => attachment.value?.filename);
|
||||
const attachmentUrl = computed(() => attachment.value?.file_url);
|
||||
@ -247,6 +249,20 @@ watch(previewContent, () => {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="hasTemplate"
|
||||
class="flex items-center gap-1.5 text-xs text-n-slate-11"
|
||||
>
|
||||
<Icon icon="i-lucide-zap" class="size-3 shrink-0" />
|
||||
<span class="truncate">
|
||||
{{
|
||||
t('SCHEDULED_MESSAGES.ITEM.TEMPLATE_LABEL', {
|
||||
name: templateName,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="shouldShowAttachmentLine"
|
||||
class="flex items-center gap-1.5 text-xs text-n-slate-11"
|
||||
|
||||
@ -35,6 +35,10 @@ const props = defineProps({
|
||||
return true;
|
||||
},
|
||||
},
|
||||
sendButtonLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['sendMessage', 'resetTemplate', 'back']);
|
||||
@ -43,6 +47,12 @@ const { t } = useI18n();
|
||||
|
||||
const processedParams = ref({});
|
||||
|
||||
const sendButtonText = computed(() => {
|
||||
return (
|
||||
props.sendButtonLabel || t('WHATSAPP_TEMPLATES.PARSER.SEND_MESSAGE_LABEL')
|
||||
);
|
||||
});
|
||||
|
||||
const languageLabel = computed(() => {
|
||||
return `${t('WHATSAPP_TEMPLATES.PARSER.LANGUAGE')}: ${props.template.language || DEFAULT_LANGUAGE}`;
|
||||
});
|
||||
@ -305,6 +315,7 @@ defineExpose({
|
||||
:go-back="goBack"
|
||||
:is-valid="!v$.$invalid"
|
||||
:disabled="isFormInvalid"
|
||||
:send-button-text="sendButtonText"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -12,9 +12,13 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
inboxId: {
|
||||
type: Number,
|
||||
type: [Number, String],
|
||||
default: undefined,
|
||||
},
|
||||
sendButtonLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['onSend', 'cancel', 'update:show'],
|
||||
data() {
|
||||
@ -39,6 +43,13 @@ export default {
|
||||
: this.$t('WHATSAPP_TEMPLATES.MODAL.SUBTITLE');
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
show(newVal) {
|
||||
if (newVal) {
|
||||
this.selectedWaTemplate = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
pickTemplate(template) {
|
||||
this.selectedWaTemplate = template;
|
||||
@ -71,6 +82,7 @@ export default {
|
||||
<WhatsAppTemplateReply
|
||||
v-else
|
||||
:template="selectedWaTemplate"
|
||||
:send-button-label="sendButtonLabel"
|
||||
@reset-template="onResetTemplate"
|
||||
@send-message="onSendMessage"
|
||||
/>
|
||||
|
||||
@ -2,11 +2,15 @@
|
||||
import WhatsAppTemplateParser from 'dashboard/components-next/whatsapp/WhatsAppTemplateParser.vue';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
template: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
sendButtonLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['sendMessage', 'resetTemplate']);
|
||||
@ -23,11 +27,14 @@ const handleResetTemplate = () => {
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<WhatsAppTemplateParser
|
||||
:template="template"
|
||||
:template="props.template"
|
||||
:send-button-label="props.sendButtonLabel"
|
||||
@send-message="handleSendMessage"
|
||||
@reset-template="handleResetTemplate"
|
||||
>
|
||||
<template #actions="{ sendMessage, resetTemplate, disabled }">
|
||||
<template
|
||||
#actions="{ sendMessage, resetTemplate, disabled, sendButtonText }"
|
||||
>
|
||||
<footer class="flex gap-2 justify-end">
|
||||
<NextButton
|
||||
faded
|
||||
@ -38,7 +45,7 @@ const handleResetTemplate = () => {
|
||||
/>
|
||||
<NextButton
|
||||
type="button"
|
||||
:label="$t('WHATSAPP_TEMPLATES.PARSER.SEND_MESSAGE_LABEL')"
|
||||
:label="sendButtonText"
|
||||
:disabled="disabled"
|
||||
@click="sendMessage"
|
||||
/>
|
||||
|
||||
@ -410,6 +410,7 @@
|
||||
"SCHEDULED_FOR": "Scheduled for {time}",
|
||||
"NO_SCHEDULE": "No schedule",
|
||||
"TEMPLATE_PREVIEW": "Template: {name}",
|
||||
"TEMPLATE_LABEL": "Template: {name}",
|
||||
"ATTACHMENT_PREVIEW": "Attachment: {filename}",
|
||||
"ATTACHMENT_LABEL": "Attachment: {filename}",
|
||||
"EMPTY_PREVIEW": "No content",
|
||||
@ -426,6 +427,9 @@
|
||||
"ATTACHMENT_LABEL": "Attachment",
|
||||
"ATTACHMENT_ADD": "Attach file",
|
||||
"ATTACHMENT_CURRENT": "Current attachment: {filename}",
|
||||
"TEMPLATE_SELECT": "Use template",
|
||||
"TEMPLATE_SELECTED": "Template: {name}",
|
||||
"TEMPLATE_ACTION": "Schedule message",
|
||||
"CANCEL": "Cancel",
|
||||
"SAVE_DRAFT": "Save as draft",
|
||||
"SCHEDULE": "Schedule"
|
||||
|
||||
@ -408,7 +408,8 @@
|
||||
"ITEM": {
|
||||
"SCHEDULED_FOR": "Agendada para {time}",
|
||||
"NO_SCHEDULE": "Sem agendamento",
|
||||
"TEMPLATE_PREVIEW": "Template: {name}",
|
||||
"TEMPLATE_PREVIEW": "Modelo: {name}",
|
||||
"TEMPLATE_LABEL": "Modelo: {name}",
|
||||
"ATTACHMENT_PREVIEW": "Anexo: {filename}",
|
||||
"ATTACHMENT_LABEL": "Anexo: {filename}",
|
||||
"EMPTY_PREVIEW": "Sem conteúdo",
|
||||
@ -425,6 +426,9 @@
|
||||
"ATTACHMENT_LABEL": "Anexo",
|
||||
"ATTACHMENT_ADD": "Anexar arquivo",
|
||||
"ATTACHMENT_CURRENT": "Anexo atual: {filename}",
|
||||
"TEMPLATE_SELECT": "Usar modelo",
|
||||
"TEMPLATE_SELECTED": "Modelo: {name}",
|
||||
"TEMPLATE_ACTION": "Agendar mensagem",
|
||||
"CANCEL": "Cancelar",
|
||||
"SAVE_DRAFT": "Salvar como rascunho",
|
||||
"SCHEDULE": "Agendar"
|
||||
|
||||
@ -17,6 +17,7 @@ import DropdownContainer from 'next/dropdown-menu/base/DropdownContainer.vue';
|
||||
import DropdownBody from 'next/dropdown-menu/base/DropdownBody.vue';
|
||||
import DropdownSection from 'next/dropdown-menu/base/DropdownSection.vue';
|
||||
import DropdownItem from 'next/dropdown-menu/base/DropdownItem.vue';
|
||||
import WhatsappTemplates from 'dashboard/components/widgets/conversation/WhatsappTemplates/Modal.vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
@ -59,12 +60,21 @@ const isUpdating = computed(() => uiFlags.value.isUpdating);
|
||||
const isSubmitting = computed(() => isCreating.value || isUpdating.value);
|
||||
const currentInbox = computed(() => inboxGetter.value(props.inboxId));
|
||||
|
||||
const whatsAppTemplates = computed(() => {
|
||||
return store.getters['inboxes/getWhatsAppTemplates'](props.inboxId) || [];
|
||||
});
|
||||
|
||||
const showWhatsappTemplates = computed(() => {
|
||||
return whatsAppTemplates.value.length > 0;
|
||||
});
|
||||
|
||||
const messageContent = ref('');
|
||||
const scheduledDateTime = ref(null);
|
||||
const attachments = ref([]);
|
||||
const existingAttachment = ref(null);
|
||||
const templateParams = ref(null);
|
||||
const showConfirmClose = ref(false);
|
||||
const showWhatsAppTemplatesModal = ref(false);
|
||||
const datePickerOpen = ref(false);
|
||||
const contentError = ref(false);
|
||||
const contentLengthError = ref(false);
|
||||
@ -172,7 +182,18 @@ const hasTemplate = computed(
|
||||
() => templateParams.value && Object.keys(templateParams.value).length
|
||||
);
|
||||
const hasExistingAttachment = computed(() => !!existingAttachment.value);
|
||||
const showAttachmentUpload = computed(() => !hasNewAttachment.value);
|
||||
const showAttachmentUpload = computed(
|
||||
() => !hasNewAttachment.value && !hasTemplate.value
|
||||
);
|
||||
|
||||
const templateName = computed(() => {
|
||||
return templateParams.value?.name || templateParams.value?.id || null;
|
||||
});
|
||||
|
||||
const clearTemplate = () => {
|
||||
templateParams.value = null;
|
||||
messageContent.value = '';
|
||||
};
|
||||
|
||||
const maxLength = computed(() => {
|
||||
const channelType = currentInbox.value?.channel_type;
|
||||
@ -354,6 +375,21 @@ const closeModal = () => {
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const openWhatsAppTemplatesModal = () => {
|
||||
showWhatsAppTemplatesModal.value = true;
|
||||
};
|
||||
|
||||
const hideWhatsAppTemplatesModal = () => {
|
||||
showWhatsAppTemplatesModal.value = false;
|
||||
};
|
||||
|
||||
const onTemplateSelect = messagePayload => {
|
||||
templateParams.value = messagePayload.templateParams;
|
||||
messageContent.value = messagePayload.message;
|
||||
hideWhatsAppTemplatesModal();
|
||||
contentError.value = false;
|
||||
};
|
||||
|
||||
const submit = async status => {
|
||||
if (!validatePayload(status)) return;
|
||||
|
||||
@ -458,14 +494,16 @@ watch(
|
||||
<WootMessageEditor
|
||||
v-model="messageContent"
|
||||
class="message-editor min-h-[10rem] max-h-[20rem] !px-3 resize-y overflow-auto"
|
||||
:class="
|
||||
:class="[
|
||||
contentError || contentLengthError
|
||||
? 'border border-n-ruby-9 rounded-xl'
|
||||
: ''
|
||||
"
|
||||
: '',
|
||||
hasTemplate ? 'opacity-60 cursor-not-allowed' : '',
|
||||
]"
|
||||
:placeholder="t('SCHEDULED_MESSAGES.MODAL.MESSAGE_PLACEHOLDER')"
|
||||
:channel-type="currentInbox?.channel_type"
|
||||
:medium="currentInbox?.medium"
|
||||
:disabled="hasTemplate"
|
||||
override-line-breaks
|
||||
@update:model-value="
|
||||
() => {
|
||||
@ -518,7 +556,7 @@ watch(
|
||||
@change="onDateTimeChange"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="showAttachmentUpload" class="flex items-center h-10">
|
||||
<div v-if="showAttachmentUpload" class="flex items-center gap-2 h-10">
|
||||
<FileUpload
|
||||
:accept="ALLOWED_FILE_TYPES"
|
||||
:multiple="false"
|
||||
@ -534,6 +572,33 @@ watch(
|
||||
class="pointer-events-none"
|
||||
/>
|
||||
</FileUpload>
|
||||
<NextButton
|
||||
v-if="showWhatsappTemplates"
|
||||
ghost
|
||||
xs
|
||||
icon="i-lucide-zap"
|
||||
:label="t('SCHEDULED_MESSAGES.MODAL.TEMPLATE_SELECT')"
|
||||
@click="openWhatsAppTemplatesModal"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasTemplate"
|
||||
class="flex items-center gap-2 text-xs text-n-slate-11"
|
||||
>
|
||||
<span>
|
||||
{{
|
||||
t('SCHEDULED_MESSAGES.MODAL.TEMPLATE_SELECTED', {
|
||||
name: templateName,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<NextButton
|
||||
ghost
|
||||
xs
|
||||
slate
|
||||
icon="i-lucide-x"
|
||||
@click="clearTemplate"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
v-if="existingAttachment && !attachments.length"
|
||||
@ -632,5 +697,13 @@ watch(
|
||||
</div>
|
||||
</div>
|
||||
</woot-modal>
|
||||
|
||||
<WhatsappTemplates
|
||||
v-model:show="showWhatsAppTemplatesModal"
|
||||
:inbox-id="inboxId"
|
||||
:send-button-label="t('SCHEDULED_MESSAGES.MODAL.TEMPLATE_ACTION')"
|
||||
@on-send="onTemplateSelect"
|
||||
@cancel="hideWhatsAppTemplatesModal"
|
||||
/>
|
||||
</woot-modal>
|
||||
</template>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user