Compare commits

..
Author SHA1 Message Date
Shivam Mishra 523769b7ed feat: install emitter as a plugin 2024-08-05 11:54:29 +05:30
Sivin VargheseandGitHub 2a8d7e55c6 Merge branch 'develop' into feat/setup-eslint-rules 2024-08-02 14:23:56 +05:30
Sivin VargheseandGitHub 0826275618 Merge branch 'develop' into feat/setup-eslint-rules 2024-08-02 09:39:55 +05:30
iamsivin 5151e33ac2 fix: remove ESLint rule vue/prefer-prop-type-boolean-first 2024-08-01 17:22:36 +05:30
Sivin VargheseandGitHub 799dfab0dd Merge branch 'develop' into feat/setup-eslint-rules 2024-08-01 11:33:28 +05:30
iamsivin 62474bca23 fix: Drag and drop in new conversation modal 2024-08-01 10:18:17 +05:30
Sivin VargheseandGitHub bca270bb17 Merge branch 'develop' into feat/setup-eslint-rules 2024-07-31 20:35:35 +05:30
iamsivin 545e352d13 chore: Minor fix after merge conflicts 2024-07-31 11:19:55 +05:30
Sivin VargheseandGitHub 98fa2957a1 Merge branch 'develop' into feat/setup-eslint-rules 2024-07-31 11:18:32 +05:30
iamsivin 66e53d7408 chore: Minor event fix after merge develop 2024-07-31 00:25:35 +05:30
iamsivin daa660ca44 Merge branch 'develop' into feat/setup-eslint-rules 2024-07-31 00:21:16 +05:30
Sivin VargheseandGitHub 1fcdf42cc8 Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-29 20:05:38 +05:30
Sivin VargheseandGitHub dca97875a7 Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-29 20:05:16 +05:30
iamsivin 743cb99d30 fix: apply ESLint rule vue/no-unused-properties 2024-07-29 17:23:56 +05:30
Sivin VargheseandGitHub 6aa03b3ce1 Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-29 17:23:13 +05:30
Shivam Mishra d9c918253d test: update test to check for translation keys 2024-07-29 12:40:09 +05:30
Sivin VargheseandGitHub 227be4df58 Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-28 08:34:34 +05:30
Sivin VargheseandGitHub 081e25395b Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-28 08:15:29 +05:30
Sivin VargheseandGitHub b80c825b7c Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-26 13:24:59 +05:30
iamsivin 7fc14c2f1d chore: fix rule 2024-07-26 13:16:27 +05:30
iamsivin 0b2477c47e fix: apply ESLint rule vue/require-macro-variable-name 2024-07-26 12:47:47 +05:30
iamsivin 51ab7d4f9e fix: apply ESLint rule vue/require-explicit-slots 2024-07-26 12:42:12 +05:30
iamsivin 16bc70b6dc fix: apply ESLint rule vue/prefer-true-attribute-shorthand 2024-07-26 12:34:36 +05:30
Shivam Mishra d3d2e361b2 feat: translate error messages in automation 2024-07-26 12:21:08 +05:30
Shivam Mishra a55ec03eb1 feat: use transtion keys to mark errors 2024-07-26 12:21:08 +05:30
iamsivin fd6375fc6c fix: apply ESLint rule vue/prefer-separate-static-class 2024-07-26 12:02:22 +05:30
iamsivin 34ca9868a5 fix: apply ESLint rule vue/prefer-prop-type-boolean-first 2024-07-26 11:56:17 +05:30
iamsivin 29007de112 fix: apply ESLint rule vue/padding-line-between-blocks 2024-07-26 11:52:27 +05:30
iamsivin 1b045c499c fix: apply ESLint rule vue/no-v-text 2024-07-26 11:45:57 +05:30
iamsivin cef0491d15 fix: apply ESLint rule vue/no-useless-v-bind 2024-07-26 11:43:30 +05:30
iamsivin e1d0b56557 fix: apply ESLint rule vue/no-use-v-else-with-v-for 2024-07-26 11:21:47 +05:30
iamsivin 8742ef67db fix: apply ESLint rule vue/no-unused-refs 2024-07-26 11:13:04 +05:30
iamsivin af3c55937b fix: apply ESLint rule vue/no-unused-emit-declarations 2024-07-26 09:19:23 +05:30
iamsivin cfd8a32337 fix: apply ESLint rule vue/no-undef-components 2024-07-26 09:04:16 +05:30
iamsivin 48fef92dbb fix: apply ESLint rule vue/no-this-in-before-route-enter 2024-07-26 08:55:24 +05:30
iamsivin 03b81a1ead fix: apply ESLint rule vue/no-template-target-blank 2024-07-26 08:52:26 +05:30
iamsivin 7f520535dd fix: apply ESLint rule vue/no-static-inline-styles 2024-07-26 08:47:19 +05:30
iamsivin f2946a8a3f fix: apply ESLint rule vue/no-root-v-if 2024-07-26 08:42:34 +05:30
Sivin VargheseandGitHub b651f5ec92 Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-26 08:28:58 +05:30
PranavandGitHub 3119f6cbf5 Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-25 16:29:38 -07:00
Sivin VargheseandGitHub 96ab20b756 Merge branch 'chore/vuelidate-v2-migration' into feat/setup-eslint-rules 2024-07-26 02:03:17 +05:30
Sivin VargheseandGitHub ca465f0f3b Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-26 02:03:06 +05:30
iamsivin 063d216247 fix: apply ESLint rule vue/no-required-prop-with-default 2024-07-26 02:01:23 +05:30
iamsivin 41a92c575f fix: apply ESLint rule vue/no-multiple-objects-in-class 2024-07-26 01:51:16 +05:30
iamsivin 1321a79b4c fix: apply ESLint rule vue/no-empty-component-block 2024-07-26 01:48:43 +05:30
iamsivin b316b47f74 fix: apply ESLint rule vue/no-bare-strings-in-template 2024-07-26 01:43:44 +05:30
iamsivin 602b0d19ca fix: apply ESLint rule vue/next-tick-style 2024-07-26 00:14:23 +05:30
iamsivin a52e93bf50 fix: apply ESLint rule vue/match-component-import-name 2024-07-26 00:09:15 +05:30
iamsivin c84c4492f0 fix: apply ESLint rule vue/define-props-declaration 2024-07-26 00:01:25 +05:30
iamsivin a3229cee99 fix: apply ESLint rule vue/define-macros-order 2024-07-25 23:58:58 +05:30
iamsivin b92f7536d2 fix: apply ESLint rule vue/define-emits-declaration 2024-07-25 23:51:26 +05:30
iamsivin 89311b54d5 fix: Broken snapshot 2024-07-25 23:47:25 +05:30
iamsivin ecb0b4a4f4 fix: apply ESLint rule vue/custom-event-name-casing 2024-07-25 23:40:54 +05:30
iamsivin 2ef9274450 fix: apply ESLint rule vue/component-options-name-casing 2024-07-25 19:51:42 +05:30
iamsivin 3ce70f4e14 fix: apply ESLint rule vue/component-name-in-template-casing 2024-07-25 19:42:48 +05:30
iamsivin 0008fca511 fix: apply ESLint rule vue/component-tags-order 2024-07-25 19:33:28 +05:30
iamsivin fede03ebe8 fix: Unexpected unnamed function warning 2024-07-25 19:26:36 +05:30
Shivam Mishra 9ef3e8ab74 feat: include "remove_assigned_team" in no params list 2024-07-25 16:35:42 +05:30
Shivam Mishra 63f8a49107 fix: ensure v$ is present 2024-07-25 16:35:42 +05:30
Sivin VargheseandGitHub 2f46f337f0 Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-25 15:35:05 +05:30
Shivam MishraandGitHub 5695eafa29 Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-25 11:25:33 +05:30
Shivam Mishra 1bd654a8c5 test: fix usage of email validator 2024-07-25 11:13:20 +05:30
Shivam Mishra ded2a72476 feat: use custom validations for macro actions 2024-07-24 20:47:19 +05:30
Shivam Mishra 55d6b0ce86 feat: use custom validation instead of vuelidate 2024-07-24 18:45:38 +05:30
Shivam Mishra 61ba2c8499 feat: use custom validator for automation rule 2024-07-24 18:36:57 +05:30
Shivam Mishra 893c88fb2d feat: remove Vuelidate usage 2024-07-24 17:18:50 +05:30
Shivam Mishra 8b57bcdd02 Merge branch 'develop' of github.com:chatwoot/chatwoot into chore/vuelidate-v2-migration 2024-07-24 17:16:53 +05:30
Shivam Mishra 004110f4c7 feat: remove legacy vuelidate 2024-07-24 17:06:09 +05:30
Shivam Mishra cf063e14d4 feat: import validators from the new library 2024-07-24 17:04:42 +05:30
Shivam Mishra 1f241e4546 refactor: use vuelidate for vue 3 in EditAutomationRule 2024-07-24 17:03:02 +05:30
Shivam Mishra 3ebf219ffa refactor: use vuelidate for vue 3 in AddAutomationRule.vue 2024-07-24 17:01:50 +05:30
Shivam Mishra ff92e6ef63 refactor: use v$ instead of in SlaForm.vue 2024-07-24 17:00:22 +05:30
Shivam Mishra b5bdb00e44 refactor: use vuelidate for vue 3 in SlaTimeInput 2024-07-24 16:59:37 +05:30
Shivam Mishra 45ff41a6ae refactor: use @vuelidate for vue 3 in MacroForm, MacroNode and MacroProperties 2024-07-24 16:58:15 +05:30
Shivam Mishra c8739caaa6 refactor: use v$ instead of in AddAgent.vue 2024-07-24 16:53:24 +05:30
Shivam Mishra cd078ca5ce refactor: use @vuelidate for vue 3 in EditLabel.vue 2024-07-23 21:00:10 +05:30
Shivam Mishra 6317421894 fix: use v$ instead of in AddLabel 2024-07-23 20:59:27 +05:30
Shivam Mishra 60e72b0c3d refactor: use @vuelidate for vue 3 in AddAgents.vue 2024-07-23 20:57:36 +05:30
Shivam Mishra 86c5884f0a refactor: use @vuelidate for vue 3 in Settings.vue 2024-07-23 20:55:22 +05:30
Shivam Mishra 6bd1fe1c10 chore: add comments 2024-07-23 17:19:11 +05:30
Shivam Mishra 8626590386 Merge branch 'develop' of github.com:chatwoot/chatwoot into chore/vuelidate-v2-migration 2024-07-23 17:03:53 +05:30
Shivam Mishra 7fe8b14539 refactor: use vuelidate for vue 3 2024-07-22 21:50:50 +05:30
Shivam Mishra c119084818 Merge branch 'develop' of github.com:chatwoot/chatwoot into chore/vuelidate-v2-migration 2024-07-22 21:49:08 +05:30
Shivam Mishra e4849a0d4b test: validateAutomation 2024-07-22 15:47:18 +05:30
Shivam Mishra bd09f6ce40 test: validateConversationOrContactFilters 2024-07-22 15:45:08 +05:30
Shivam Mishra 54ed5e44bc style: add separator for better organization 2024-07-22 15:44:57 +05:30
Shivam Mishra ce16558df4 refactor: split validateAutomation
It also reuses logic from validateSingleFilter
2024-07-22 15:39:10 +05:30
Shivam Mishra fbd95ff44a refactor: separate validateSingleFilter method 2024-07-22 15:32:44 +05:30
Shivam Mishra 7f15d8cbf2 docs: update JSdocs for validations 2024-07-22 15:21:22 +05:30
Fayaz Ahmed 353e2d0330 Draft 2024-07-22 15:10:58 +05:30
Shivam Mishra 2a2cd30c6b Merge branch 'develop' of github.com:chatwoot/chatwoot into chore/vuelidate-v2-migration 2024-07-22 15:04:26 +05:30
Fayaz Ahmed 9aeccf63c4 Replace vuelidate with custom validations 2024-07-18 23:53:39 +05:30
Fayaz AhmedandGitHub 1361c921de Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-17 15:00:14 +05:30
Fayaz Ahmed eeac9252fb Revert "draft somewhat working validation $each"
This reverts commit 624d61913c.
2024-07-17 14:59:51 +05:30
Fayaz Ahmed 624d61913c draft somewhat working validation $each 2024-07-16 01:30:23 +05:30
Fayaz AhmedandGitHub 29c2b8576c Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-15 23:38:27 +05:30
Fayaz Ahmed 0c969bf318 chore: Migrate remaining components 2024-07-10 16:05:45 +05:30
Muhsin KelothandGitHub 28d9c2615d Merge branch 'develop' into chore/vuelidate-v2-migration 2024-07-10 12:31:04 +05:30
Fayaz Ahmed e0ddeb4ee6 chore: Migrate all instances of old vuelidate to new v2 syntax 2024-06-10 15:15:14 +05:30
20 changed files with 18 additions and 773 deletions
@@ -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,
};
}
+2 -2
View File
@@ -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();
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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 });
+2 -2
View File
@@ -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;
+8 -1
View File
@@ -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;
};
}
-164
View File
@@ -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,
};
}
+2 -6
View File
@@ -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',