diff --git a/app/javascript/dashboard/api/inboxes.js b/app/javascript/dashboard/api/inboxes.js index 361b9472f..675616ec7 100644 --- a/app/javascript/dashboard/api/inboxes.js +++ b/app/javascript/dashboard/api/inboxes.js @@ -32,6 +32,16 @@ class Inboxes extends CacheEnabledApiClient { syncTemplates(inboxId) { return axios.post(`${this.url}/${inboxId}/sync_templates`); } + + createCSATTemplate(inboxId, template) { + return axios.post(`${this.url}/${inboxId}/create_csat_template`, { + template, + }); + } + + getCSATTemplateStatus(inboxId) { + return axios.get(`${this.url}/${inboxId}/csat_template_status`); + } } export default new Inboxes(); diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index 87fe57564..188153e58 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -792,6 +792,23 @@ "LABEL": "Message", "PLACEHOLDER": "Please enter a message to show users with the form" }, + "BUTTON_TEXT": { + "LABEL": "Button text", + "PLACEHOLDER": "Please rate us" + }, + "MESSAGE_PREVIEW": { + "LABEL": "Message preview", + "TOOLTIP": "This may vary slightly when rendered on WhatsApp's platform." + }, + "TEMPLATE_STATUS": { + "APPROVED": "Approved by WhatsApp", + "PENDING": "Needs WhatsApp approval", + "REJECTED": "Rejected by WhatsApp" + }, + "TEMPLATE_CREATION": { + "SUCCESS_MESSAGE": "WhatsApp template created successfully and sent for approval", + "ERROR_MESSAGE": "Failed to create WhatsApp template" + }, "SURVEY_RULE": { "LABEL": "Survey rule", "DESCRIPTION_PREFIX": "Send the survey if the conversation", diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/CustomerSatisfactionPage.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/CustomerSatisfactionPage.vue index 807f1ad0f..b8812e773 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/CustomerSatisfactionPage.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/CustomerSatisfactionPage.vue @@ -8,10 +8,12 @@ import { CSAT_DISPLAY_TYPES } from 'shared/constants/messages'; import WithLabel from 'v3/components/Form/WithLabel.vue'; import SectionLayout from 'dashboard/routes/dashboard/settings/account/components/SectionLayout.vue'; import CSATDisplayTypeSelector from './components/CSATDisplayTypeSelector.vue'; +import CSATTemplate from './components/CSATTemplate.vue'; import Editor from 'dashboard/components-next/Editor/Editor.vue'; import FilterSelect from 'dashboard/components-next/filter/inputs/FilterSelect.vue'; import NextButton from 'dashboard/components-next/button/Button.vue'; import Switch from 'next/switch/Switch.vue'; +import Input from 'v3/components/Form/Input.vue'; const props = defineProps({ inbox: { type: Object, required: true }, @@ -29,9 +31,14 @@ const state = reactive({ csatSurveyEnabled: false, displayType: 'emoji', message: '', + buttonText: 'Please rate us', surveyRuleOperator: 'contains', }); +// WhatsApp template status +const templateStatus = ref(null); +const templateLoading = ref(false); + const filterTypes = [ { label: t('INBOX_MGMT.CSAT.SURVEY_RULE.OPERATOR.CONTAINS'), @@ -51,6 +58,45 @@ const labelOptions = computed(() => : [] ); +const isWhatsAppChannel = computed( + () => props.inbox?.channel_type === 'Channel::Whatsapp' +); + +const messagePreviewData = computed(() => ({ + content: state.message || t('INBOX_MGMT.CSAT.MESSAGE.PLACEHOLDER'), +})); + +const templateApprovalStatus = computed(() => { + if (!templateStatus.value) return null; + + switch (templateStatus.value.status) { + case 'APPROVED': + return { + text: t('INBOX_MGMT.CSAT.TEMPLATE_STATUS.APPROVED'), + icon: 'i-lucide-check-circle', + color: 'text-green-600', + }; + case 'PENDING': + return { + text: t('INBOX_MGMT.CSAT.TEMPLATE_STATUS.PENDING'), + icon: 'i-lucide-clock', + color: 'text-yellow-600', + }; + case 'REJECTED': + return { + text: t('INBOX_MGMT.CSAT.TEMPLATE_STATUS.REJECTED'), + icon: 'i-lucide-x-circle', + color: 'text-red-600', + }; + default: + return { + text: t('INBOX_MGMT.CSAT.TEMPLATE_STATUS.PENDING'), + icon: 'i-lucide-clock', + color: 'text-yellow-600', + }; + } +}); + const initializeState = () => { if (!props.inbox) return; @@ -63,11 +109,13 @@ const initializeState = () => { const { display_type: displayType = CSAT_DISPLAY_TYPES.EMOJI, message = '', + button_text: buttonText = 'Please rate us', survey_rules: surveyRules = {}, } = csat_config; state.displayType = displayType; state.message = message; + state.buttonText = buttonText; state.surveyRuleOperator = surveyRules.operator || 'contains'; selectedLabelValues.value = Array.isArray(surveyRules.values) @@ -75,9 +123,26 @@ const initializeState = () => { : []; }; +const checkTemplateStatus = async () => { + if (!isWhatsAppChannel.value) return; + + try { + templateLoading.value = true; + const response = await store.dispatch('inboxes/getCSATTemplateStatus', { + inboxId: props.inbox.id, + }); + templateStatus.value = response.data; + } catch (error) { + // console.error('Error fetching template status:', error); + } finally { + templateLoading.value = false; + } +}; + onMounted(() => { initializeState(); if (!labels.value?.length) store.dispatch('labels/get'); + if (isWhatsAppChannel.value) checkTemplateStatus(); }); watch(() => props.inbox, initializeState, { immediate: true }); @@ -115,13 +180,45 @@ const updateInbox = async attributes => { return store.dispatch('inboxes/updateInbox', payload); }; +const createTemplate = async () => { + if (!isWhatsAppChannel.value) return; + + try { + isUpdating.value = true; + await store.dispatch('inboxes/createCSATTemplate', { + inboxId: props.inbox.id, + template: { + message: state.message, + button_text: state.buttonText, + }, + }); + + // Check status after creation + await checkTemplateStatus(); + useAlert(t('INBOX_MGMT.CSAT.TEMPLATE_CREATION.SUCCESS_MESSAGE')); + } catch (error) { + const errorMessage = + error.response?.data?.error || + t('INBOX_MGMT.CSAT.TEMPLATE_CREATION.ERROR_MESSAGE'); + useAlert(errorMessage); + } finally { + isUpdating.value = false; + } +}; + const saveSettings = async () => { try { isUpdating.value = true; + // For WhatsApp channels, create template first if needed + if (isWhatsAppChannel.value && state.csatSurveyEnabled) { + await createTemplate(); + } + const csatConfig = { display_type: state.displayType, message: state.message, + button_text: state.buttonText, survey_rules: { operator: state.surveyRuleOperator, values: selectedLabelValues.value, @@ -155,7 +252,9 @@ const saveSettings = async () => {
+ @@ -165,14 +264,86 @@ const saveSettings = async () => { /> - - - + + + + + { >
{{ $t('INBOX_MGMT.CSAT.SURVEY_RULE.DESCRIPTION_PREFIX') }} { + const response = await InboxesAPI.createCSATTemplate(inboxId, template); + return response.data; + }, + getCSATTemplateStatus: async (_, { inboxId }) => { + const response = await InboxesAPI.getCSATTemplateStatus(inboxId); + return response.data; + }, }; export const mutations = {