Compare commits
99
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
523769b7ed | ||
|
|
2a8d7e55c6 | ||
|
|
0826275618 | ||
|
|
5151e33ac2 | ||
|
|
799dfab0dd | ||
|
|
62474bca23 | ||
|
|
bca270bb17 | ||
|
|
545e352d13 | ||
|
|
98fa2957a1 | ||
|
|
66e53d7408 | ||
|
|
daa660ca44 | ||
|
|
1fcdf42cc8 | ||
|
|
dca97875a7 | ||
|
|
743cb99d30 | ||
|
|
6aa03b3ce1 | ||
|
|
d9c918253d | ||
|
|
227be4df58 | ||
|
|
081e25395b | ||
|
|
b80c825b7c | ||
|
|
7fc14c2f1d | ||
|
|
0b2477c47e | ||
|
|
51ab7d4f9e | ||
|
|
16bc70b6dc | ||
|
|
d3d2e361b2 | ||
|
|
a55ec03eb1 | ||
|
|
fd6375fc6c | ||
|
|
34ca9868a5 | ||
|
|
29007de112 | ||
|
|
1b045c499c | ||
|
|
cef0491d15 | ||
|
|
e1d0b56557 | ||
|
|
8742ef67db | ||
|
|
af3c55937b | ||
|
|
cfd8a32337 | ||
|
|
48fef92dbb | ||
|
|
03b81a1ead | ||
|
|
7f520535dd | ||
|
|
f2946a8a3f | ||
|
|
b651f5ec92 | ||
|
|
3119f6cbf5 | ||
|
|
96ab20b756 | ||
|
|
ca465f0f3b | ||
|
|
063d216247 | ||
|
|
41a92c575f | ||
|
|
1321a79b4c | ||
|
|
b316b47f74 | ||
|
|
602b0d19ca | ||
|
|
a52e93bf50 | ||
|
|
c84c4492f0 | ||
|
|
a3229cee99 | ||
|
|
b92f7536d2 | ||
|
|
89311b54d5 | ||
|
|
ecb0b4a4f4 | ||
|
|
2ef9274450 | ||
|
|
3ce70f4e14 | ||
|
|
0008fca511 | ||
|
|
fede03ebe8 | ||
|
|
9ef3e8ab74 | ||
|
|
63f8a49107 | ||
|
|
2f46f337f0 | ||
|
|
5695eafa29 | ||
|
|
1bd654a8c5 | ||
|
|
ded2a72476 | ||
|
|
55d6b0ce86 | ||
|
|
61ba2c8499 | ||
|
|
893c88fb2d | ||
|
|
8b57bcdd02 | ||
|
|
004110f4c7 | ||
|
|
cf063e14d4 | ||
|
|
1f241e4546 | ||
|
|
3ebf219ffa | ||
|
|
ff92e6ef63 | ||
|
|
b5bdb00e44 | ||
|
|
45ff41a6ae | ||
|
|
c8739caaa6 | ||
|
|
cd078ca5ce | ||
|
|
6317421894 | ||
|
|
60e72b0c3d | ||
|
|
86c5884f0a | ||
|
|
6bd1fe1c10 | ||
|
|
8626590386 | ||
|
|
7fe8b14539 | ||
|
|
c119084818 | ||
|
|
e4849a0d4b | ||
|
|
bd09f6ce40 | ||
|
|
54ed5e44bc | ||
|
|
ce16558df4 | ||
|
|
fbd95ff44a | ||
|
|
7f15d8cbf2 | ||
|
|
353e2d0330 | ||
|
|
2a2cd30c6b | ||
|
|
9aeccf63c4 | ||
|
|
1361c921de | ||
|
|
eeac9252fb | ||
|
|
624d61913c | ||
|
|
29c2b8576c | ||
|
|
0c969bf318 | ||
|
|
28d9c2615d | ||
|
|
e0ddeb4ee6 |
@@ -1,127 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
import { utcToZonedTime } from 'date-fns-tz';
|
||||
import { isTimeAfter } from 'shared/helpers/DateHelper';
|
||||
|
||||
/**
|
||||
* Composable for handling availability-related computations.
|
||||
* @param {Object} i18n - Vue i18n instance for translations.
|
||||
* @param {Object} availableAgents - Available agents object.
|
||||
* @returns {Object} An object containing computed properties and methods for availability management.
|
||||
*/
|
||||
export function useAvailability(availableAgents, i18n) {
|
||||
const channelConfig = computed(() => window.chatwootWebChannel);
|
||||
const replyTime = computed(() => window.chatwootWebChannel.replyTime);
|
||||
|
||||
const replyTimeStatus = computed(() => {
|
||||
switch (replyTime.value) {
|
||||
case 'in_a_few_minutes':
|
||||
return i18n.t('REPLY_TIME.IN_A_FEW_MINUTES');
|
||||
case 'in_a_few_hours':
|
||||
return i18n.t('REPLY_TIME.IN_A_FEW_HOURS');
|
||||
case 'in_a_day':
|
||||
return i18n.t('REPLY_TIME.IN_A_DAY');
|
||||
default:
|
||||
return i18n.t('REPLY_TIME.IN_A_FEW_HOURS');
|
||||
}
|
||||
});
|
||||
|
||||
const isOnline = computed(() => {
|
||||
const { workingHoursEnabled } = channelConfig.value;
|
||||
const anyAgentOnline = availableAgents.value.length > 0;
|
||||
if (workingHoursEnabled) {
|
||||
return isInBetweenTheWorkingHours.value;
|
||||
}
|
||||
return anyAgentOnline;
|
||||
});
|
||||
|
||||
const replyWaitMessage = computed(() => {
|
||||
const { workingHoursEnabled } = channelConfig.value;
|
||||
if (workingHoursEnabled) {
|
||||
return isOnline.value
|
||||
? replyTimeStatus.value
|
||||
: `${i18n.t('REPLY_TIME.BACK_IN')} ${timeLeftToBackInOnline.value}`;
|
||||
}
|
||||
return isOnline.value
|
||||
? replyTimeStatus.value
|
||||
: i18n.t('TEAM_AVAILABILITY.OFFLINE');
|
||||
});
|
||||
|
||||
const outOfOfficeMessage = computed(
|
||||
() => channelConfig.value.outOfOfficeMessage
|
||||
);
|
||||
|
||||
const currentDayAvailability = computed(() => {
|
||||
const { utcOffset } = channelConfig.value;
|
||||
const dayOfTheWeek = getDateWithOffset(utcOffset).getDay();
|
||||
const [workingHourConfig = {}] = channelConfig.value.workingHours.filter(
|
||||
workingHour => workingHour.day_of_week === dayOfTheWeek
|
||||
);
|
||||
return {
|
||||
closedAllDay: workingHourConfig.closed_all_day,
|
||||
openHour: workingHourConfig.open_hour,
|
||||
openMinute: workingHourConfig.open_minutes,
|
||||
closeHour: workingHourConfig.close_hour,
|
||||
closeMinute: workingHourConfig.close_minutes,
|
||||
openAllDay: workingHourConfig.open_all_day,
|
||||
};
|
||||
});
|
||||
|
||||
const isInBetweenTheWorkingHours = computed(() => {
|
||||
const {
|
||||
openHour,
|
||||
openMinute,
|
||||
closeHour,
|
||||
closeMinute,
|
||||
closedAllDay,
|
||||
openAllDay,
|
||||
} = currentDayAvailability.value;
|
||||
|
||||
if (openAllDay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (closedAllDay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { utcOffset } = channelConfig.value;
|
||||
const today = getDateWithOffset(utcOffset);
|
||||
const currentHours = today.getHours();
|
||||
const currentMinutes = today.getMinutes();
|
||||
const isAfterStartTime = isTimeAfter(
|
||||
currentHours,
|
||||
currentMinutes,
|
||||
openHour,
|
||||
openMinute
|
||||
);
|
||||
const isBeforeEndTime = isTimeAfter(
|
||||
closeHour,
|
||||
closeMinute,
|
||||
currentHours,
|
||||
currentMinutes
|
||||
);
|
||||
return isAfterStartTime && isBeforeEndTime;
|
||||
});
|
||||
|
||||
const isInBusinessHours = computed(() => {
|
||||
const { workingHoursEnabled } = channelConfig.value;
|
||||
return workingHoursEnabled ? isInBetweenTheWorkingHours.value : true;
|
||||
});
|
||||
|
||||
const getDateWithOffset = utcOffset => {
|
||||
return utcToZonedTime(new Date().toISOString(), utcOffset);
|
||||
};
|
||||
|
||||
return {
|
||||
channelConfig,
|
||||
replyTime,
|
||||
replyTimeStatus,
|
||||
replyWaitMessage,
|
||||
outOfOfficeMessage,
|
||||
currentDayAvailability,
|
||||
isInBetweenTheWorkingHours,
|
||||
isInBusinessHours,
|
||||
isOnline,
|
||||
getDateWithOffset,
|
||||
};
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { CAMPAIGN_TYPES } from '../constants/campaign';
|
||||
|
||||
/**
|
||||
* Composable for handling campaign-related computations.
|
||||
* @returns {Object} An object containing computed properties for campaign types.
|
||||
*/
|
||||
export function useCampaign() {
|
||||
const route = useRoute();
|
||||
|
||||
const campaignType = computed(() => {
|
||||
const campaignTypeMap = {
|
||||
ongoing_campaigns: CAMPAIGN_TYPES.ONGOING,
|
||||
one_off: CAMPAIGN_TYPES.ONE_OFF,
|
||||
};
|
||||
return campaignTypeMap[route.name];
|
||||
});
|
||||
|
||||
const isOngoingType = computed(
|
||||
() => campaignType.value === CAMPAIGN_TYPES.ONGOING
|
||||
);
|
||||
const isOneOffType = computed(
|
||||
() => campaignType.value === CAMPAIGN_TYPES.ONE_OFF
|
||||
);
|
||||
|
||||
return {
|
||||
campaignType,
|
||||
isOngoingType,
|
||||
isOneOffType,
|
||||
};
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
/**
|
||||
* Composable for accessing Chatwoot configuration values.
|
||||
* @returns {Object} An object containing computed properties for various Chatwoot configuration values.
|
||||
*/
|
||||
export function useChatwootConfig() {
|
||||
const hostURL = computed(() => window.chatwootConfig.hostURL);
|
||||
|
||||
const vapidPublicKey = computed(() => window.chatwootConfig.vapidPublicKey);
|
||||
|
||||
const enabledLanguages = computed(
|
||||
() => window.chatwootConfig.enabledLanguages
|
||||
);
|
||||
|
||||
const isEnterprise = computed(
|
||||
() => window.chatwootConfig.isEnterprise === 'true'
|
||||
);
|
||||
|
||||
const enterprisePlanName = computed(
|
||||
() => window.chatwootConfig?.enterprisePlanName
|
||||
);
|
||||
|
||||
return {
|
||||
hostURL,
|
||||
vapidPublicKey,
|
||||
enabledLanguages,
|
||||
isEnterprise,
|
||||
enterprisePlanName,
|
||||
};
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// export default {
|
||||
// computed: {
|
||||
// hostURL() {
|
||||
// return window.chatwootConfig.hostURL;
|
||||
// },
|
||||
// vapidPublicKey() {
|
||||
// return window.chatwootConfig.vapidPublicKey;
|
||||
// },
|
||||
// enabledLanguages() {
|
||||
// return window.chatwootConfig.enabledLanguages;
|
||||
// },
|
||||
// isEnterprise() {
|
||||
// return window.chatwootConfig.isEnterprise === 'true';
|
||||
// },
|
||||
// enterprisePlanName() {
|
||||
// // returns "community" or "enterprise"
|
||||
// return window.chatwootConfig?.enterprisePlanName;
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
/**
|
||||
* Composable for accessing Chatwoot configuration values.
|
||||
* @returns {Object} An object containing computed properties for various Chatwoot configuration values.
|
||||
*/
|
||||
export function useConfig() {
|
||||
const hostURL = computed(() => window.chatwootConfig.hostURL);
|
||||
|
||||
const vapidPublicKey = computed(() => window.chatwootConfig.vapidPublicKey);
|
||||
|
||||
const enabledLanguages = computed(
|
||||
() => window.chatwootConfig.enabledLanguages
|
||||
);
|
||||
|
||||
const isEnterprise = computed(
|
||||
() => window.chatwootConfig.isEnterprise === 'true'
|
||||
);
|
||||
|
||||
const enterprisePlanName = computed(
|
||||
() => window.chatwootConfig?.enterprisePlanName
|
||||
);
|
||||
|
||||
return {
|
||||
hostURL,
|
||||
vapidPublicKey,
|
||||
enabledLanguages,
|
||||
isEnterprise,
|
||||
enterprisePlanName,
|
||||
};
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
/**
|
||||
* Composable for handling dark mode preferences and utility functions.
|
||||
* @returns {Object} An object containing computed properties and methods for dark mode management.
|
||||
*/
|
||||
export function useDarkMode() {
|
||||
const store = useStore();
|
||||
|
||||
const darkMode = computed(() => store.getters['appConfig/darkMode']);
|
||||
|
||||
const prefersDarkMode = computed(() => {
|
||||
const isOSOnDarkMode =
|
||||
darkMode.value === 'auto' &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
return isOSOnDarkMode || darkMode.value === 'dark';
|
||||
});
|
||||
|
||||
const dm = (light, dark) => {
|
||||
if (darkMode.value === 'light') {
|
||||
return light;
|
||||
}
|
||||
if (darkMode.value === 'dark') {
|
||||
return dark;
|
||||
}
|
||||
return `${light} ${dark}`;
|
||||
};
|
||||
|
||||
return {
|
||||
darkMode,
|
||||
prefersDarkMode,
|
||||
dm,
|
||||
};
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
// File: app/javascript/dashboard/composables/useFilter.js
|
||||
import { ref, computed } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
|
||||
/**
|
||||
* Composable for handling filter-related functionalities.
|
||||
* @returns {Object} An object containing methods for filter management.
|
||||
*/
|
||||
export function useFilter(
|
||||
attributeModel,
|
||||
filtersFori18n,
|
||||
filterAttributeGroups,
|
||||
customAttributeInputType,
|
||||
getOperatorTypes
|
||||
) {
|
||||
const store = useStore();
|
||||
const filterTypes = ref([]);
|
||||
const filterGroups = ref([]);
|
||||
const appliedFilter = ref([]);
|
||||
const activeStatus = ref('');
|
||||
const activeAssigneeTab = ref('');
|
||||
const conversationInbox = ref('');
|
||||
const teamId = ref('');
|
||||
const label = ref('');
|
||||
const currentUserDetails = ref([]);
|
||||
const inbox = ref({});
|
||||
const activeTeam = ref({});
|
||||
|
||||
const setFilterAttributes = () => {
|
||||
const allCustomAttributes = store.getters[
|
||||
'attributes/getAttributesByModel'
|
||||
](attributeModel.value);
|
||||
const customAttributesFormatted = {
|
||||
name: store.$t(`${filtersFori18n.value}.GROUPS.CUSTOM_ATTRIBUTES`),
|
||||
attributes: allCustomAttributes.map(attr => ({
|
||||
key: attr.attribute_key,
|
||||
name: store.$t(`${filtersFori18n.value}.ATTRIBUTES.${attr.i18nKey}`),
|
||||
})),
|
||||
};
|
||||
const allFilterGroups = filterAttributeGroups.value.map(group => ({
|
||||
name: store.$t(`${filtersFori18n.value}.GROUPS.${group.i18nGroup}`),
|
||||
attributes: group.attributes.map(attribute => ({
|
||||
key: attribute.key,
|
||||
name: store.$t(
|
||||
`${filtersFori18n.value}.ATTRIBUTES.${attribute.i18nKey}`
|
||||
),
|
||||
})),
|
||||
}));
|
||||
const customAttributeTypes = allCustomAttributes.map(attr => ({
|
||||
attributeKey: attr.attribute_key,
|
||||
attributeI18nKey: `CUSTOM_ATTRIBUTE_${attr.attribute_display_type.toUpperCase()}`,
|
||||
inputType: customAttributeInputType(attr.attribute_display_type),
|
||||
filterOperators: getOperatorTypes(attr.attribute_display_type),
|
||||
attributeModel: 'custom_attributes',
|
||||
}));
|
||||
filterTypes.value = [...filterTypes.value, ...customAttributeTypes];
|
||||
filterGroups.value = [...allFilterGroups, customAttributesFormatted];
|
||||
};
|
||||
|
||||
const initializeExistingFilterToModal = () => {
|
||||
initializeStatusAndAssigneeFilterToModal();
|
||||
initializeInboxTeamAndLabelFilterToModal();
|
||||
};
|
||||
|
||||
const initializeStatusAndAssigneeFilterToModal = () => {
|
||||
if (activeStatus.value !== '') {
|
||||
appliedFilter.value.push({
|
||||
attribute_key: 'status',
|
||||
attribute_model: 'standard',
|
||||
filter_operator: 'equal_to',
|
||||
values: [
|
||||
{
|
||||
id: activeStatus.value,
|
||||
name: store.$t(
|
||||
`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus.value}.TEXT`
|
||||
),
|
||||
},
|
||||
],
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
});
|
||||
}
|
||||
if (activeAssigneeTab.value === wootConstants.ASSIGNEE_TYPE.ME) {
|
||||
appliedFilter.value.push({
|
||||
attribute_key: 'assignee_id',
|
||||
filter_operator: 'equal_to',
|
||||
values: currentUserDetails.value,
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const initializeInboxTeamAndLabelFilterToModal = () => {
|
||||
if (conversationInbox.value) {
|
||||
appliedFilter.value.push({
|
||||
attribute_key: 'inbox_id',
|
||||
attribute_model: 'standard',
|
||||
filter_operator: 'equal_to',
|
||||
values: [
|
||||
{
|
||||
id: conversationInbox.value,
|
||||
name: inbox.value.name,
|
||||
},
|
||||
],
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
});
|
||||
}
|
||||
if (teamId.value) {
|
||||
appliedFilter.value.push({
|
||||
attribute_key: 'team_id',
|
||||
attribute_model: 'standard',
|
||||
filter_operator: 'equal_to',
|
||||
values: activeTeam.value,
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
});
|
||||
}
|
||||
if (label.value) {
|
||||
appliedFilter.value.push({
|
||||
attribute_key: 'labels',
|
||||
attribute_model: 'standard',
|
||||
filter_operator: 'equal_to',
|
||||
values: [
|
||||
{
|
||||
id: label.value,
|
||||
name: label.value,
|
||||
},
|
||||
],
|
||||
query_operator: 'and',
|
||||
custom_attribute_type: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
setFilterAttributes,
|
||||
initializeExistingFilterToModal,
|
||||
initializeStatusAndAssigneeFilterToModal,
|
||||
initializeInboxTeamAndLabelFilterToModal,
|
||||
filterTypes,
|
||||
filterGroups,
|
||||
appliedFilter,
|
||||
activeStatus,
|
||||
activeAssigneeTab,
|
||||
conversationInbox,
|
||||
teamId,
|
||||
label,
|
||||
currentUserDetails,
|
||||
inbox,
|
||||
activeTeam,
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
/**
|
||||
* Composable for handling hook-related computations.
|
||||
* @param {Object} integration - The integration object containing hook information.
|
||||
* @returns {Object} An object containing computed properties for hook types and connections.
|
||||
*/
|
||||
export function useHook(integration) {
|
||||
const isHookTypeInbox = computed(() => integration.hook_type === 'inbox');
|
||||
const hasConnectedHooks = computed(() => !!integration.hooks.length);
|
||||
|
||||
return {
|
||||
isHookTypeInbox,
|
||||
hasConnectedHooks,
|
||||
};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
/**
|
||||
* Composable for handling message-related computations.
|
||||
* @param {Object} message - The message object to be processed.
|
||||
* @returns {Object} An object containing computed properties for message content and attachments.
|
||||
*/
|
||||
export function useMessage(message) {
|
||||
const messageContentAttributes = computed(() => {
|
||||
const { content_attributes: attribute = {} } = message;
|
||||
return attribute;
|
||||
});
|
||||
|
||||
const hasAttachments = computed(() => {
|
||||
return !!(message.attachments && message.attachments.length > 0);
|
||||
});
|
||||
|
||||
return {
|
||||
messageContentAttributes,
|
||||
hasAttachments,
|
||||
};
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import MessageFormatter from '../helpers/MessageFormatter';
|
||||
|
||||
/**
|
||||
* Composable for handling message formatting operations.
|
||||
* @returns {Object} An object containing methods for formatting and manipulating messages.
|
||||
*/
|
||||
export function useMessageFormatter() {
|
||||
const formatMessage = (message, isATweet, isAPrivateNote) => {
|
||||
const messageFormatter = new MessageFormatter(
|
||||
message,
|
||||
isATweet,
|
||||
isAPrivateNote
|
||||
);
|
||||
return messageFormatter.formattedMessage;
|
||||
};
|
||||
|
||||
const getPlainText = (message, isATweet) => {
|
||||
const messageFormatter = new MessageFormatter(message, isATweet);
|
||||
return messageFormatter.plainText;
|
||||
};
|
||||
|
||||
const truncateMessage = (description = '') => {
|
||||
if (description.length < 100) {
|
||||
return description;
|
||||
}
|
||||
return `${description.slice(0, 97)}...`;
|
||||
};
|
||||
|
||||
const highlightContent = (
|
||||
content = '',
|
||||
searchTerm = '',
|
||||
highlightClass = ''
|
||||
) => {
|
||||
const plainTextContent = getPlainText(content);
|
||||
const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
return plainTextContent.replace(
|
||||
new RegExp(`(${escapedSearchTerm})`, 'ig'),
|
||||
`<span class="${highlightClass}">$1</span>`
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
formatMessage,
|
||||
getPlainText,
|
||||
truncateMessage,
|
||||
highlightContent,
|
||||
};
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
import allLocales from 'shared/constants/locales.js';
|
||||
|
||||
/**
|
||||
* Composable for handling portal-related computations and methods.
|
||||
* @returns {Object} An object containing computed properties and methods for portal management.
|
||||
*/
|
||||
export function usePortal() {
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
const accountId = computed(() => store.getters.getCurrentAccountId);
|
||||
const portalSlug = computed(() => route.params.portalSlug);
|
||||
const locale = computed(() => route.params.locale);
|
||||
|
||||
const articleUrl = id => {
|
||||
return frontendURL(
|
||||
`accounts/${accountId.value}/portals/${portalSlug.value}/${locale.value}/articles/${id}`
|
||||
);
|
||||
};
|
||||
|
||||
const localeName = code => {
|
||||
return allLocales[code];
|
||||
};
|
||||
|
||||
return {
|
||||
accountId,
|
||||
portalSlug,
|
||||
locale,
|
||||
articleUrl,
|
||||
localeName,
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
/**
|
||||
* Composable for handling router-related operations.
|
||||
* @returns {Object} An object containing methods for router manipulation.
|
||||
*/
|
||||
export function useRouterHelper() {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
/**
|
||||
* Replaces the current route with a new one if it's different.
|
||||
* @param {string} name - The name of the route to replace with.
|
||||
* @param {Object} params - The params to pass to the new route.
|
||||
* @returns {Promise|undefined} A promise that resolves when the navigation is complete, or undefined if no navigation occurs.
|
||||
*/
|
||||
const replaceRoute = async (name, params = {}) => {
|
||||
if (route.name !== name) {
|
||||
return router.replace({ name, params });
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
return {
|
||||
replaceRoute,
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import WootUiKit from '../dashboard/components';
|
||||
import App from '../dashboard/App';
|
||||
import i18n from '../dashboard/i18n';
|
||||
import createAxios from '../dashboard/helper/APIHelper';
|
||||
import { emitter } from '../shared/helpers/mitt';
|
||||
import { EmitterPlugin } from '../shared/helpers/mitt';
|
||||
|
||||
import commonHelpers, { isJSONValid } from '../dashboard/helper/commons';
|
||||
import router, { initalizeRouter } from '../dashboard/routes';
|
||||
@@ -93,7 +93,7 @@ commonHelpers();
|
||||
|
||||
window.WootConstants = constants;
|
||||
window.axios = createAxios(axios);
|
||||
Vue.prototype.$emitter = emitter;
|
||||
Vue.use(EmitterPlugin);
|
||||
|
||||
initializeChatwootEvents();
|
||||
initializeAnalyticsEvents();
|
||||
|
||||
@@ -3,7 +3,7 @@ import VueI18n from 'vue-i18n';
|
||||
import App from '../survey/App.vue';
|
||||
import i18n from '../survey/i18n';
|
||||
import store from '../survey/store';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
import { EmitterPlugin } from 'shared/helpers/mitt';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
|
||||
@@ -13,7 +13,7 @@ const i18nConfig = new VueI18n({
|
||||
});
|
||||
|
||||
// Event Bus
|
||||
Vue.prototype.$emitter = emitter;
|
||||
Vue.use(EmitterPlugin);
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import App from '../v3/App.vue';
|
||||
import router, { initalizeRouter } from '../v3/views/index';
|
||||
import store from '../v3/store';
|
||||
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
|
||||
import { emitter } from '../shared/helpers/mitt';
|
||||
import { EmitterPlugin } from '../shared/helpers/mitt';
|
||||
|
||||
Vue.config.env = process.env;
|
||||
|
||||
@@ -45,7 +45,7 @@ Vue.use(VueRouter);
|
||||
Vue.use(VueI18n);
|
||||
|
||||
Vue.use(AnalyticsPlugin);
|
||||
Vue.prototype.$emitter = emitter;
|
||||
Vue.use(EmitterPlugin);
|
||||
Vue.component('fluent-icon', FluentIcon);
|
||||
|
||||
const i18nConfig = new VueI18n({ locale: 'en', messages: i18n });
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from 'shared/helpers/Validators';
|
||||
import router from '../widget/router';
|
||||
import { directive as onClickaway } from 'vue-clickaway';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
import { EmitterPlugin } from 'shared/helpers/mitt';
|
||||
import { domPurifyConfig } from '../shared/helpers/HTMLSanitizer';
|
||||
const PhoneInput = () => import('../widget/components/Form/PhoneInput');
|
||||
|
||||
@@ -45,7 +45,7 @@ Vue.use(VueFormulate, {
|
||||
},
|
||||
});
|
||||
// Event Bus
|
||||
Vue.prototype.$emitter = emitter;
|
||||
Vue.use(EmitterPlugin);
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import mitt from 'mitt';
|
||||
const emitter = mitt();
|
||||
export { emitter };
|
||||
|
||||
const EmitterPlugin = {
|
||||
install(Vue) {
|
||||
Vue.prototype.$emitter = emitter;
|
||||
},
|
||||
};
|
||||
|
||||
export { emitter, EmitterPlugin };
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Composable for replacing 'Chatwoot' with a custom installation name in a string.
|
||||
* @param {string} installationName - The custom installation name to replace 'Chatwoot' with.
|
||||
* @returns {Function} A function that replaces 'Chatwoot' with the custom installation name in a given string.
|
||||
*/
|
||||
export function useInstallationName(installationName) {
|
||||
return str => {
|
||||
if (str && installationName) {
|
||||
return str.replace(/Chatwoot/g, installationName);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
export const INBOX_TYPES = {
|
||||
WEB: 'Channel::WebWidget',
|
||||
FB: 'Channel::FacebookPage',
|
||||
TWITTER: 'Channel::TwitterProfile',
|
||||
TWILIO: 'Channel::TwilioSms',
|
||||
WHATSAPP: 'Channel::Whatsapp',
|
||||
API: 'Channel::Api',
|
||||
EMAIL: 'Channel::Email',
|
||||
TELEGRAM: 'Channel::Telegram',
|
||||
LINE: 'Channel::Line',
|
||||
SMS: 'Channel::Sms',
|
||||
};
|
||||
|
||||
export const INBOX_FEATURES = {
|
||||
REPLY_TO: 'replyTo',
|
||||
REPLY_TO_OUTGOING: 'replyToOutgoing',
|
||||
};
|
||||
|
||||
export const INBOX_FEATURE_MAP = {
|
||||
[INBOX_FEATURES.REPLY_TO]: [
|
||||
INBOX_TYPES.FB,
|
||||
INBOX_TYPES.WEB,
|
||||
INBOX_TYPES.TWITTER,
|
||||
INBOX_TYPES.WHATSAPP,
|
||||
INBOX_TYPES.TELEGRAM,
|
||||
INBOX_TYPES.API,
|
||||
],
|
||||
[INBOX_FEATURES.REPLY_TO_OUTGOING]: [
|
||||
INBOX_TYPES.WEB,
|
||||
INBOX_TYPES.TWITTER,
|
||||
INBOX_TYPES.WHATSAPP,
|
||||
INBOX_TYPES.TELEGRAM,
|
||||
INBOX_TYPES.API,
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Composable for handling inbox-related computations and methods.
|
||||
* @param {Object} inbox - The inbox object to be processed.
|
||||
* @param {Object} chat - The chat object associated with the inbox.
|
||||
* @returns {Object} An object containing computed properties and methods for inbox management.
|
||||
*/
|
||||
export function useInbox(inbox, chat) {
|
||||
const channelType = computed(() => inbox.channel_type);
|
||||
const whatsAppAPIProvider = computed(() => inbox.provider || '');
|
||||
|
||||
const isAMicrosoftInbox = computed(
|
||||
() => isAnEmailChannel.value && inbox.provider === 'microsoft'
|
||||
);
|
||||
const isAGoogleInbox = computed(
|
||||
() => isAnEmailChannel.value && inbox.provider === 'google'
|
||||
);
|
||||
const isAPIInbox = computed(() => channelType.value === INBOX_TYPES.API);
|
||||
const isATwitterInbox = computed(
|
||||
() => channelType.value === INBOX_TYPES.TWITTER
|
||||
);
|
||||
const isAFacebookInbox = computed(() => channelType.value === INBOX_TYPES.FB);
|
||||
const isAWebWidgetInbox = computed(
|
||||
() => channelType.value === INBOX_TYPES.WEB
|
||||
);
|
||||
const isATwilioChannel = computed(
|
||||
() => channelType.value === INBOX_TYPES.TWILIO
|
||||
);
|
||||
const isALineChannel = computed(() => channelType.value === INBOX_TYPES.LINE);
|
||||
const isAnEmailChannel = computed(
|
||||
() => channelType.value === INBOX_TYPES.EMAIL
|
||||
);
|
||||
const isATelegramChannel = computed(
|
||||
() => channelType.value === INBOX_TYPES.TELEGRAM
|
||||
);
|
||||
|
||||
const isATwilioSMSChannel = computed(() => {
|
||||
const { medium = '' } = inbox;
|
||||
return isATwilioChannel.value && medium === 'sms';
|
||||
});
|
||||
|
||||
const isASmsInbox = computed(
|
||||
() => channelType.value === INBOX_TYPES.SMS || isATwilioSMSChannel.value
|
||||
);
|
||||
|
||||
const isATwilioWhatsAppChannel = computed(() => {
|
||||
const { medium = '' } = inbox;
|
||||
return isATwilioChannel.value && medium === 'whatsapp';
|
||||
});
|
||||
|
||||
const isAWhatsAppCloudChannel = computed(
|
||||
() =>
|
||||
channelType.value === INBOX_TYPES.WHATSAPP &&
|
||||
whatsAppAPIProvider.value === 'whatsapp_cloud'
|
||||
);
|
||||
|
||||
const is360DialogWhatsAppChannel = computed(
|
||||
() =>
|
||||
channelType.value === INBOX_TYPES.WHATSAPP &&
|
||||
whatsAppAPIProvider.value === 'default'
|
||||
);
|
||||
|
||||
const chatAdditionalAttributes = computed(() => {
|
||||
const { additional_attributes: additionalAttributes } = chat || {};
|
||||
return additionalAttributes || {};
|
||||
});
|
||||
|
||||
const isTwitterInboxTweet = computed(
|
||||
() => chatAdditionalAttributes.value.type === 'tweet'
|
||||
);
|
||||
|
||||
const twilioBadge = computed(
|
||||
() => `${isATwilioSMSChannel.value ? 'sms' : 'whatsapp'}`
|
||||
);
|
||||
const twitterBadge = computed(
|
||||
() => `${isTwitterInboxTweet.value ? 'twitter-tweet' : 'twitter-dm'}`
|
||||
);
|
||||
const facebookBadge = computed(
|
||||
() => chatAdditionalAttributes.value.type || 'facebook'
|
||||
);
|
||||
|
||||
const inboxBadge = computed(() => {
|
||||
if (isATwitterInbox.value) return twitterBadge.value;
|
||||
if (isAFacebookInbox.value) return facebookBadge.value;
|
||||
if (isATwilioChannel.value) return twilioBadge.value;
|
||||
if (isAWhatsAppChannel.value) return 'whatsapp';
|
||||
return channelType.value;
|
||||
});
|
||||
|
||||
const isAWhatsAppChannel = computed(
|
||||
() =>
|
||||
channelType.value === INBOX_TYPES.WHATSAPP ||
|
||||
isATwilioWhatsAppChannel.value
|
||||
);
|
||||
|
||||
const inboxHasFeature = feature => {
|
||||
return INBOX_FEATURE_MAP[feature]?.includes(channelType.value) ?? false;
|
||||
};
|
||||
|
||||
return {
|
||||
channelType,
|
||||
whatsAppAPIProvider,
|
||||
isAMicrosoftInbox,
|
||||
isAGoogleInbox,
|
||||
isAPIInbox,
|
||||
isATwitterInbox,
|
||||
isAFacebookInbox,
|
||||
isAWebWidgetInbox,
|
||||
isATwilioChannel,
|
||||
isALineChannel,
|
||||
isAnEmailChannel,
|
||||
isATelegramChannel,
|
||||
isATwilioSMSChannel,
|
||||
isASmsInbox,
|
||||
isATwilioWhatsAppChannel,
|
||||
isAWhatsAppCloudChannel,
|
||||
is360DialogWhatsAppChannel,
|
||||
chatAdditionalAttributes,
|
||||
isTwitterInboxTweet,
|
||||
twilioBadge,
|
||||
twitterBadge,
|
||||
facebookBadge,
|
||||
inboxBadge,
|
||||
isAWhatsAppChannel,
|
||||
inboxHasFeature,
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { setHeader } from 'widget/helpers/axios';
|
||||
import addHours from 'date-fns/addHours';
|
||||
import { IFrameHelper, RNHelper } from 'widget/helpers/utils';
|
||||
import configMixin from './mixins/configMixin';
|
||||
import { useAvailability } from '../dashboard/composables/useAvailability.js';
|
||||
import availabilityMixin from 'widget/mixins/availability';
|
||||
import { getLocale } from './helpers/urlParamsHelper';
|
||||
import { isEmptyObject } from 'widget/helpers/utils';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
@@ -27,17 +27,13 @@ export default {
|
||||
components: {
|
||||
Spinner,
|
||||
},
|
||||
mixins: [configMixin, routerMixin, darkModeMixin],
|
||||
mixins: [availabilityMixin, configMixin, routerMixin, darkModeMixin],
|
||||
data() {
|
||||
return {
|
||||
isMobile: false,
|
||||
campaignsSnoozedTill: undefined,
|
||||
};
|
||||
},
|
||||
setup() {
|
||||
const { isInBusinessHours } = useAvailability();
|
||||
return { isInBusinessHours };
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
activeCampaign: 'campaign/getActiveCampaign',
|
||||
|
||||
Reference in New Issue
Block a user