-
- {{ `#${conversationId} ` }}
-
+
+ {{ `#${conversationId}` }}
+
{{ $t('SLA_REPORTS.WITH') }}
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmap.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmap.vue
new file mode 100644
index 000000000..3f9dd9db4
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmap.vue
@@ -0,0 +1,214 @@
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmapContainer.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmapContainer.vue
new file mode 100644
index 000000000..2a692b12a
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/BaseHeatmapContainer.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ConversationHeatmapContainer.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ConversationHeatmapContainer.vue
new file mode 100644
index 000000000..394b7cdc2
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ConversationHeatmapContainer.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/HeatmapTooltip.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/HeatmapTooltip.vue
new file mode 100644
index 000000000..79377a6a3
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/HeatmapTooltip.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+ {{ tooltipText }}
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ResolutionHeatmapContainer.vue b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ResolutionHeatmapContainer.vue
new file mode 100644
index 000000000..24530d0c7
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/ResolutionHeatmapContainer.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/composables/useHeatmapTooltip.js b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/composables/useHeatmapTooltip.js
new file mode 100644
index 000000000..28b050542
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/reports/components/heatmaps/composables/useHeatmapTooltip.js
@@ -0,0 +1,34 @@
+import { ref } from 'vue';
+
+export function useHeatmapTooltip() {
+ const visible = ref(false);
+ const x = ref(0);
+ const y = ref(0);
+ const value = ref(null);
+
+ let timeoutId = null;
+
+ const show = (event, cellValue) => {
+ clearTimeout(timeoutId);
+
+ // Update position immediately for smooth movement
+ const rect = event.target.getBoundingClientRect();
+ x.value = rect.left + rect.width / 2;
+ y.value = rect.top;
+
+ // Only delay content update and visibility
+ timeoutId = setTimeout(() => {
+ value.value = cellValue;
+ visible.value = true;
+ }, 100);
+ };
+
+ const hide = () => {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(() => {
+ visible.value = false;
+ }, 50);
+ };
+
+ return { visible, x, y, value, show, hide };
+}
diff --git a/app/javascript/dashboard/store/captain/customTools.js b/app/javascript/dashboard/store/captain/customTools.js
new file mode 100644
index 000000000..3d3af03c0
--- /dev/null
+++ b/app/javascript/dashboard/store/captain/customTools.js
@@ -0,0 +1,35 @@
+import CaptainCustomTools from 'dashboard/api/captain/customTools';
+import { createStore } from './storeFactory';
+import { throwErrorMessage } from 'dashboard/store/utils/api';
+
+export default createStore({
+ name: 'CaptainCustomTool',
+ API: CaptainCustomTools,
+ actions: mutations => ({
+ update: async ({ commit }, { id, ...updateObj }) => {
+ commit(mutations.SET_UI_FLAG, { updatingItem: true });
+ try {
+ const response = await CaptainCustomTools.update(id, updateObj);
+ commit(mutations.EDIT, response.data);
+ commit(mutations.SET_UI_FLAG, { updatingItem: false });
+ return response.data;
+ } catch (error) {
+ commit(mutations.SET_UI_FLAG, { updatingItem: false });
+ return throwErrorMessage(error);
+ }
+ },
+
+ delete: async ({ commit }, id) => {
+ commit(mutations.SET_UI_FLAG, { deletingItem: true });
+ try {
+ await CaptainCustomTools.delete(id);
+ commit(mutations.DELETE, id);
+ commit(mutations.SET_UI_FLAG, { deletingItem: false });
+ return id;
+ } catch (error) {
+ commit(mutations.SET_UI_FLAG, { deletingItem: false });
+ return throwErrorMessage(error);
+ }
+ },
+ }),
+});
diff --git a/app/javascript/dashboard/store/captain/response.js b/app/javascript/dashboard/store/captain/response.js
index 5f8c2eee1..0822b43cd 100644
--- a/app/javascript/dashboard/store/captain/response.js
+++ b/app/javascript/dashboard/store/captain/response.js
@@ -1,9 +1,22 @@
import CaptainResponseAPI from 'dashboard/api/captain/response';
import { createStore } from './storeFactory';
+const SET_PENDING_COUNT = 'SET_PENDING_COUNT';
+
export default createStore({
name: 'CaptainResponse',
API: CaptainResponseAPI,
+ getters: {
+ getPendingCount: state => state.meta.pendingCount || 0,
+ },
+ mutations: {
+ [SET_PENDING_COUNT](state, count) {
+ state.meta = {
+ ...state.meta,
+ pendingCount: Number(count),
+ };
+ },
+ },
actions: mutations => ({
removeBulkResponses: ({ commit, state }, ids) => {
const updatedRecords = state.records.filter(
@@ -28,5 +41,18 @@ export default createStore({
commit(mutations.SET, updatedRecords);
},
+ fetchPendingCount: async ({ commit }, assistantId) => {
+ try {
+ const response = await CaptainResponseAPI.get({
+ status: 'pending',
+ page: 1,
+ assistantId,
+ });
+ const count = response.data?.meta?.total_count || 0;
+ commit(SET_PENDING_COUNT, count);
+ } catch (error) {
+ commit(SET_PENDING_COUNT, 0);
+ }
+ },
}),
});
diff --git a/app/javascript/dashboard/store/captain/storeFactory.js b/app/javascript/dashboard/store/captain/storeFactory.js
index ad669f62b..d57b98862 100644
--- a/app/javascript/dashboard/store/captain/storeFactory.js
+++ b/app/javascript/dashboard/store/captain/storeFactory.js
@@ -49,6 +49,7 @@ export const createMutations = mutationTypes => ({
},
[mutationTypes.SET_META](state, meta) {
state.meta = {
+ ...state.meta,
totalCount: Number(meta.total_count),
page: Number(meta.page),
};
@@ -69,7 +70,7 @@ export const createCrudActions = (API, mutationTypes) => ({
});
export const createStore = options => {
- const { name, API, actions, getters } = options;
+ const { name, API, actions, getters, mutations } = options;
const mutationTypes = generateMutationTypes(name);
const customActions = actions ? actions(mutationTypes) : {};
@@ -81,7 +82,10 @@ export const createStore = options => {
...createGetters(),
...(getters || {}),
},
- mutations: createMutations(mutationTypes),
+ mutations: {
+ ...createMutations(mutationTypes),
+ ...(mutations || {}),
+ },
actions: {
...createCrudActions(API, mutationTypes),
...customActions,
diff --git a/app/javascript/dashboard/store/captain/tools.js b/app/javascript/dashboard/store/captain/tools.js
index 9a9bcc330..9638e45c3 100644
--- a/app/javascript/dashboard/store/captain/tools.js
+++ b/app/javascript/dashboard/store/captain/tools.js
@@ -3,7 +3,7 @@ import CaptainToolsAPI from '../../api/captain/tools';
import { throwErrorMessage } from 'dashboard/store/utils/api';
const toolsStore = createStore({
- name: 'captainTool',
+ name: 'Tools',
API: CaptainToolsAPI,
actions: mutations => ({
getTools: async ({ commit }) => {
diff --git a/app/javascript/dashboard/store/index.js b/app/javascript/dashboard/store/index.js
index 16bcab3f9..d56958eb5 100755
--- a/app/javascript/dashboard/store/index.js
+++ b/app/javascript/dashboard/store/index.js
@@ -57,6 +57,7 @@ import copilotThreads from './captain/copilotThreads';
import copilotMessages from './captain/copilotMessages';
import captainScenarios from './captain/scenarios';
import captainTools from './captain/tools';
+import captainCustomTools from './captain/customTools';
const plugins = [];
@@ -119,6 +120,7 @@ export default createStore({
copilotMessages,
captainScenarios,
captainTools,
+ captainCustomTools,
},
plugins,
});
diff --git a/app/javascript/dashboard/store/modules/conversationStats.js b/app/javascript/dashboard/store/modules/conversationStats.js
index 917781bbf..ba3e5c455 100644
--- a/app/javascript/dashboard/store/modules/conversationStats.js
+++ b/app/javascript/dashboard/store/modules/conversationStats.js
@@ -25,18 +25,18 @@ const fetchMetaData = async (commit, params) => {
}
};
-const debouncedFetchMetaData = debounce(fetchMetaData, 500, false, 1000);
-const longDebouncedFetchMetaData = debounce(fetchMetaData, 500, false, 5000);
+const debouncedFetchMetaData = debounce(fetchMetaData, 500, false, 1500);
+const longDebouncedFetchMetaData = debounce(fetchMetaData, 5000, false, 10000);
const superLongDebouncedFetchMetaData = debounce(
fetchMetaData,
- 1500,
+ 10000,
false,
- 10000
+ 20000
);
export const actions = {
get: async ({ commit, state: $state }, params) => {
- if ($state.allCount > 10000) {
+ if ($state.allCount > 5000) {
superLongDebouncedFetchMetaData(commit, params);
} else if ($state.allCount > 100) {
longDebouncedFetchMetaData(commit, params);
diff --git a/app/javascript/dashboard/store/modules/conversations/helpers/filterHelpers.js b/app/javascript/dashboard/store/modules/conversations/helpers/filterHelpers.js
index 3d627e3ef..96f4a0123 100644
--- a/app/javascript/dashboard/store/modules/conversations/helpers/filterHelpers.js
+++ b/app/javascript/dashboard/store/modules/conversations/helpers/filterHelpers.js
@@ -154,7 +154,10 @@ const equalTo = (filterValue, conversationValue) => {
* It only works with string values and returns false for non-string types.
*/
const contains = (filterValue, conversationValue) => {
- if (typeof conversationValue === 'string') {
+ if (
+ typeof conversationValue === 'string' &&
+ typeof filterValue === 'string'
+ ) {
return conversationValue.toLowerCase().includes(filterValue.toLowerCase());
}
return false;
@@ -190,10 +193,8 @@ const compareDates = (conversationValue, filterValue, compareFn) => {
const matchesCondition = (conversationValue, filter) => {
const { filter_operator: filterOperator, values } = filter;
- // Handle null/undefined values
- if (conversationValue === null || conversationValue === undefined) {
- return filterOperator === 'is_not_present';
- }
+ const isNullish =
+ conversationValue === null || conversationValue === undefined;
const filterValue = Array.isArray(values)
? values.map(resolveValue)
@@ -213,10 +214,10 @@ const matchesCondition = (conversationValue, filter) => {
return !contains(filterValue, conversationValue);
case 'is_present':
- return true; // We already handled null/undefined above
+ return !isNullish;
case 'is_not_present':
- return false; // We already handled null/undefined above
+ return isNullish;
case 'is_greater_than':
return compareDates(conversationValue, filterValue, (a, b) => a > b);
@@ -225,6 +226,10 @@ const matchesCondition = (conversationValue, filter) => {
return compareDates(conversationValue, filterValue, (a, b) => a < b);
case 'days_before': {
+ if (isNullish) {
+ return false;
+ }
+
const today = new Date();
const daysInMilliseconds = filterValue * 24 * 60 * 60 * 1000;
const targetDate = new Date(today.getTime() - daysInMilliseconds);
diff --git a/app/javascript/dashboard/store/modules/conversations/helpers/specs/filterHelpers.spec.js b/app/javascript/dashboard/store/modules/conversations/helpers/specs/filterHelpers.spec.js
index 096481c69..db1017407 100644
--- a/app/javascript/dashboard/store/modules/conversations/helpers/specs/filterHelpers.spec.js
+++ b/app/javascript/dashboard/store/modules/conversations/helpers/specs/filterHelpers.spec.js
@@ -192,6 +192,32 @@ describe('filterHelpers', () => {
expect(matchesFilters(conversation, filters)).toBe(true);
});
+ it('should not match conversation with equal_to operator when assignee is null', () => {
+ const conversation = { meta: { assignee: null } };
+ const filters = [
+ {
+ attribute_key: 'assignee_id',
+ filter_operator: 'equal_to',
+ values: { id: 1, name: 'John Doe' },
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(false);
+ });
+
+ it('should match conversation with not_equal_to operator when assignee is null', () => {
+ const conversation = { meta: { assignee: null } };
+ const filters = [
+ {
+ attribute_key: 'assignee_id',
+ filter_operator: 'not_equal_to',
+ values: { id: 1, name: 'John Doe' },
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(true);
+ });
+
it('should match conversation with is_not_present operator for assignee_id', () => {
const conversation = { meta: { assignee: null } };
const filters = [
@@ -285,6 +311,58 @@ describe('filterHelpers', () => {
expect(matchesFilters(conversation, filters)).toBe(false);
});
+ it('should not match contains operator when display_id is null', () => {
+ const conversation = { id: null };
+ const filters = [
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'contains',
+ values: '234',
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(false);
+ });
+
+ it('should not match contains operator when filter value is null', () => {
+ const conversation = { id: '12345' };
+ const filters = [
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'contains',
+ values: null,
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(false);
+ });
+
+ it('should match does_not_contain operator when display_id is null', () => {
+ const conversation = { id: null };
+ const filters = [
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'does_not_contain',
+ values: '234',
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(true);
+ });
+
+ it('should match does_not_contain operator when filter value is null', () => {
+ const conversation = { id: '12345' };
+ const filters = [
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'does_not_contain',
+ values: null,
+ query_operator: 'and',
+ },
+ ];
+ expect(matchesFilters(conversation, filters)).toBe(true);
+ });
+
it('should match conversation with does_not_contain operator when value is not present', () => {
const conversation = { id: '12345' };
const filters = [
diff --git a/app/javascript/dashboard/store/modules/inboxes.js b/app/javascript/dashboard/store/modules/inboxes.js
index 9886be679..5d788e8ce 100644
--- a/app/javascript/dashboard/store/modules/inboxes.js
+++ b/app/javascript/dashboard/store/modules/inboxes.js
@@ -78,6 +78,11 @@ export const getters = {
return false;
}
+ // Filter out authentication templates
+ if (template.category === 'AUTHENTICATION') {
+ return false;
+ }
+
// Filter out interactive templates (LIST, PRODUCT, CATALOG), location templates, and call permission templates
const hasUnsupportedComponents = template.components.some(
component =>
diff --git a/app/javascript/dashboard/store/modules/reports.js b/app/javascript/dashboard/store/modules/reports.js
index bb5364bb5..99b2acf18 100644
--- a/app/javascript/dashboard/store/modules/reports.js
+++ b/app/javascript/dashboard/store/modules/reports.js
@@ -57,11 +57,13 @@ const state = {
uiFlags: {
isFetchingAccountConversationMetric: false,
isFetchingAccountConversationsHeatmap: false,
+ isFetchingAccountResolutionsHeatmap: false,
isFetchingAgentConversationMetric: false,
isFetchingTeamConversationMetric: false,
},
accountConversationMetric: {},
accountConversationHeatmap: [],
+ accountResolutionHeatmap: [],
agentConversationMetric: [],
teamConversationMetric: [],
},
@@ -89,6 +91,9 @@ const getters = {
getAccountConversationHeatmapData(_state) {
return _state.overview.accountConversationHeatmap;
},
+ getAccountResolutionHeatmapData(_state) {
+ return _state.overview.accountResolutionHeatmap;
+ },
getAgentConversationMetric(_state) {
return _state.overview.agentConversationMetric;
},
@@ -130,6 +135,16 @@ export const actions = {
commit(types.default.TOGGLE_HEATMAP_LOADING, false);
});
},
+ fetchAccountResolutionHeatmap({ commit }, reportObj) {
+ commit(types.default.TOGGLE_RESOLUTION_HEATMAP_LOADING, true);
+ Report.getReports({ ...reportObj, groupBy: 'hour' }).then(heatmapData => {
+ let { data } = heatmapData;
+ data = clampDataBetweenTimeline(data, reportObj.from, reportObj.to);
+
+ commit(types.default.SET_RESOLUTION_HEATMAP_DATA, data);
+ commit(types.default.TOGGLE_RESOLUTION_HEATMAP_LOADING, false);
+ });
+ },
fetchAccountSummary({ commit }, reportObj) {
commit(types.default.SET_ACCOUNT_SUMMARY_STATUS, STATUS.FETCHING);
Report.getSummary(
@@ -287,6 +302,9 @@ const mutations = {
[types.default.SET_HEATMAP_DATA](_state, heatmapData) {
_state.overview.accountConversationHeatmap = heatmapData;
},
+ [types.default.SET_RESOLUTION_HEATMAP_DATA](_state, heatmapData) {
+ _state.overview.accountResolutionHeatmap = heatmapData;
+ },
[types.default.TOGGLE_ACCOUNT_REPORT_LOADING](_state, { metric, value }) {
_state.accountReport.isFetching[metric] = value;
},
@@ -299,6 +317,9 @@ const mutations = {
[types.default.TOGGLE_HEATMAP_LOADING](_state, flag) {
_state.overview.uiFlags.isFetchingAccountConversationsHeatmap = flag;
},
+ [types.default.TOGGLE_RESOLUTION_HEATMAP_LOADING](_state, flag) {
+ _state.overview.uiFlags.isFetchingAccountResolutionsHeatmap = flag;
+ },
[types.default.SET_ACCOUNT_SUMMARY](_state, summaryData) {
_state.accountSummary = summaryData;
},
diff --git a/app/javascript/dashboard/store/modules/specs/inboxes/getters.spec.js b/app/javascript/dashboard/store/modules/specs/inboxes/getters.spec.js
index eeb52b1dc..ac2aab26b 100644
--- a/app/javascript/dashboard/store/modules/specs/inboxes/getters.spec.js
+++ b/app/javascript/dashboard/store/modules/specs/inboxes/getters.spec.js
@@ -265,6 +265,39 @@ describe('#getters', () => {
expect(result[0].name).toBe('regular_template');
});
+ it('filters out authentication templates', () => {
+ const authenticationTemplates = [
+ {
+ name: 'auth_template',
+ status: 'approved',
+ category: 'AUTHENTICATION',
+ components: [
+ { type: 'BODY', text: 'Your verification code is {{1}}' },
+ ],
+ },
+ {
+ name: 'regular_template',
+ status: 'approved',
+ category: 'MARKETING',
+ components: [{ type: 'BODY', text: 'Regular message' }],
+ },
+ ];
+
+ const state = {
+ records: [
+ {
+ id: 1,
+ channel_type: 'Channel::Whatsapp',
+ message_templates: authenticationTemplates,
+ },
+ ],
+ };
+
+ const result = getters.getFilteredWhatsAppTemplates(state)(1);
+ expect(result).toHaveLength(1);
+ expect(result[0].name).toBe('regular_template');
+ });
+
it('returns valid templates from fixture data', () => {
const state = {
records: [
diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js
index f15ec714f..996122ce5 100644
--- a/app/javascript/dashboard/store/mutation-types.js
+++ b/app/javascript/dashboard/store/mutation-types.js
@@ -188,6 +188,8 @@ export default {
SET_ACCOUNT_REPORTS: 'SET_ACCOUNT_REPORTS',
SET_HEATMAP_DATA: 'SET_HEATMAP_DATA',
TOGGLE_HEATMAP_LOADING: 'TOGGLE_HEATMAP_LOADING',
+ SET_RESOLUTION_HEATMAP_DATA: 'SET_RESOLUTION_HEATMAP_DATA',
+ TOGGLE_RESOLUTION_HEATMAP_LOADING: 'TOGGLE_RESOLUTION_HEATMAP_LOADING',
SET_ACCOUNT_SUMMARY: 'SET_ACCOUNT_SUMMARY',
SET_BOT_SUMMARY: 'SET_BOT_SUMMARY',
TOGGLE_ACCOUNT_REPORT_LOADING: 'TOGGLE_ACCOUNT_REPORT_LOADING',
diff --git a/app/javascript/shared/constants/links.js b/app/javascript/shared/constants/links.js
index b9732c0a2..94d3de3f6 100644
--- a/app/javascript/shared/constants/links.js
+++ b/app/javascript/shared/constants/links.js
@@ -6,3 +6,5 @@ export const REPLY_POLICY = {
WHATSAPP_CLOUD:
'https://business.whatsapp.com/policy#:~:text=You%20may%20reply%20to%20a,messages%20via%20approved%20Message%20Templates.',
};
+
+export const CHANGELOG_API_URL = 'https://hub.2.chatwoot.com/changelogs';
diff --git a/app/javascript/survey/i18n/locale/bn.json b/app/javascript/survey/i18n/locale/bn.json
new file mode 100644
index 000000000..beee65ac5
--- /dev/null
+++ b/app/javascript/survey/i18n/locale/bn.json
@@ -0,0 +1,19 @@
+{
+ "SURVEY": {
+ "DESCRIPTION": "Dear customer 👋, please take a few moments to share feedback about the conversation you had with {inboxName}.",
+ "RATING": {
+ "LABEL": "Rate your conversation",
+ "SUCCESS_MESSAGE": "Thank you for submitting the rating"
+ },
+ "FEEDBACK": {
+ "LABEL": "Do you have any thoughts you'd like to share?",
+ "PLACEHOLDER": "Your feedback (optional)",
+ "BUTTON_TEXT": "Submit feedback"
+ },
+ "API": {
+ "SUCCESS_MESSAGE": "Survey updated successfully",
+ "ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later"
+ }
+ },
+ "POWERED_BY": "Powered by Chatwoot"
+}
diff --git a/app/javascript/survey/i18n/locale/et.json b/app/javascript/survey/i18n/locale/et.json
new file mode 100644
index 000000000..beee65ac5
--- /dev/null
+++ b/app/javascript/survey/i18n/locale/et.json
@@ -0,0 +1,19 @@
+{
+ "SURVEY": {
+ "DESCRIPTION": "Dear customer 👋, please take a few moments to share feedback about the conversation you had with {inboxName}.",
+ "RATING": {
+ "LABEL": "Rate your conversation",
+ "SUCCESS_MESSAGE": "Thank you for submitting the rating"
+ },
+ "FEEDBACK": {
+ "LABEL": "Do you have any thoughts you'd like to share?",
+ "PLACEHOLDER": "Your feedback (optional)",
+ "BUTTON_TEXT": "Submit feedback"
+ },
+ "API": {
+ "SUCCESS_MESSAGE": "Survey updated successfully",
+ "ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later"
+ }
+ },
+ "POWERED_BY": "Powered by Chatwoot"
+}
diff --git a/app/javascript/v3/components/GoogleOauth/Button.vue b/app/javascript/v3/components/GoogleOauth/Button.vue
index c6214e9c3..2d1fc5a4e 100644
--- a/app/javascript/v3/components/GoogleOauth/Button.vue
+++ b/app/javascript/v3/components/GoogleOauth/Button.vue
@@ -34,7 +34,7 @@ export default {