feat: Replace alertMixin usage with useAlert (#9793)

# Pull Request Template

## Description

This PR will replace the usage of `alertMixin` from the code base with
the `useAlert` composable.

Fixes
https://linear.app/chatwoot/issue/CW-3462/replace-alertmixin-usage-with-usealert

## Type of change

- [x] Breaking change (fix or feature that would cause existing
functionality not to work as expected)

## How Has This Been Tested?

Please refer this issue description

https://linear.app/chatwoot/issue/CW-3462/replace-alertmixin-usage-with-usealert


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
Sivin Varghese 2024-07-23 16:41:11 +05:30 committed by GitHub
parent 10ee773aac
commit 79aa5a5d7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
163 changed files with 868 additions and 850 deletions

View File

@ -116,6 +116,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import VirtualList from 'vue-virtual-scroll-list'; import VirtualList from 'vue-virtual-scroll-list';
import ChatListHeader from './ChatListHeader.vue'; import ChatListHeader from './ChatListHeader.vue';
@ -130,7 +131,6 @@ import filterQueryGenerator from '../helper/filterQueryGenerator.js';
import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue'; import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue';
import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue'; import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue';
import ConversationBulkActions from './widgets/conversation/conversationBulkActions/Index.vue'; import ConversationBulkActions from './widgets/conversation/conversationBulkActions/Index.vue';
import alertMixin from 'shared/mixins/alertMixin';
import filterMixin from 'shared/mixins/filterMixin'; import filterMixin from 'shared/mixins/filterMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages'; import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
@ -160,7 +160,6 @@ export default {
mixins: [ mixins: [
conversationMixin, conversationMixin,
keyboardEventListenerMixins, keyboardEventListenerMixins,
alertMixin,
filterMixin, filterMixin,
uiSettingsMixin, uiSettingsMixin,
], ],
@ -810,7 +809,7 @@ export default {
}); });
this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.$store.dispatch('bulkActions/clearSelectedConversationIds');
if (conversationId) { if (conversationId) {
this.showAlert( useAlert(
this.$t( this.$t(
'CONVERSATION.CARD_CONTEXT_MENU.API.AGENT_ASSIGNMENT.SUCCESFUL', 'CONVERSATION.CARD_CONTEXT_MENU.API.AGENT_ASSIGNMENT.SUCCESFUL',
{ {
@ -820,10 +819,10 @@ export default {
) )
); );
} else { } else {
this.showAlert(this.$t('BULK_ACTION.ASSIGN_SUCCESFUL')); useAlert(this.$t('BULK_ACTION.ASSIGN_SUCCESFUL'));
} }
} catch (err) { } catch (err) {
this.showAlert(this.$t('BULK_ACTION.ASSIGN_FAILED')); useAlert(this.$t('BULK_ACTION.ASSIGN_FAILED'));
} }
}, },
async assignPriority(priority, conversationId = null) { async assignPriority(priority, conversationId = null) {
@ -838,7 +837,7 @@ export default {
newValue: priority, newValue: priority,
from: 'Context menu', from: 'Context menu',
}); });
this.showAlert( useAlert(
this.$t('CONVERSATION.PRIORITY.CHANGE_PRIORITY.SUCCESSFUL', { this.$t('CONVERSATION.PRIORITY.CHANGE_PRIORITY.SUCCESSFUL', {
priority, priority,
conversationId, conversationId,
@ -881,7 +880,7 @@ export default {
conversationId, conversationId,
teamId: team.id, teamId: team.id,
}); });
this.showAlert( useAlert(
this.$t( this.$t(
'CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.SUCCESFUL', 'CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.SUCCESFUL',
{ {
@ -891,7 +890,7 @@ export default {
) )
); );
} catch (error) { } catch (error) {
this.showAlert( useAlert(
this.$t('CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.FAILED') this.$t('CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.FAILED')
); );
} }
@ -908,7 +907,7 @@ export default {
}); });
this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.$store.dispatch('bulkActions/clearSelectedConversationIds');
if (conversationId) { if (conversationId) {
this.showAlert( useAlert(
this.$t( this.$t(
'CONVERSATION.CARD_CONTEXT_MENU.API.LABEL_ASSIGNMENT.SUCCESFUL', 'CONVERSATION.CARD_CONTEXT_MENU.API.LABEL_ASSIGNMENT.SUCCESFUL',
{ {
@ -918,10 +917,10 @@ export default {
) )
); );
} else { } else {
this.showAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_SUCCESFUL')); useAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_SUCCESFUL'));
} }
} catch (err) { } catch (err) {
this.showAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_FAILED')); useAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_FAILED'));
} }
}, },
async onAssignTeamsForBulk(team) { async onAssignTeamsForBulk(team) {
@ -934,9 +933,9 @@ export default {
}, },
}); });
this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.$store.dispatch('bulkActions/clearSelectedConversationIds');
this.showAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_SUCCESFUL')); useAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_SUCCESFUL'));
} catch (err) { } catch (err) {
this.showAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_FAILED')); useAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_FAILED'));
} }
}, },
async onUpdateConversations(status, snoozedUntil) { async onUpdateConversations(status, snoozedUntil) {
@ -950,9 +949,9 @@ export default {
snoozed_until: snoozedUntil, snoozed_until: snoozedUntil,
}); });
this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.$store.dispatch('bulkActions/clearSelectedConversationIds');
this.showAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_SUCCESFUL')); useAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_SUCCESFUL'));
} catch (err) { } catch (err) {
this.showAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_FAILED')); useAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_FAILED'));
} }
}, },
toggleConversationStatus(conversationId, status, snoozedUntil) { toggleConversationStatus(conversationId, status, snoozedUntil) {
@ -963,7 +962,7 @@ export default {
snoozedUntil, snoozedUntil,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS')); useAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
this.isLoading = false; this.isLoading = false;
}); });
}, },

View File

@ -25,10 +25,9 @@
<script> <script>
import 'highlight.js/styles/default.css'; import 'highlight.js/styles/default.css';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
script: { script: {
type: String, type: String,
@ -61,7 +60,7 @@ export default {
async onCopy(e) { async onCopy(e) {
e.preventDefault(); e.preventDefault();
await copyTextToClipboard(this.script); await copyTextToClipboard(this.script);
this.showAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL')); useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
}, },
}, },
}; };

View File

@ -18,10 +18,9 @@
<script> <script>
import 'highlight.js/styles/default.css'; import 'highlight.js/styles/default.css';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
value: { value: {
type: String, type: String,
@ -37,7 +36,7 @@ export default {
async onCopy(e) { async onCopy(e) {
e.preventDefault(); e.preventDefault();
await copyTextToClipboard(this.value); await copyTextToClipboard(this.value);
this.showAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL')); useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
}, },
toggleMasked() { toggleMasked() {
this.masked = !this.masked; this.masked = !this.masked;

View File

@ -15,13 +15,11 @@
<script> <script>
import WootSnackbar from './Snackbar.vue'; import WootSnackbar from './Snackbar.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
WootSnackbar, WootSnackbar,
}, },
mixins: [alertMixin],
props: { props: {
duration: { duration: {
type: Number, type: Number,
@ -42,7 +40,7 @@ export default {
this.$emitter.off('newToastMessage', this.onNewToastMessage); this.$emitter.off('newToastMessage', this.onNewToastMessage);
}, },
methods: { methods: {
onNewToastMessage(message, action) { onNewToastMessage({ message, action }) {
this.snackMessages.push({ this.snackMessages.push({
key: new Date().getTime(), key: new Date().getTime(),
message, message,

View File

@ -10,9 +10,9 @@
</template> </template>
<script> <script>
import Banner from 'dashboard/components/ui/Banner.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
import Banner from 'dashboard/components/ui/Banner.vue';
import accountMixin from 'dashboard/mixins/account'; import accountMixin from 'dashboard/mixins/account';
const EMPTY_SUBSCRIPTION_INFO = { const EMPTY_SUBSCRIPTION_INFO = {
@ -22,7 +22,13 @@ const EMPTY_SUBSCRIPTION_INFO = {
export default { export default {
components: { Banner }, components: { Banner },
mixins: [adminMixin, accountMixin], mixins: [accountMixin],
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
computed: { computed: {
...mapGetters({ ...mapGetters({
isOnChatwootCloud: 'globalConfig/isOnChatwootCloud', isOnChatwootCloud: 'globalConfig/isOnChatwootCloud',

View File

@ -14,11 +14,11 @@
import Banner from 'dashboard/components/ui/Banner.vue'; import Banner from 'dashboard/components/ui/Banner.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import accountMixin from 'dashboard/mixins/account'; import accountMixin from 'dashboard/mixins/account';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
components: { Banner }, components: { Banner },
mixins: [accountMixin, alertMixin], mixins: [accountMixin],
computed: { computed: {
...mapGetters({ ...mapGetters({
currentUser: 'getCurrentUser', currentUser: 'getCurrentUser',
@ -36,7 +36,7 @@ export default {
methods: { methods: {
resendVerificationEmail() { resendVerificationEmail() {
this.$store.dispatch('resendConfirmation'); this.$store.dispatch('resendConfirmation');
this.showAlert(this.$t('APP_GLOBAL.EMAIL_VERIFICATION_SENT')); useAlert(this.$t('APP_GLOBAL.EMAIL_VERIFICATION_SENT'));
}, },
}, },
}; };

View File

@ -14,15 +14,20 @@ import Banner from 'dashboard/components/ui/Banner.vue';
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage'; import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage'; import { LocalStorage } from 'shared/helpers/localStorage';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
import { hasAnUpdateAvailable } from './versionCheckHelper'; import { hasAnUpdateAvailable } from './versionCheckHelper';
export default { export default {
components: { Banner }, components: { Banner },
mixins: [adminMixin],
props: { props: {
latestChatwootVersion: { type: String, default: '' }, latestChatwootVersion: { type: String, default: '' },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data() { data() {
return { userDismissedBanner: false }; return { userDismissedBanner: false };
}, },

View File

@ -12,13 +12,12 @@
<script> <script>
import Banner from 'dashboard/components/ui/Banner.vue'; import Banner from 'dashboard/components/ui/Banner.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin';
import accountMixin from 'dashboard/mixins/account'; import accountMixin from 'dashboard/mixins/account';
import { differenceInDays } from 'date-fns'; import { differenceInDays } from 'date-fns';
export default { export default {
components: { Banner }, components: { Banner },
mixins: [adminMixin, accountMixin], mixins: [accountMixin],
data() { data() {
return { conversationMeta: {} }; return { conversationMeta: {} };
}, },

View File

@ -78,7 +78,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
@ -94,7 +94,7 @@ export default {
WootDropdownItem, WootDropdownItem,
WootDropdownMenu, WootDropdownMenu,
}, },
mixins: [alertMixin, keyboardEventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { conversationId: { type: [String, Number], required: true } }, props: { conversationId: { type: [String, Number], required: true } },
data() { data() {
return { return {
@ -209,7 +209,7 @@ export default {
snoozedUntil, snoozedUntil,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS')); useAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
this.isLoading = false; this.isLoading = false;
}); });
}, },

View File

@ -18,7 +18,7 @@
</woot-button> </woot-button>
</woot-dropdown-item> </woot-dropdown-item>
<woot-dropdown-divider /> <woot-dropdown-divider />
<woot-dropdown-item class="m-0 flex items-center justify-between p-2"> <woot-dropdown-item class="flex items-center justify-between p-2 m-0">
<div class="flex items-center"> <div class="flex items-center">
<fluent-icon <fluent-icon
v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')" v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')"
@ -28,7 +28,7 @@
/> />
<span <span
class="my-0 mx-1 text-xs font-medium text-slate-600 dark:text-slate-100" class="mx-1 my-0 text-xs font-medium text-slate-600 dark:text-slate-100"
> >
{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }} {{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}
</span> </span>
@ -36,7 +36,7 @@
<woot-switch <woot-switch
size="small" size="small"
class="mt-px mx-1 mb-0" class="mx-1 mt-px mb-0"
:value="currentUserAutoOffline" :value="currentUserAutoOffline"
@input="updateAutoOffline" @input="updateAutoOffline"
/> />
@ -47,7 +47,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue'; import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue';
@ -65,9 +65,6 @@ export default {
WootDropdownItem, WootDropdownItem,
AvailabilityStatusBadge, AvailabilityStatusBadge,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
isStatusMenuOpened: false, isStatusMenuOpened: false,
@ -129,7 +126,7 @@ export default {
account_id: this.currentAccountId, account_id: this.currentAccountId,
}); });
} catch (error) { } catch (error) {
this.showAlert( useAlert(
this.$t('PROFILE_SETTINGS.FORM.AVAILABILITY.SET_AVAILABILITY_ERROR') this.$t('PROFILE_SETTINGS.FORM.AVAILABILITY.SET_AVAILABILITY_ERROR')
); );
} finally { } finally {

View File

@ -30,9 +30,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from '../../mixins/isAdmin';
import { getSidebarItems } from './config/default-sidebar'; import { getSidebarItems } from './config/default-sidebar';
import alertMixin from 'shared/mixins/alertMixin';
import PrimarySidebar from './sidebarComponents/Primary.vue'; import PrimarySidebar from './sidebarComponents/Primary.vue';
import SecondarySidebar from './sidebarComponents/Secondary.vue'; import SecondarySidebar from './sidebarComponents/Secondary.vue';
@ -45,7 +43,7 @@ export default {
PrimarySidebar, PrimarySidebar,
SecondarySidebar, SecondarySidebar,
}, },
mixins: [adminMixin, alertMixin, keyboardEventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { props: {
showSecondarySidebar: { showSecondarySidebar: {
type: Boolean, type: Boolean,

View File

@ -51,10 +51,9 @@
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@ -88,13 +87,13 @@ export default {
account_name: this.accountName, account_name: this.accountName,
}); });
this.$emit('close-account-create-modal'); this.$emit('close-account-create-modal');
this.showAlert(this.$t('CREATE_ACCOUNT.API.SUCCESS_MESSAGE')); useAlert(this.$t('CREATE_ACCOUNT.API.SUCCESS_MESSAGE'));
window.location = `/app/accounts/${account_id}/dashboard`; window.location = `/app/accounts/${account_id}/dashboard`;
} catch (error) { } catch (error) {
if (error.response.status === 422) { if (error.response.status === 422) {
this.showAlert(this.$t('CREATE_ACCOUNT.API.EXIST_MESSAGE')); useAlert(this.$t('CREATE_ACCOUNT.API.EXIST_MESSAGE'));
} else { } else {
this.showAlert(this.$t('CREATE_ACCOUNT.API.ERROR_MESSAGE')); useAlert(this.$t('CREATE_ACCOUNT.API.ERROR_MESSAGE'));
} }
} }
}, },

View File

@ -94,8 +94,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import adminMixin from '../../../mixins/isAdmin';
import configMixin from 'shared/mixins/configMixin'; import configMixin from 'shared/mixins/configMixin';
import { import {
getInboxClassByType, getInboxClassByType,
@ -111,13 +110,19 @@ import Policy from '../../policy.vue';
export default { export default {
components: { SecondaryChildNavItem, Policy }, components: { SecondaryChildNavItem, Policy },
mixins: [adminMixin, configMixin], mixins: [configMixin],
props: { props: {
menuItem: { menuItem: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
computed: { computed: {
...mapGetters({ ...mapGetters({
activeInbox: 'getSelectedInbox', activeInbox: 'getSelectedInbox',

View File

@ -35,10 +35,10 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import AICTAModal from './AICTAModal.vue'; import AICTAModal from './AICTAModal.vue';
import AIAssistanceModal from './AIAssistanceModal.vue'; import AIAssistanceModal from './AIAssistanceModal.vue';
import adminMixin from 'dashboard/mixins/aiMixin'; import aiMixin from 'dashboard/mixins/aiMixin';
import aiMixin from 'dashboard/mixins/isAdmin';
import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents'; import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
@ -50,7 +50,13 @@ export default {
AICTAModal, AICTAModal,
AIAssistanceCTAButton, AIAssistanceCTAButton,
}, },
mixins: [aiMixin, keyboardEventListenerMixins, adminMixin, uiSettingsMixin], mixins: [aiMixin, keyboardEventListenerMixins, uiSettingsMixin],
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data: () => ({ data: () => ({
showAIAssistanceModal: false, showAIAssistanceModal: false,
showAICtaModal: false, showAICtaModal: false,

View File

@ -40,12 +40,12 @@
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import aiMixin from 'dashboard/mixins/aiMixin'; import aiMixin from 'dashboard/mixins/aiMixin';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
export default { export default {
mixins: [aiMixin, alertMixin, uiSettingsMixin], mixins: [aiMixin, uiSettingsMixin],
data() { data() {
return { return {
value: '', value: '',
@ -67,7 +67,7 @@ export default {
}, },
onDismiss() { onDismiss() {
this.showAlert( useAlert(
this.$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.DISMISS_MESSAGE') this.$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.DISMISS_MESSAGE')
); );
this.updateUISettings({ this.updateUISettings({
@ -97,7 +97,7 @@ export default {
this.alertMessage = this.alertMessage =
errorMessage || this.$t('INTEGRATION_APPS.ADD.API.ERROR_MESSAGE'); errorMessage || this.$t('INTEGRATION_APPS.ADD.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
openOpenAIDoc() { openOpenAIDoc() {

View File

@ -26,13 +26,12 @@
</template> </template>
<script> <script>
import { useAlert } from 'dashboard/composables';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
Spinner, Spinner,
}, },
mixins: [alertMixin],
props: { props: {
value: { value: {
type: Array, type: Array,
@ -71,7 +70,7 @@ export default {
} catch (error) { } catch (error) {
this.uploadState = 'failed'; this.uploadState = 'failed';
this.label = this.$t('AUTOMATION.ATTACHMENT.LABEL_UPLOAD_FAILED'); this.label = this.$t('AUTOMATION.ATTACHMENT.LABEL_UPLOAD_FAILED');
this.showAlert(this.$t('AUTOMATION.ATTACHMENT.UPLOAD_ERROR')); useAlert(this.$t('AUTOMATION.ATTACHMENT.UPLOAD_ERROR'));
} }
}, },
}, },

View File

@ -33,7 +33,7 @@
import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import adminMixin from 'dashboard/mixins/isAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
export default { export default {
components: { components: {
@ -41,7 +41,7 @@ export default {
LabelDropdown, LabelDropdown,
}, },
mixins: [adminMixin, keyboardEventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { props: {
allLabels: { allLabels: {
@ -54,6 +54,13 @@ export default {
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data() { data() {
return { return {
showSearchDropdownLabel: false, showSearchDropdownLabel: false,

View File

@ -15,10 +15,9 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import DyteAPI from 'dashboard/api/integrations/dyte'; import DyteAPI from 'dashboard/api/integrations/dyte';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
conversationId: { conversationId: {
type: Number, type: Number,
@ -47,7 +46,7 @@ export default {
try { try {
await DyteAPI.createAMeeting(this.conversationId); await DyteAPI.createAMeeting(this.conversationId);
} catch (error) { } catch (error) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.CREATE_ERROR')); useAlert(this.$t('INTEGRATION_SETTINGS.DYTE.CREATE_ERROR'));
} finally { } finally {
this.isLoading = false; this.isLoading = false;
} }

View File

@ -11,7 +11,7 @@ import 'videojs-record/dist/css/videojs.record.css';
import videojs from 'video.js'; import videojs from 'video.js';
import alertMixin from '../../../../shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import Recorder from 'opus-recorder'; import Recorder from 'opus-recorder';
@ -50,7 +50,6 @@ const RECORDER_CONFIG = {
export default { export default {
name: 'WootAudioRecorder', name: 'WootAudioRecorder',
mixins: [alertMixin],
props: { props: {
audioRecordFormat: { audioRecordFormat: {
type: String, type: String,
@ -188,14 +187,10 @@ export default {
deviceErrorName?.includes('notallowederror') || deviceErrorName?.includes('notallowederror') ||
deviceErrorName?.includes('permissiondeniederror') deviceErrorName?.includes('permissiondeniederror')
) { ) {
this.showAlert( useAlert(this.$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_PERMISSION'));
this.$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_PERMISSION')
);
this.fireStateRecorderChanged('notallowederror'); this.fireStateRecorderChanged('notallowederror');
} else { } else {
this.showAlert( useAlert(this.$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_ERROR'));
this.$t('CONVERSATION.REPLYBOX.TIP_AUDIORECORDER_ERROR')
);
} }
}, },
formatTimeProgress() { formatTimeProgress() {

View File

@ -89,7 +89,7 @@ import {
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper'; import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { uploadFile } from 'dashboard/helper/uploadHelper'; import { uploadFile } from 'dashboard/helper/uploadHelper';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { import {
MESSAGE_EDITOR_MENU_OPTIONS, MESSAGE_EDITOR_MENU_OPTIONS,
MESSAGE_EDITOR_IMAGE_RESIZES, MESSAGE_EDITOR_IMAGE_RESIZES,
@ -119,7 +119,7 @@ const createState = (
export default { export default {
name: 'WootMessageEditor', name: 'WootMessageEditor',
components: { TagAgents, CannedResponse, VariableList }, components: { TagAgents, CannedResponse, VariableList },
mixins: [keyboardEventListenerMixins, uiSettingsMixin, alertMixin], mixins: [keyboardEventListenerMixins, uiSettingsMixin],
props: { props: {
value: { type: String, default: '' }, value: { type: String, default: '' },
editorId: { type: String, default: '' }, editorId: { type: String, default: '' },
@ -611,7 +611,7 @@ export default {
if (checkFileSizeLimit(file, MAXIMUM_FILE_UPLOAD_SIZE)) { if (checkFileSizeLimit(file, MAXIMUM_FILE_UPLOAD_SIZE)) {
this.uploadImageToStorage(file); this.uploadImageToStorage(file);
} else { } else {
this.showAlert( useAlert(
this.$t( this.$t(
'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_SIZE_ERROR', 'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_SIZE_ERROR',
{ {
@ -629,13 +629,13 @@ export default {
if (fileUrl) { if (fileUrl) {
this.onImageInsertInEditor(fileUrl); this.onImageInsertInEditor(fileUrl);
} }
this.showAlert( useAlert(
this.$t( this.$t(
'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_SUCCESS' 'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_SUCCESS'
) )
); );
} catch (error) { } catch (error) {
this.showAlert( useAlert(
this.$t( this.$t(
'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_ERROR' 'PROFILE_SETTINGS.FORM.MESSAGE_SIGNATURE_SECTION.IMAGE_UPLOAD_ERROR'
) )

View File

@ -24,7 +24,7 @@ import {
Selection, Selection,
} from '@chatwoot/prosemirror-schema'; } from '@chatwoot/prosemirror-schema';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper'; import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
@ -51,7 +51,7 @@ const createState = (
}; };
export default { export default {
mixins: [keyboardEventListenerMixins, uiSettingsMixin, alertMixin], mixins: [keyboardEventListenerMixins, uiSettingsMixin],
props: { props: {
value: { type: String, default: '' }, value: { type: String, default: '' },
editorId: { type: String, default: '' }, editorId: { type: String, default: '' },
@ -108,7 +108,7 @@ export default {
if (checkFileSizeLimit(file, MAXIMUM_FILE_UPLOAD_SIZE)) { if (checkFileSizeLimit(file, MAXIMUM_FILE_UPLOAD_SIZE)) {
this.uploadImageToStorage(file); this.uploadImageToStorage(file);
} else { } else {
this.showAlert( useAlert(
this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.ERROR_FILE_SIZE', { this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.ERROR_FILE_SIZE', {
size: MAXIMUM_FILE_UPLOAD_SIZE, size: MAXIMUM_FILE_UPLOAD_SIZE,
}) })
@ -127,13 +127,9 @@ export default {
if (fileUrl) { if (fileUrl) {
this.onImageUploadStart(fileUrl); this.onImageUploadStart(fileUrl);
} }
this.showAlert( useAlert(this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.SUCCESS'));
this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.SUCCESS')
);
} catch (error) { } catch (error) {
this.showAlert( useAlert(this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.ERROR'));
this.$t('HELP_CENTER.ARTICLE_EDITOR.IMAGE_UPLOAD.ERROR')
);
} }
}, },
onImageUploadStart(fileUrl) { onImageUploadStart(fileUrl) {

View File

@ -79,7 +79,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { required, requiredIf } from 'vuelidate/lib/validators'; import { required, requiredIf } from 'vuelidate/lib/validators';
import FilterInputBox from '../FilterInput/Index.vue'; import FilterInputBox from '../FilterInput/Index.vue';
import languages from './advancedFilterItems/languages'; import languages from './advancedFilterItems/languages';
@ -94,7 +94,7 @@ export default {
components: { components: {
FilterInputBox, FilterInputBox,
}, },
mixins: [alertMixin, filterMixin], mixins: [filterMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,
@ -341,7 +341,7 @@ export default {
}, },
removeFilter(index) { removeFilter(index) {
if (this.appliedFilters.length <= 1) { if (this.appliedFilters.length <= 1) {
this.showAlert(this.$t('FILTER.FILTER_DELETE_ERROR')); useAlert(this.$t('FILTER.FILTER_DELETE_ERROR'));
} else { } else {
this.appliedFilters.splice(index, 1); this.appliedFilters.splice(index, 1);
} }

View File

@ -125,7 +125,6 @@ import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
import InboxName from '../InboxName.vue'; import InboxName from '../InboxName.vue';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import ConversationContextMenu from './contextMenu/Index.vue'; import ConversationContextMenu from './contextMenu/Index.vue';
import alertMixin from 'shared/mixins/alertMixin';
import TimeAgo from 'dashboard/components/ui/TimeAgo.vue'; import TimeAgo from 'dashboard/components/ui/TimeAgo.vue';
import CardLabels from './conversationCardComponents/CardLabels.vue'; import CardLabels from './conversationCardComponents/CardLabels.vue';
import PriorityMark from './PriorityMark.vue'; import PriorityMark from './PriorityMark.vue';
@ -142,8 +141,7 @@ export default {
PriorityMark, PriorityMark,
SLACardLabel, SLACardLabel,
}, },
mixins: [inboxMixin, conversationMixin],
mixins: [inboxMixin, conversationMixin, alertMixin],
props: { props: {
activeLabel: { activeLabel: {
type: String, type: String,

View File

@ -1,7 +1,7 @@
<!-- eslint-disable vue/no-mutating-props --> <!-- eslint-disable vue/no-mutating-props -->
<template> <template>
<woot-modal :show.sync="show" :on-close="onCancel"> <woot-modal :show.sync="show" :on-close="onCancel">
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header <woot-modal-header
:header-title="$t('EMAIL_TRANSCRIPT.TITLE')" :header-title="$t('EMAIL_TRANSCRIPT.TITLE')"
:header-content="$t('EMAIL_TRANSCRIPT.DESC')" :header-content="$t('EMAIL_TRANSCRIPT.DESC')"
@ -61,7 +61,7 @@
</label> </label>
</div> </div>
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-submit-button <woot-submit-button
:button-text="$t('EMAIL_TRANSCRIPT.SUBMIT')" :button-text="$t('EMAIL_TRANSCRIPT.SUBMIT')"
:disabled="!isFormValid" :disabled="!isFormValid"
@ -77,9 +77,8 @@
<script> <script>
import { required, minLength, email } from 'vuelidate/lib/validators'; import { required, minLength, email } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@ -142,10 +141,10 @@ export default {
email: this.selectedEmailAddress, email: this.selectedEmailAddress,
conversationId: this.currentChat.id, conversationId: this.currentChat.id,
}); });
this.showAlert(this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS')); useAlert(this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS'));
this.onCancel(); this.onCancel();
} catch (error) { } catch (error) {
this.showAlert(this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_ERROR')); useAlert(this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_ERROR'));
} finally { } finally {
this.isSubmitting = false; this.isSubmitting = false;
} }

View File

@ -35,7 +35,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
import accountMixin from 'dashboard/mixins/account'; import accountMixin from 'dashboard/mixins/account';
import OnboardingView from '../OnboardingView.vue'; import OnboardingView from '../OnboardingView.vue';
import EmptyStateMessage from './EmptyStateMessage.vue'; import EmptyStateMessage from './EmptyStateMessage.vue';
@ -45,13 +45,19 @@ export default {
OnboardingView, OnboardingView,
EmptyStateMessage, EmptyStateMessage,
}, },
mixins: [accountMixin, adminMixin], mixins: [accountMixin],
props: { props: {
isOnExpandedLayout: { isOnExpandedLayout: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
computed: { computed: {
...mapGetters({ ...mapGetters({
currentChat: 'getSelectedChat', currentChat: 'getSelectedChat',

View File

@ -157,7 +157,6 @@ import ContextMenu from 'dashboard/modules/conversations/components/MessageConte
import InstagramStory from './bubble/InstagramStory.vue'; import InstagramStory from './bubble/InstagramStory.vue';
import InstagramStoryReply from './bubble/InstagramStoryReply.vue'; import InstagramStoryReply from './bubble/InstagramStoryReply.vue';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { CONTENT_TYPES } from 'shared/constants/contentType'; import { CONTENT_TYPES } from 'shared/constants/contentType';
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages'; import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
import { generateBotMessageContent } from './helpers/botMessageContentHelper'; import { generateBotMessageContent } from './helpers/botMessageContentHelper';
@ -184,7 +183,7 @@ export default {
InstagramStoryReply, InstagramStoryReply,
Spinner, Spinner,
}, },
mixins: [alertMixin, messageFormatterMixin], mixins: [messageFormatterMixin],
props: { props: {
data: { data: {
type: Object, type: Object,

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex actions--container relative items-center gap-2"> <div class="relative flex items-center gap-2 actions--container">
<woot-button <woot-button
v-if="!currentChat.muted" v-if="!currentChat.muted"
v-tooltip="$t('CONTACT_PANEL.MUTE_CONTACT')" v-tooltip="$t('CONTACT_PANEL.MUTE_CONTACT')"
@ -37,7 +37,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import EmailTranscriptModal from './EmailTranscriptModal.vue'; import EmailTranscriptModal from './EmailTranscriptModal.vue';
import ResolveAction from '../../buttons/ResolveAction.vue'; import ResolveAction from '../../buttons/ResolveAction.vue';
import { import {
@ -51,7 +51,6 @@ export default {
EmailTranscriptModal, EmailTranscriptModal,
ResolveAction, ResolveAction,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
showEmailActionsModal: false, showEmailActionsModal: false,
@ -73,11 +72,11 @@ export default {
methods: { methods: {
mute() { mute() {
this.$store.dispatch('muteConversation', this.currentChat.id); this.$store.dispatch('muteConversation', this.currentChat.id);
this.showAlert(this.$t('CONTACT_PANEL.MUTED_SUCCESS')); useAlert(this.$t('CONTACT_PANEL.MUTED_SUCCESS'));
}, },
unmute() { unmute() {
this.$store.dispatch('unmuteConversation', this.currentChat.id); this.$store.dispatch('unmuteConversation', this.currentChat.id);
this.showAlert(this.$t('CONTACT_PANEL.UNMUTED_SUCCESS')); useAlert(this.$t('CONTACT_PANEL.UNMUTED_SUCCESS'));
}, },
toggleEmailActionsModal() { toggleEmailActionsModal() {
this.showEmailActionsModal = !this.showEmailActionsModal; this.showEmailActionsModal = !this.showEmailActionsModal;

View File

@ -153,7 +153,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import CannedResponse from './CannedResponse.vue'; import CannedResponse from './CannedResponse.vue';
@ -219,7 +219,6 @@ export default {
mixins: [ mixins: [
inboxMixin, inboxMixin,
uiSettingsMixin, uiSettingsMixin,
alertMixin,
messageFormatterMixin, messageFormatterMixin,
rtlMixin, rtlMixin,
fileUploadMixin, fileUploadMixin,
@ -310,7 +309,7 @@ export default {
agentId, agentId,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('CONVERSATION.CHANGE_AGENT')); useAlert(this.$t('CONVERSATION.CHANGE_AGENT'));
}); });
}, },
}, },
@ -880,7 +879,7 @@ export default {
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.data?.error || this.$t('CONVERSATION.MESSAGE_ERROR'); error?.response?.data?.error || this.$t('CONVERSATION.MESSAGE_ERROR');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
async onSendWhatsAppReply(messagePayload) { async onSendWhatsAppReply(messagePayload) {

View File

@ -17,14 +17,13 @@
</template> </template>
<script> <script>
import { useAlert } from 'dashboard/composables';
import { import {
DuplicateContactException, DuplicateContactException,
ExceptionWithMessage, ExceptionWithMessage,
} from 'shared/helpers/CustomErrors'; } from 'shared/helpers/CustomErrors';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
mixins: [alertMixin],
props: { props: {
name: { name: {
type: String, type: String,
@ -52,18 +51,18 @@ export default {
'contacts/create', 'contacts/create',
this.getContactObject() this.getContactObject()
); );
this.showAlert(this.$t('CONTACT_FORM.SUCCESS_MESSAGE')); useAlert(this.$t('CONTACT_FORM.SUCCESS_MESSAGE'));
} }
this.openContactNewTab(contact.id); this.openContactNewTab(contact.id);
} catch (error) { } catch (error) {
if (error instanceof DuplicateContactException) { if (error instanceof DuplicateContactException) {
if (error.data.includes('phone_number')) { if (error.data.includes('phone_number')) {
this.showAlert(this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DUPLICATE')); useAlert(this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DUPLICATE'));
} }
} else if (error instanceof ExceptionWithMessage) { } else if (error instanceof ExceptionWithMessage) {
this.showAlert(error.data); useAlert(error.data);
} else { } else {
this.showAlert(this.$t('CONTACT_FORM.ERROR_MESSAGE')); useAlert(this.$t('CONTACT_FORM.ERROR_MESSAGE'));
} }
} }
}, },

View File

@ -31,10 +31,9 @@
<script> <script>
import DyteAPI from 'dashboard/api/integrations/dyte'; import DyteAPI from 'dashboard/api/integrations/dyte';
import { buildDyteURL } from 'shared/helpers/IntegrationHelper'; import { buildDyteURL } from 'shared/helpers/IntegrationHelper';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
messageId: { messageId: {
type: Number, type: Number,
@ -61,7 +60,7 @@ export default {
await DyteAPI.addParticipantToMeeting(this.messageId); await DyteAPI.addParticipantToMeeting(this.messageId);
this.dyteAuthToken = authToken; this.dyteAuthToken = authToken;
} catch (err) { } catch (err) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.DYTE.JOIN_ERROR')); useAlert(this.$t('INTEGRATION_SETTINGS.DYTE.JOIN_ERROR'));
} finally { } finally {
this.isLoading = false; this.isLoading = false;
} }

View File

@ -85,11 +85,11 @@ describe('MoveActions', () => {
it('shows alert', async () => { it('shows alert', async () => {
await moreActions.find('button:first-child').trigger('click'); await moreActions.find('button:first-child').trigger('click');
expect(emitter.emit).toBeCalledWith( expect(emitter.emit).toBeCalledWith('newToastMessage', {
'newToastMessage', message:
'This contact is blocked successfully. You will not be notified of any future conversations.', 'This contact is blocked successfully. You will not be notified of any future conversations.',
undefined action: null,
); });
}); });
}); });
@ -111,11 +111,10 @@ describe('MoveActions', () => {
it('shows alert', async () => { it('shows alert', async () => {
await moreActions.find('button:first-child').trigger('click'); await moreActions.find('button:first-child').trigger('click');
expect(emitter.emit).toBeCalledWith( expect(emitter.emit).toBeCalledWith('newToastMessage', {
'newToastMessage', message: 'This contact is unblocked successfully.',
'This contact is unblocked successfully.', action: null,
undefined });
);
}); });
}); });
}); });

View File

@ -1,6 +1,10 @@
import { getCurrentInstance } from 'vue'; import { getCurrentInstance } from 'vue';
import { emitter } from 'shared/helpers/mitt'; import { emitter } from 'shared/helpers/mitt';
/**
* Custom hook to track events
* @returns {Function} The track function
*/
export const useTrack = () => { export const useTrack = () => {
const vm = getCurrentInstance(); const vm = getCurrentInstance();
if (!vm) throw new Error('must be called in setup'); if (!vm) throw new Error('must be called in setup');
@ -8,6 +12,11 @@ export const useTrack = () => {
return vm.proxy.$track; return vm.proxy.$track;
}; };
export function useAlert(message, action) { /**
emitter.emit('newToastMessage', message, action); * Emits a toast message event using a global emitter.
} * @param {string} message - The message to be displayed in the toast.
* @param {Object|null} action - Optional callback function or object to execute.
*/
export const useAlert = (message, action = null) => {
emitter.emit('newToastMessage', { message, action });
};

View File

@ -0,0 +1,51 @@
import { getCurrentInstance } from 'vue';
import { emitter } from 'shared/helpers/mitt';
import { useTrack, useAlert } from '../index';
vi.mock('vue', () => ({
getCurrentInstance: vi.fn(),
}));
vi.mock('shared/helpers/mitt', () => ({
emitter: {
emit: vi.fn(),
},
}));
describe('useTrack', () => {
it('should return $track from the current instance proxy', () => {
const mockProxy = { $track: vi.fn() };
getCurrentInstance.mockReturnValue({ proxy: mockProxy });
const track = useTrack();
expect(track).toBe(mockProxy.$track);
});
it('should throw an error if called outside of setup', () => {
getCurrentInstance.mockReturnValue(null);
expect(useTrack).toThrowError('must be called in setup');
});
});
describe('useAlert', () => {
it('should emit a newToastMessage event with the provided message and action', () => {
const message = 'Toast message';
const action = {
type: 'link',
to: '/app/accounts/1/conversations/1',
message: 'Navigate',
};
useAlert(message, action);
expect(emitter.emit).toHaveBeenCalledWith('newToastMessage', {
message,
action,
});
});
it('should emit a newToastMessage event with the provided message and no action if action is null', () => {
const message = 'Toast message';
useAlert(message);
expect(emitter.emit).toHaveBeenCalledWith('newToastMessage', {
message,
action: null,
});
});
});

View File

@ -0,0 +1,52 @@
import { ref } from 'vue';
import { useAdmin } from '../useAdmin';
import { useStoreGetters } from 'dashboard/composables/store';
vi.mock('dashboard/composables/store');
describe('useAdmin', () => {
it('returns true if the current user is an administrator', () => {
useStoreGetters.mockReturnValue({
getCurrentRole: ref('administrator'),
});
const { isAdmin } = useAdmin();
expect(isAdmin.value).toBe(true);
});
it('returns false if the current user is not an administrator', () => {
useStoreGetters.mockReturnValue({
getCurrentRole: ref('user'),
});
const { isAdmin } = useAdmin();
expect(isAdmin.value).toBe(false);
});
it('returns false if the current user role is null', () => {
useStoreGetters.mockReturnValue({
getCurrentRole: ref(null),
});
const { isAdmin } = useAdmin();
expect(isAdmin.value).toBe(false);
});
it('returns false if the current user role is undefined', () => {
useStoreGetters.mockReturnValue({
getCurrentRole: ref(undefined),
});
const { isAdmin } = useAdmin();
expect(isAdmin.value).toBe(false);
});
it('returns false if the current user role is an empty string', () => {
useStoreGetters.mockReturnValue({
getCurrentRole: ref(''),
});
const { isAdmin } = useAdmin();
expect(isAdmin.value).toBe(false);
});
});

View File

@ -0,0 +1,17 @@
import { computed } from 'vue';
import { useStoreGetters } from 'dashboard/composables/store';
/**
* Composable to determine if the current user is an administrator.
* @returns {Boolean} - True if the current user is an administrator, false otherwise.
*/
export function useAdmin() {
const getters = useStoreGetters();
const currentUserRole = computed(() => getters.getCurrentRole.value);
const isAdmin = computed(() => currentUserRole.value === 'administrator');
return {
isAdmin,
};
}

View File

@ -1,7 +1,7 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import NotificationSubscriptions from '../api/notificationSubscription'; import NotificationSubscriptions from '../api/notificationSubscription';
import auth from '../api/auth'; import auth from '../api/auth';
import { emitter } from 'shared/helpers/mitt'; import { useAlert } from 'dashboard/composables';
export const verifyServiceWorkerExistence = (callback = () => {}) => { export const verifyServiceWorkerExistence = (callback = () => {}) => {
if (!('serviceWorker' in navigator)) { if (!('serviceWorker' in navigator)) {
@ -69,19 +69,13 @@ export const registerSubscription = (onSuccess = () => {}) => {
onSuccess(); onSuccess();
}) })
.catch(() => { .catch(() => {
emitter.emit( useAlert('This browser does not support desktop notification');
'newToastMessage',
'This browser does not support desktop notification'
);
}); });
}; };
export const requestPushPermissions = ({ onSuccess }) => { export const requestPushPermissions = ({ onSuccess }) => {
if (!('Notification' in window)) { if (!('Notification' in window)) {
emitter.emit( useAlert('This browser does not support desktop notification');
'newToastMessage',
'This browser does not support desktop notification'
);
} else if (Notification.permission === 'granted') { } else if (Notification.permission === 'granted') {
registerSubscription(onSuccess); registerSubscription(onSuccess);
} else if (Notification.permission !== 'denied') { } else if (Notification.permission !== 'denied') {

View File

@ -1,10 +1,9 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { OPEN_AI_EVENTS } from '../helper/AnalyticsHelper/events'; import { OPEN_AI_EVENTS } from '../helper/AnalyticsHelper/events';
import OpenAPI from '../api/integrations/openapi'; import OpenAPI from '../api/integrations/openapi';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
mixins: [alertMixin],
mounted() { mounted() {
this.fetchIntegrationsIfRequired(); this.fetchIntegrationsIfRequired();
}, },
@ -101,7 +100,7 @@ export default {
} = result; } = result;
return generatedMessage; return generatedMessage;
} catch (error) { } catch (error) {
this.showAlert(this.$t('INTEGRATION_SETTINGS.OPEN_AI.GENERATE_ERROR')); useAlert(this.$t('INTEGRATION_SETTINGS.OPEN_AI.GENERATE_ERROR'));
return ''; return '';
} }
}, },

View File

@ -17,6 +17,7 @@ import {
generateCustomAttributes, generateCustomAttributes,
} from 'dashboard/helper/automationHelper'; } from 'dashboard/helper/automationHelper';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
export default { export default {
computed: { computed: {
@ -138,14 +139,14 @@ export default {
}, },
removeFilter(index) { removeFilter(index) {
if (this.automation.conditions.length <= 1) { if (this.automation.conditions.length <= 1) {
this.showAlert(this.$t('AUTOMATION.CONDITION.DELETE_MESSAGE')); useAlert(this.$t('AUTOMATION.CONDITION.DELETE_MESSAGE'));
} else { } else {
this.automation.conditions.splice(index, 1); this.automation.conditions.splice(index, 1);
} }
}, },
removeAction(index) { removeAction(index) {
if (this.automation.actions.length <= 1) { if (this.automation.actions.length <= 1) {
this.showAlert(this.$t('AUTOMATION.ACTION.DELETE_MESSAGE')); useAlert(this.$t('AUTOMATION.ACTION.DELETE_MESSAGE'));
} else { } else {
this.automation.actions.splice(index, 1); this.automation.actions.splice(index, 1);
} }

View File

@ -1,3 +1,4 @@
import { useAlert } from 'dashboard/composables';
import { import {
MAXIMUM_FILE_UPLOAD_SIZE, MAXIMUM_FILE_UPLOAD_SIZE,
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL, MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL,
@ -38,13 +39,13 @@ export default {
upload.create((error, blob) => { upload.create((error, blob) => {
if (error) { if (error) {
this.showAlert(error); useAlert(error);
} else { } else {
this.attachFile({ file, blob }); this.attachFile({ file, blob });
} }
}); });
} else { } else {
this.showAlert( useAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', { this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
}) })
@ -61,7 +62,7 @@ export default {
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) { if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
this.attachFile({ file }); this.attachFile({ file });
} else { } else {
this.showAlert( useAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', { this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
}) })

View File

@ -1,12 +0,0 @@
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
currentUserRole: 'getCurrentRole',
}),
isAdmin() {
return this.currentUserRole === 'administrator';
},
},
};

View File

@ -1,5 +1,6 @@
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
import Vue from 'vue'; import Vue from 'vue';
import { useAlert } from 'dashboard/composables';
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
vi.mock('shared/helpers/FileHelper', () => ({ vi.mock('shared/helpers/FileHelper', () => ({
checkFileSizeLimit: vi.fn(), checkFileSizeLimit: vi.fn(),
@ -11,6 +12,10 @@ vi.mock('activestorage', () => ({
})), })),
})); }));
vi.mock('dashboard/composables', () => ({
useAlert: vi.fn(),
}));
describe('FileUploadMixin', () => { describe('FileUploadMixin', () => {
let vm; let vm;
@ -53,9 +58,8 @@ describe('FileUploadMixin', () => {
it('shows an alert if the file size exceeds the maximum limit', () => { it('shows an alert if the file size exceeds the maximum limit', () => {
const fakeFile = { size: 999999999 }; const fakeFile = { size: 999999999 };
vm.showAlert = vi.fn();
vm.onDirectFileUpload(fakeFile); vm.onDirectFileUpload(fakeFile);
expect(vm.showAlert).toHaveBeenCalledWith(expect.any(String)); expect(useAlert).toHaveBeenCalledWith(expect.any(String));
}); });
}); });
@ -67,9 +71,8 @@ describe('FileUploadMixin', () => {
it('shows an alert if the file size exceeds the maximum limit', () => { it('shows an alert if the file size exceeds the maximum limit', () => {
const fakeFile = { size: 999999999 }; const fakeFile = { size: 999999999 };
vm.showAlert = vi.fn();
vm.onIndirectFileUpload(fakeFile); vm.onIndirectFileUpload(fakeFile);
expect(vm.showAlert).toHaveBeenCalledWith(expect.any(String)); expect(useAlert).toHaveBeenCalledWith(expect.any(String));
}); });
}); });
}); });

View File

@ -1,28 +0,0 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import isAdminMixin from '../isAdmin';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('isAdminMixin', () => {
let getters;
let store;
beforeEach(() => {
getters = {
getCurrentRole: () => 'administrator',
};
store = new Vuex.Store({ getters });
});
it('set accountId properly', () => {
const Component = {
render() {},
title: 'TestComponent',
mixins: [isAdminMixin],
};
const wrapper = shallowMount(Component, { store, localVue });
expect(wrapper.vm.isAdmin).toBe(true);
});
});

View File

@ -19,7 +19,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import MergeContact from 'dashboard/modules/contact/components/MergeContact.vue'; import MergeContact from 'dashboard/modules/contact/components/MergeContact.vue';
import ContactAPI from 'dashboard/api/contacts'; import ContactAPI from 'dashboard/api/contacts';
@ -29,7 +29,6 @@ import { CONTACTS_EVENTS } from '../../helper/AnalyticsHelper/events';
export default { export default {
components: { MergeContact }, components: { MergeContact },
mixins: [alertMixin],
props: { props: {
primaryContact: { primaryContact: {
type: Object, type: Object,
@ -68,7 +67,7 @@ export default {
contact => contact.id !== this.primaryContact.id contact => contact.id !== this.primaryContact.id
); );
} catch (error) { } catch (error) {
this.showAlert(this.$t('MERGE_CONTACTS.SEARCH.ERROR_MESSAGE')); useAlert(this.$t('MERGE_CONTACTS.SEARCH.ERROR_MESSAGE'));
} finally { } finally {
this.isSearching = false; this.isSearching = false;
} }
@ -80,10 +79,10 @@ export default {
childId: this.primaryContact.id, childId: this.primaryContact.id,
parentId: parentContactId, parentId: parentContactId,
}); });
this.showAlert(this.$t('MERGE_CONTACTS.FORM.SUCCESS_MESSAGE')); useAlert(this.$t('MERGE_CONTACTS.FORM.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
this.showAlert(this.$t('MERGE_CONTACTS.FORM.ERROR_MESSAGE')); useAlert(this.$t('MERGE_CONTACTS.FORM.ERROR_MESSAGE'));
} }
}, },
}, },

View File

@ -21,7 +21,7 @@
:label="$t('CUSTOM_ATTRIBUTES.FORM.VALUE.LABEL')" :label="$t('CUSTOM_ATTRIBUTES.FORM.VALUE.LABEL')"
:placeholder="$t('CUSTOM_ATTRIBUTES.FORM.VALUE.PLACEHOLDER')" :placeholder="$t('CUSTOM_ATTRIBUTES.FORM.VALUE.PLACEHOLDER')"
/> />
<div class="flex justify-end items-center py-2 px-0 gap-2"> <div class="flex items-center justify-end gap-2 px-0 py-2">
<woot-button <woot-button
:is-disabled="$v.attributeName.$invalid || isCreating" :is-disabled="$v.attributeName.$invalid || isCreating"
:is-loading="isCreating" :is-loading="isCreating"
@ -38,14 +38,12 @@
<script> <script>
import Modal from 'dashboard/components/Modal.vue'; import Modal from 'dashboard/components/Modal.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
export default { export default {
components: { components: {
Modal, Modal,
}, },
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,

View File

@ -57,7 +57,7 @@
</span> </span>
</div> </div>
</div> </div>
<div class="multiselect-wrap--medium flex"> <div class="flex multiselect-wrap--medium">
<div <div
class="w-8 relative text-base text-slate-100 dark:text-slate-600 after:content-[''] after:h-12 after:w-0 after:left-4 after:absolute after:border-l after:border-solid after:border-slate-100 after:dark:border-slate-600 before:content-[''] before:h-0 before:w-4 before:left-4 before:top-12 before:absolute before:border-b before:border-solid before:border-slate-100 before:dark:border-slate-600" class="w-8 relative text-base text-slate-100 dark:text-slate-600 after:content-[''] after:h-12 after:w-0 after:left-4 after:absolute after:border-l after:border-solid after:border-slate-100 after:dark:border-slate-600 before:content-[''] before:h-0 before:w-4 before:left-4 before:top-12 before:absolute before:border-b before:border-solid before:border-slate-100 before:dark:border-slate-600"
> >
@ -102,7 +102,7 @@
:primary-contact-name="primaryContact.name" :primary-contact-name="primaryContact.name"
:parent-contact-name="parentContactName" :parent-contact-name="parentContactName"
/> />
<div class="mt-6 flex gap-2 justify-end"> <div class="flex justify-end gap-2 mt-6">
<woot-button variant="clear" @click.prevent="onCancel"> <woot-button variant="clear" @click.prevent="onCancel">
{{ $t('MERGE_CONTACTS.FORM.CANCEL') }} {{ $t('MERGE_CONTACTS.FORM.CANCEL') }}
</woot-button> </woot-button>
@ -114,7 +114,6 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import MergeContactSummary from 'dashboard/modules/contact/components/MergeContactSummary.vue'; import MergeContactSummary from 'dashboard/modules/contact/components/MergeContactSummary.vue';
@ -122,7 +121,6 @@ import ContactDropdownItem from './ContactDropdownItem.vue';
export default { export default {
components: { MergeContactSummary, ContactDropdownItem }, components: { MergeContactSummary, ContactDropdownItem },
mixins: [alertMixin],
props: { props: {
primaryContact: { primaryContact: {
type: Object, type: Object,

View File

@ -104,7 +104,7 @@
</div> </div>
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import AddCannedModal from 'dashboard/routes/dashboard/settings/canned/AddCanned.vue'; import AddCannedModal from 'dashboard/routes/dashboard/settings/canned/AddCanned.vue';
@ -123,7 +123,7 @@ export default {
TranslateModal, TranslateModal,
MenuItem, MenuItem,
}, },
mixins: [alertMixin, messageFormatterMixin], mixins: [messageFormatterMixin],
props: { props: {
message: { message: {
type: Object, type: Object,
@ -183,12 +183,12 @@ export default {
await copyTextToClipboard( await copyTextToClipboard(
`${fullConversationURL}?messageId=${this.messageId}` `${fullConversationURL}?messageId=${this.messageId}`
); );
this.showAlert(this.$t('CONVERSATION.CONTEXT_MENU.LINK_COPIED')); useAlert(this.$t('CONVERSATION.CONTEXT_MENU.LINK_COPIED'));
this.handleClose(); this.handleClose();
}, },
async handleCopy() { async handleCopy() {
await copyTextToClipboard(this.plainTextContent); await copyTextToClipboard(this.plainTextContent);
this.showAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL')); useAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL'));
this.handleClose(); this.handleClose();
}, },
showCannedResponseModal() { showCannedResponseModal() {
@ -233,10 +233,10 @@ export default {
conversationId: this.conversationId, conversationId: this.conversationId,
messageId: this.messageId, messageId: this.messageId,
}); });
this.showAlert(this.$t('CONVERSATION.SUCCESS_DELETE_MESSAGE')); useAlert(this.$t('CONVERSATION.SUCCESS_DELETE_MESSAGE'));
this.handleClose(); this.handleClose();
} catch (error) { } catch (error) {
this.showAlert(this.$t('CONVERSATION.FAIL_DELETE_MESSSAGE')); useAlert(this.$t('CONVERSATION.FAIL_DELETE_MESSSAGE'));
} }
}, },
closeDeleteModal() { closeDeleteModal() {

View File

@ -21,12 +21,10 @@ import appearanceHotKeys from './appearanceHotKeys';
import agentMixin from 'dashboard/mixins/agentMixin'; import agentMixin from 'dashboard/mixins/agentMixin';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin'; import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
import conversationTeamMixin from 'dashboard/mixins/conversation/teamMixin'; import conversationTeamMixin from 'dashboard/mixins/conversation/teamMixin';
import adminMixin from 'dashboard/mixins/isAdmin';
import { GENERAL_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { GENERAL_EVENTS } from '../../../helper/AnalyticsHelper/events';
export default { export default {
mixins: [ mixins: [
adminMixin,
agentMixin, agentMixin,
conversationHotKeysMixin, conversationHotKeysMixin,
bulkActionsHotKeysMixin, bulkActionsHotKeysMixin,

View File

@ -17,6 +17,7 @@ import {
} from './CommandBarIcons'; } from './CommandBarIcons';
import { frontendURL } from '../../../helper/URLHelper'; import { frontendURL } from '../../../helper/URLHelper';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import { FEATURE_FLAGS } from '../../../featureFlags'; import { FEATURE_FLAGS } from '../../../featureFlags';
const GO_TO_COMMANDS = [ const GO_TO_COMMANDS = [
@ -172,6 +173,12 @@ const GO_TO_COMMANDS = [
]; ];
export default { export default {
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
computed: { computed: {
...mapGetters({ ...mapGetters({
accountId: 'getCurrentAccountId', accountId: 'getCurrentAccountId',

View File

@ -9,12 +9,11 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import LabelSelector from 'dashboard/components/widgets/LabelSelector.vue'; import LabelSelector from 'dashboard/components/widgets/LabelSelector.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { LabelSelector }, components: { LabelSelector },
mixins: [alertMixin],
props: { props: {
contactId: { contactId: {
type: [String, Number], type: [String, Number],
@ -59,7 +58,7 @@ export default {
labels: selectedLabels, labels: selectedLabels,
}); });
} catch (error) { } catch (error) {
this.showAlert(this.$t('CONTACT_PANEL.LABELS.CONTACT.ERROR')); useAlert(this.$t('CONTACT_PANEL.LABELS.CONTACT.ERROR'));
} }
}, },

View File

@ -89,7 +89,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import FilterInputBox from '../../../../components/widgets/FilterInput/Index.vue'; import FilterInputBox from '../../../../components/widgets/FilterInput/Index.vue';
import countries from 'shared/constants/countries.js'; import countries from 'shared/constants/countries.js';
@ -102,7 +102,7 @@ export default {
components: { components: {
FilterInputBox, FilterInputBox,
}, },
mixins: [alertMixin, filterMixin], mixins: [filterMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,
@ -308,7 +308,7 @@ export default {
}, },
removeFilter(index) { removeFilter(index) {
if (this.appliedFilters.length <= 1) { if (this.appliedFilters.length <= 1) {
this.showAlert(this.$t('CONTACTS_FILTER.FILTER_DELETE_ERROR')); useAlert(this.$t('CONTACTS_FILTER.FILTER_DELETE_ERROR'));
} else { } else {
this.appliedFilters.splice(index, 1); this.appliedFilters.splice(index, 1);
} }

View File

@ -81,6 +81,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import ContactsHeader from './Header.vue'; import ContactsHeader from './Header.vue';
import ContactsTable from './ContactsTable.vue'; import ContactsTable from './ContactsTable.vue';
@ -94,7 +95,6 @@ import filterQueryGenerator from '../../../../helper/filterQueryGenerator';
import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue'; import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue';
import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue'; import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue';
import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import alertMixin from 'shared/mixins/alertMixin';
import countries from 'shared/constants/countries.js'; import countries from 'shared/constants/countries.js';
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper'; import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
@ -113,7 +113,6 @@ export default {
AddCustomViews, AddCustomViews,
DeleteCustomViews, DeleteCustomViews,
}, },
mixins: [alertMixin],
props: { props: {
label: { type: String, default: '' }, label: { type: String, default: '' },
segmentsId: { segmentsId: {
@ -404,11 +403,9 @@ export default {
...query, ...query,
label: this.label, label: this.label,
}); });
this.showAlert(this.$t('EXPORT_CONTACTS.SUCCESS_MESSAGE')); useAlert(this.$t('EXPORT_CONTACTS.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert( useAlert(error.message || this.$t('EXPORT_CONTACTS.ERROR_MESSAGE'));
error.message || this.$t('EXPORT_CONTACTS.ERROR_MESSAGE')
);
} }
}, },
setParamsForEditSegmentModal() { setParamsForEditSegmentModal() {

View File

@ -125,10 +125,9 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin'; import { useAdmin } from 'dashboard/composables/useAdmin';
export default { export default {
mixins: [adminMixin],
props: { props: {
headerTitle: { headerTitle: {
type: String, type: String,
@ -143,6 +142,12 @@ export default {
default: 0, default: 0,
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data() { data() {
return { return {
showCreateModal: false, showCreateModal: false,

View File

@ -1,6 +1,6 @@
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header :header-title="$t('IMPORT_CONTACTS.TITLE')"> <woot-modal-header :header-title="$t('IMPORT_CONTACTS.TITLE')">
<p> <p>
{{ $t('IMPORT_CONTACTS.DESC') }} {{ $t('IMPORT_CONTACTS.DESC') }}
@ -22,7 +22,7 @@
/> />
</label> </label>
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<div class="w-full"> <div class="w-full">
<woot-button <woot-button
:disabled="uiFlags.isCreating || !file" :disabled="uiFlags.isCreating || !file"
@ -42,16 +42,15 @@
</template> </template>
<script> <script>
import Modal from '../../../../components/Modal.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import Modal from '../../../../components/Modal.vue';
export default { export default {
components: { components: {
Modal, Modal,
}, },
mixins: [alertMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,
@ -81,12 +80,10 @@ export default {
if (!this.file) return; if (!this.file) return;
await this.$store.dispatch('contacts/import', this.file); await this.$store.dispatch('contacts/import', this.file);
this.onClose(); this.onClose();
this.showAlert(this.$t('IMPORT_CONTACTS.SUCCESS_MESSAGE')); useAlert(this.$t('IMPORT_CONTACTS.SUCCESS_MESSAGE'));
this.$track(CONTACTS_EVENTS.IMPORT_SUCCESS); this.$track(CONTACTS_EVENTS.IMPORT_SUCCESS);
} catch (error) { } catch (error) {
this.showAlert( useAlert(error.message || this.$t('IMPORT_CONTACTS.ERROR_MESSAGE'));
error.message || this.$t('IMPORT_CONTACTS.ERROR_MESSAGE')
);
this.$track(CONTACTS_EVENTS.IMPORT_FAILURE); this.$track(CONTACTS_EVENTS.IMPORT_FAILURE);
} }
}, },

View File

@ -133,7 +133,6 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import AccordionItem from 'dashboard/components/Accordion/AccordionItem.vue'; import AccordionItem from 'dashboard/components/Accordion/AccordionItem.vue';
import ContactConversations from './ContactConversations.vue'; import ContactConversations from './ContactConversations.vue';
import ConversationAction from './ConversationAction.vue'; import ConversationAction from './ConversationAction.vue';
@ -157,7 +156,7 @@ export default {
draggable, draggable,
MacrosList, MacrosList,
}, },
mixins: [alertMixin, uiSettingsMixin], mixins: [uiSettingsMixin],
props: { props: {
conversationId: { conversationId: {
type: [Number, String], type: [Number, String],

View File

@ -82,7 +82,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import ContactDetailsItem from './ContactDetailsItem.vue'; import ContactDetailsItem from './ContactDetailsItem.vue';
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue'; import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
import ConversationLabels from './labels/LabelBox.vue'; import ConversationLabels from './labels/LabelBox.vue';
@ -97,7 +97,7 @@ export default {
MultiselectDropdown, MultiselectDropdown,
ConversationLabels, ConversationLabels,
}, },
mixins: [agentMixin, alertMixin, teamMixin], mixins: [agentMixin, teamMixin],
props: { props: {
conversationId: { conversationId: {
type: [Number, String], type: [Number, String],
@ -157,7 +157,7 @@ export default {
agentId, agentId,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('CONVERSATION.CHANGE_AGENT')); useAlert(this.$t('CONVERSATION.CHANGE_AGENT'));
}); });
}, },
}, },
@ -172,7 +172,7 @@ export default {
this.$store this.$store
.dispatch('assignTeam', { conversationId, teamId }) .dispatch('assignTeam', { conversationId, teamId })
.then(() => { .then(() => {
this.showAlert(this.$t('CONVERSATION.CHANGE_TEAM')); useAlert(this.$t('CONVERSATION.CHANGE_TEAM'));
}); });
}, },
}, },
@ -201,7 +201,7 @@ export default {
newValue: priority, newValue: priority,
from: 'Conversation Sidebar', from: 'Conversation Sidebar',
}); });
this.showAlert( useAlert(
this.$t('CONVERSATION.PRIORITY.CHANGE_PRIORITY.SUCCESSFUL', { this.$t('CONVERSATION.PRIORITY.CHANGE_PRIORITY.SUCCESSFUL', {
priority: priorityItem.name, priority: priorityItem.name,
conversationId, conversationId,

View File

@ -79,7 +79,7 @@
<script> <script>
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import agentMixin from 'dashboard/mixins/agentMixin'; import agentMixin from 'dashboard/mixins/agentMixin';
import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue'; import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue';
@ -91,7 +91,7 @@ export default {
ThumbnailGroup, ThumbnailGroup,
MultiselectDropdownItems, MultiselectDropdownItems,
}, },
mixins: [alertMixin, agentMixin], mixins: [agentMixin],
props: { props: {
conversationId: { conversationId: {
type: [Number, String], type: [Number, String],
@ -197,7 +197,7 @@ export default {
error?.message || error?.message ||
this.$t('CONVERSATION_PARTICIPANTS.API.ERROR_MESSAGE'); this.$t('CONVERSATION_PARTICIPANTS.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(alertMessage); useAlert(alertMessage);
} }
this.fetchParticipants(); this.fetchParticipants();
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<section class="conversation-page bg-white dark:bg-slate-900"> <section class="bg-white conversation-page dark:bg-slate-900">
<chat-list <chat-list
:show-conversation-list="showConversationList" :show-conversation-list="showConversationList"
:conversation-inbox="inboxId" :conversation-inbox="inboxId"
@ -36,13 +36,13 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { getUnixTime } from 'date-fns'; import { getUnixTime } from 'date-fns';
import ChatList from '../../../components/ChatList.vue'; import ChatList from '../../../components/ChatList.vue';
import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue'; import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
import PopOverSearch from './search/PopOverSearch.vue'; import PopOverSearch from './search/PopOverSearch.vue';
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue'; import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import alertMixin from 'shared/mixins/alertMixin';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents'; import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
@ -55,7 +55,7 @@ export default {
PopOverSearch, PopOverSearch,
CustomSnoozeModal, CustomSnoozeModal,
}, },
mixins: [uiSettingsMixin, alertMixin], mixins: [uiSettingsMixin],
props: { props: {
inboxId: { inboxId: {
type: [String, Number], type: [String, Number],
@ -235,7 +235,7 @@ export default {
}) })
.then(() => { .then(() => {
this.$store.dispatch('setContextMenuChatId', null); this.$store.dispatch('setContextMenuChatId', null);
this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS')); useAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
}); });
}, },
hideCustomSnoozeModal() { hideCustomSnoozeModal() {

View File

@ -3,7 +3,7 @@
<span class="overflow-hidden whitespace-nowrap text-ellipsis">{{ <span class="overflow-hidden whitespace-nowrap text-ellipsis">{{
macro.name macro.name
}}</span> }}</span>
<div class="macros-actions flex items-center gap-1"> <div class="flex items-center gap-1 macros-actions">
<woot-button <woot-button
v-tooltip.left-start="$t('MACROS.EXECUTE.PREVIEW')" v-tooltip.left-start="$t('MACROS.EXECUTE.PREVIEW')"
size="tiny" size="tiny"
@ -33,7 +33,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import MacroPreview from './MacroPreview.vue'; import MacroPreview from './MacroPreview.vue';
import { CONVERSATION_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../../helper/AnalyticsHelper/events';
@ -41,7 +41,6 @@ export default {
components: { components: {
MacroPreview, MacroPreview,
}, },
mixins: [alertMixin],
props: { props: {
macro: { macro: {
type: Object, type: Object,
@ -67,9 +66,9 @@ export default {
conversationIds: [this.conversationId], conversationIds: [this.conversationId],
}); });
this.$track(CONVERSATION_EVENTS.EXECUTED_A_MACRO); this.$track(CONVERSATION_EVENTS.EXECUTED_A_MACRO);
this.showAlert(this.$t('MACROS.EXECUTE.EXECUTED_SUCCESSFULLY')); useAlert(this.$t('MACROS.EXECUTE.EXECUTED_SUCCESSFULLY'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('MACROS.ERROR')); useAlert(this.$t('MACROS.ERROR'));
} finally { } finally {
this.isExecuting = false; this.isExecuting = false;
} }

View File

@ -150,7 +150,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { import {
DuplicateContactException, DuplicateContactException,
ExceptionWithMessage, ExceptionWithMessage,
@ -161,7 +161,6 @@ import { isPhoneNumberValid } from 'shared/helpers/Validators';
import parsePhoneNumber from 'libphonenumber-js'; import parsePhoneNumber from 'libphonenumber-js';
export default { export default {
mixins: [alertMixin],
props: { props: {
contact: { contact: {
type: Object, type: Object,
@ -375,20 +374,18 @@ export default {
try { try {
await this.onSubmit(this.getContactObject()); await this.onSubmit(this.getContactObject());
this.onSuccess(); this.onSuccess();
this.showAlert(this.$t('CONTACT_FORM.SUCCESS_MESSAGE')); useAlert(this.$t('CONTACT_FORM.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
if (error instanceof DuplicateContactException) { if (error instanceof DuplicateContactException) {
if (error.data.includes('email')) { if (error.data.includes('email')) {
this.showAlert( useAlert(this.$t('CONTACT_FORM.FORM.EMAIL_ADDRESS.DUPLICATE'));
this.$t('CONTACT_FORM.FORM.EMAIL_ADDRESS.DUPLICATE')
);
} else if (error.data.includes('phone_number')) { } else if (error.data.includes('phone_number')) {
this.showAlert(this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DUPLICATE')); useAlert(this.$t('CONTACT_FORM.FORM.PHONE_NUMBER.DUPLICATE'));
} }
} else if (error instanceof ExceptionWithMessage) { } else if (error instanceof ExceptionWithMessage) {
this.showAlert(error.data); useAlert(error.data);
} else { } else {
this.showAlert(this.$t('CONTACT_FORM.ERROR_MESSAGE')); useAlert(this.$t('CONTACT_FORM.ERROR_MESSAGE'));
} }
} }
}, },
@ -400,15 +397,13 @@ export default {
try { try {
if (this.contact && this.contact.id) { if (this.contact && this.contact.id) {
await this.$store.dispatch('contacts/deleteAvatar', this.contact.id); await this.$store.dispatch('contacts/deleteAvatar', this.contact.id);
this.showAlert( useAlert(this.$t('CONTACT_FORM.DELETE_AVATAR.API.SUCCESS_MESSAGE'));
this.$t('CONTACT_FORM.DELETE_AVATAR.API.SUCCESS_MESSAGE')
);
} }
this.avatarFile = null; this.avatarFile = null;
this.avatarUrl = ''; this.avatarUrl = '';
this.activeDialCode = ''; this.activeDialCode = '';
} catch (error) { } catch (error) {
this.showAlert( useAlert(
error.message error.message
? error.message ? error.message
: this.$t('CONTACT_FORM.DELETE_AVATAR.API.ERROR_MESSAGE') : this.$t('CONTACT_FORM.DELETE_AVATAR.API.ERROR_MESSAGE')

View File

@ -166,17 +166,16 @@
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { dynamicTime } from 'shared/helpers/timeHelper'; import { dynamicTime } from 'shared/helpers/timeHelper';
import { useAdmin } from 'dashboard/composables/useAdmin';
import ContactInfoRow from './ContactInfoRow.vue'; import ContactInfoRow from './ContactInfoRow.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import SocialIcons from './SocialIcons.vue'; import SocialIcons from './SocialIcons.vue';
import EditContact from './EditContact.vue'; import EditContact from './EditContact.vue';
import NewConversation from './NewConversation.vue'; import NewConversation from './NewConversation.vue';
import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue'; import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue';
import alertMixin from 'shared/mixins/alertMixin';
import adminMixin from '../../../../mixins/isAdmin';
import { mapGetters } from 'vuex';
import { getCountryFlag } from 'dashboard/helper/flag'; import { getCountryFlag } from 'dashboard/helper/flag';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import { import {
@ -194,7 +193,6 @@ export default {
NewConversation, NewConversation,
ContactMergeModal, ContactMergeModal,
}, },
mixins: [alertMixin, adminMixin],
props: { props: {
contact: { contact: {
type: Object, type: Object,
@ -217,6 +215,12 @@ export default {
default: 'chevron-right', default: 'chevron-right',
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data() { data() {
return { return {
showEditModal: false, showEditModal: false,
@ -301,7 +305,7 @@ export default {
try { try {
await this.$store.dispatch('contacts/delete', id); await this.$store.dispatch('contacts/delete', id);
this.$emit('panel-close'); this.$emit('panel-close');
this.showAlert(this.$t('DELETE_CONTACT.API.SUCCESS_MESSAGE')); useAlert(this.$t('DELETE_CONTACT.API.SUCCESS_MESSAGE'));
if (isAConversationRoute(this.$route.name)) { if (isAConversationRoute(this.$route.name)) {
this.$router.push({ this.$router.push({
@ -317,7 +321,7 @@ export default {
}); });
} }
} catch (error) { } catch (error) {
this.showAlert( useAlert(
error.message error.message
? error.message ? error.message
: this.$t('DELETE_CONTACT.API.ERROR_MESSAGE') : this.$t('DELETE_CONTACT.API.ERROR_MESSAGE')

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="ltr:-ml-1 rtl:-mr-1 h-5 w-full"> <div class="w-full h-5 ltr:-ml-1 rtl:-mr-1">
<a <a
v-if="href" v-if="href"
:href="href" :href="href"
@ -9,16 +9,16 @@
:icon="icon" :icon="icon"
:emoji="emoji" :emoji="emoji"
icon-size="14" icon-size="14"
class="ltr:ml-1 rtl:mr-1 flex-shrink-0" class="flex-shrink-0 ltr:ml-1 rtl:mr-1"
/> />
<span <span
v-if="value" v-if="value"
class="overflow-hidden whitespace-nowrap text-ellipsis text-sm" class="overflow-hidden text-sm whitespace-nowrap text-ellipsis"
:title="value" :title="value"
> >
{{ value }} {{ value }}
</span> </span>
<span v-else class="text-slate-300 dark:text-slate-600 text-sm">{{ <span v-else class="text-sm text-slate-300 dark:text-slate-600">{{
$t('CONTACT_PANEL.NOT_AVAILABLE') $t('CONTACT_PANEL.NOT_AVAILABLE')
}}</span> }}</span>
@ -42,22 +42,22 @@
:icon="icon" :icon="icon"
:emoji="emoji" :emoji="emoji"
icon-size="14" icon-size="14"
class="ltr:ml-1 rtl:mr-1 flex-shrink-0" class="flex-shrink-0 ltr:ml-1 rtl:mr-1"
/> />
<span <span
v-if="value" v-if="value"
class="overflow-hidden whitespace-nowrap text-ellipsis text-sm" class="overflow-hidden text-sm whitespace-nowrap text-ellipsis"
> >
{{ value }} {{ value }}
</span> </span>
<span v-else class="text-slate-300 dark:text-slate-600 text-sm">{{ <span v-else class="text-sm text-slate-300 dark:text-slate-600">{{
$t('CONTACT_PANEL.NOT_AVAILABLE') $t('CONTACT_PANEL.NOT_AVAILABLE')
}}</span> }}</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
@ -65,7 +65,6 @@ export default {
components: { components: {
EmojiOrIcon, EmojiOrIcon,
}, },
mixins: [alertMixin],
props: { props: {
href: { href: {
type: String, type: String,
@ -92,7 +91,7 @@ export default {
async onCopy(e) { async onCopy(e) {
e.preventDefault(); e.preventDefault();
await copyTextToClipboard(this.value); await copyTextToClipboard(this.value);
this.showAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL')); useAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL'));
}, },
}, },
}; };

View File

@ -1,5 +1,5 @@
<template> <template>
<form class="conversation--form w-full" @submit.prevent="onFormSubmit"> <form class="w-full conversation--form" @submit.prevent="onFormSubmit">
<div <div
v-if="showNoInboxAlert" v-if="showNoInboxAlert"
class="relative mx-0 mt-0 mb-2.5 p-2 rounded-none text-sm border border-solid border-yellow-500 dark:border-yellow-700 bg-yellow-200/60 dark:bg-yellow-200/20 text-slate-700 dark:text-yellow-400" class="relative mx-0 mt-0 mb-2.5 p-2 rounded-none text-sm border border-solid border-yellow-500 dark:border-yellow-700 bg-yellow-200/60 dark:bg-yellow-200/20 text-slate-700 dark:text-yellow-400"
@ -9,7 +9,7 @@
</p> </p>
</div> </div>
<div v-else> <div v-else>
<div class="gap-2 flex flex-row"> <div class="flex flex-row gap-2">
<div class="w-[50%]"> <div class="w-[50%]">
<label> <label>
{{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }} {{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }}
@ -69,7 +69,7 @@
:status="contact.availability_status" :status="contact.availability_status"
/> />
<h4 <h4
class="m-0 ml-2 mr-2 text-slate-700 dark:text-slate-100 text-sm" class="m-0 ml-2 mr-2 text-sm text-slate-700 dark:text-slate-100"
> >
{{ contact.name }} {{ contact.name }}
</h4> </h4>
@ -128,7 +128,7 @@
v-if="isSignatureEnabledForInbox && !messageSignature" v-if="isSignatureEnabledForInbox && !messageSignature"
class="!mx-0 mb-1" class="!mx-0 mb-1"
/> />
<div v-if="isAnEmailInbox" class="mb-3 mt-px"> <div v-if="isAnEmailInbox" class="mt-px mb-3">
<woot-button <woot-button
v-tooltip.top-end="signatureToggleTooltip" v-tooltip.top-end="signatureToggleTooltip"
icon="signature" icon="signature"
@ -191,7 +191,7 @@
{{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.SELECT') }} {{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.SELECT') }}
</woot-button> </woot-button>
<span <span
class="text-slate-500 ltr:ml-1 rtl:mr-1 font-medium text-xs dark:text-slate-400" class="text-xs font-medium text-slate-500 ltr:ml-1 rtl:mr-1 dark:text-slate-400"
> >
{{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.HELP_TEXT') }} {{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.HELP_TEXT') }}
</span> </span>
@ -213,7 +213,7 @@
<div <div
v-if="!hasWhatsappTemplates" v-if="!hasWhatsappTemplates"
class="flex flex-row justify-end gap-2 py-2 px-0 w-full" class="flex flex-row justify-end w-full gap-2 px-0 py-2"
> >
<button class="button clear" @click.prevent="onCancel"> <button class="button clear" @click.prevent="onCancel">
{{ $t('NEW_CONVERSATION.FORM.CANCEL') }} {{ $t('NEW_CONVERSATION.FORM.CANCEL') }}
@ -226,7 +226,7 @@
<transition v-if="isEmailOrWebWidgetInbox" name="modal-fade"> <transition v-if="isEmailOrWebWidgetInbox" name="modal-fade">
<div <div
v-show="$refs.uploadAttachment && $refs.uploadAttachment.dropActive" v-show="$refs.uploadAttachment && $refs.uploadAttachment.dropActive"
class="flex top-0 bottom-0 z-30 gap-2 right-0 left-0 items-center justify-center flex-col absolute w-full h-full bg-white/80 dark:bg-slate-700/80" class="absolute top-0 bottom-0 left-0 right-0 z-30 flex flex-col items-center justify-center w-full h-full gap-2 bg-white/80 dark:bg-slate-700/80"
> >
<fluent-icon icon="cloud-backup" size="40" /> <fluent-icon icon="cloud-backup" size="40" />
<h4 class="text-2xl break-words text-slate-600 dark:text-slate-200"> <h4 class="text-2xl break-words text-slate-600 dark:text-slate-200">
@ -239,6 +239,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue'; import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue';
@ -246,7 +247,6 @@ import CannedResponse from 'dashboard/components/widgets/conversation/CannedResp
import MessageSignatureMissingAlert from 'dashboard/components/widgets/conversation/MessageSignatureMissingAlert'; import MessageSignatureMissingAlert from 'dashboard/components/widgets/conversation/MessageSignatureMissingAlert';
import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem.vue'; import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem.vue';
import WhatsappTemplates from './WhatsappTemplates.vue'; import WhatsappTemplates from './WhatsappTemplates.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { INBOX_TYPES } from 'shared/mixins/inboxMixin'; import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors'; import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
import { getInboxSource } from 'dashboard/helper/inbox'; import { getInboxSource } from 'dashboard/helper/inbox';
@ -274,7 +274,7 @@ export default {
AttachmentPreview, AttachmentPreview,
MessageSignatureMissingAlert, MessageSignatureMissingAlert,
}, },
mixins: [alertMixin, uiSettingsMixin, inboxMixin, fileUploadMixin], mixins: [uiSettingsMixin, inboxMixin, fileUploadMixin],
props: { props: {
contact: { contact: {
type: Object, type: Object,
@ -515,15 +515,12 @@ export default {
message: this.$t('NEW_CONVERSATION.FORM.GO_TO_CONVERSATION'), message: this.$t('NEW_CONVERSATION.FORM.GO_TO_CONVERSATION'),
}; };
this.onSuccess(); this.onSuccess();
this.showAlert( useAlert(this.$t('NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'), action);
this.$t('NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'),
action
);
} catch (error) { } catch (error) {
if (error instanceof ExceptionWithMessage) { if (error instanceof ExceptionWithMessage) {
this.showAlert(error.data); useAlert(error.data);
} else { } else {
this.showAlert(this.$t('NEW_CONVERSATION.FORM.ERROR_MESSAGE')); useAlert(this.$t('NEW_CONVERSATION.FORM.ERROR_MESSAGE'));
} }
} }
}, },

View File

@ -42,7 +42,7 @@
<script> <script>
import CustomAttribute from 'dashboard/components/CustomAttribute.vue'; import CustomAttribute from 'dashboard/components/CustomAttribute.vue';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import attributeMixin from 'dashboard/mixins/attributeMixin'; import attributeMixin from 'dashboard/mixins/attributeMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
@ -51,7 +51,7 @@ export default {
components: { components: {
CustomAttribute, CustomAttribute,
}, },
mixins: [alertMixin, attributeMixin, uiSettingsMixin], mixins: [attributeMixin, uiSettingsMixin],
props: { props: {
attributeType: { attributeType: {
type: String, type: String,
@ -141,12 +141,12 @@ export default {
custom_attributes: updatedAttributes, custom_attributes: updatedAttributes,
}); });
} }
this.showAlert(this.$t('CUSTOM_ATTRIBUTES.FORM.UPDATE.SUCCESS')); useAlert(this.$t('CUSTOM_ATTRIBUTES.FORM.UPDATE.SUCCESS'));
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || error?.response?.message ||
this.$t('CUSTOM_ATTRIBUTES.FORM.UPDATE.ERROR'); this.$t('CUSTOM_ATTRIBUTES.FORM.UPDATE.ERROR');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
async onDelete(key) { async onDelete(key) {
@ -164,17 +164,17 @@ export default {
}); });
} }
this.showAlert(this.$t('CUSTOM_ATTRIBUTES.FORM.DELETE.SUCCESS')); useAlert(this.$t('CUSTOM_ATTRIBUTES.FORM.DELETE.SUCCESS'));
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || error?.response?.message ||
this.$t('CUSTOM_ATTRIBUTES.FORM.DELETE.ERROR'); this.$t('CUSTOM_ATTRIBUTES.FORM.DELETE.ERROR');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
async onCopy(attributeValue) { async onCopy(attributeValue) {
await copyTextToClipboard(attributeValue); await copyTextToClipboard(attributeValue);
this.showAlert(this.$t('CUSTOM_ATTRIBUTES.COPY_SUCCESSFUL')); useAlert(this.$t('CUSTOM_ATTRIBUTES.COPY_SUCCESSFUL'));
}, },
}, },
}; };

View File

@ -45,10 +45,10 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import adminMixin from 'dashboard/mixins/isAdmin';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin'; import conversationLabelMixin from 'dashboard/mixins/conversation/labelMixin';
@ -59,14 +59,19 @@ export default {
AddLabel, AddLabel,
}, },
mixins: [conversationLabelMixin, adminMixin, keyboardEventListenerMixins], mixins: [conversationLabelMixin, keyboardEventListenerMixins],
props: { props: {
conversationId: { conversationId: {
type: Number, type: Number,
required: true, required: true,
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
data() { data() {
return { return {
selectedLabels: [], selectedLabels: [],

View File

@ -30,11 +30,10 @@
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events';
export default { export default {
mixins: [alertMixin],
props: { props: {
filterType: { filterType: {
type: Number, type: Number,
@ -101,7 +100,7 @@ export default {
? errorMessage ? errorMessage
: this.$t('FILTER.CUSTOM_VIEWS.ADD.API_SEGMENTS.ERROR_MESSAGE'); : this.$t('FILTER.CUSTOM_VIEWS.ADD.API_SEGMENTS.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
this.openLastSavedItem(); this.openLastSavedItem();
}, },

View File

@ -16,10 +16,9 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events';
export default { export default {
mixins: [alertMixin],
props: { props: {
showDeletePopup: { showDeletePopup: {
type: Boolean, type: Boolean,
@ -79,7 +78,7 @@ export default {
const filterType = this.activeCustomViews; const filterType = this.activeCustomViews;
await this.$store.dispatch('customViews/delete', { id, filterType }); await this.$store.dispatch('customViews/delete', { id, filterType });
this.closeDeletePopup(); this.closeDeletePopup();
this.showAlert( useAlert(
this.activeFilterType === 0 this.activeFilterType === 0
? this.$t('FILTER.CUSTOM_VIEWS.DELETE.API_FOLDERS.SUCCESS_MESSAGE') ? this.$t('FILTER.CUSTOM_VIEWS.DELETE.API_FOLDERS.SUCCESS_MESSAGE')
: this.$t('FILTER.CUSTOM_VIEWS.DELETE.API_SEGMENTS.SUCCESS_MESSAGE') : this.$t('FILTER.CUSTOM_VIEWS.DELETE.API_SEGMENTS.SUCCESS_MESSAGE')
@ -94,7 +93,7 @@ export default {
: this.$t( : this.$t(
'FILTER.CUSTOM_VIEWS.DELETE.API_SEGMENTS.SUCCESS_MESSAGE' 'FILTER.CUSTOM_VIEWS.DELETE.API_SEGMENTS.SUCCESS_MESSAGE'
); );
this.showAlert(errorMessage); useAlert(errorMessage);
} }
this.openLastItemAfterDelete(); this.openLastItemAfterDelete();
}, },

View File

@ -24,7 +24,7 @@
</label> </label>
<div class="w-full"> <div class="w-full">
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button class="button clear" @click.prevent="onClose"> <woot-button class="button clear" @click.prevent="onClose">
{{ $t('HELP_CENTER.PORTAL.ADD_LOCALE.BUTTONS.CANCEL') }} {{ $t('HELP_CENTER.PORTAL.ADD_LOCALE.BUTTONS.CANCEL') }}
</woot-button> </woot-button>
@ -39,16 +39,15 @@
</template> </template>
<script> <script>
import Modal from 'dashboard/components/Modal.vue'; import { useAlert } from 'dashboard/composables';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import allLocales from 'shared/constants/locales.js'; import allLocales from 'shared/constants/locales.js';
import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import Modal from 'dashboard/components/Modal.vue';
export default { export default {
components: { components: {
Modal, Modal,
}, },
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@ -120,7 +119,7 @@ export default {
error?.message || error?.message ||
this.$t('HELP_CENTER.PORTAL.ADD_LOCALE.API.ERROR_MESSAGE'); this.$t('HELP_CENTER.PORTAL.ADD_LOCALE.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
this.isUpdating = false; this.isUpdating = false;
} }
}, },

View File

@ -1,17 +1,17 @@
<template> <template>
<button <button
class="flex flex-col gap-1 bg-white dark:bg-slate-900 hover:bg-slate-25 hover:dark:bg-slate-800 rounded-md py-1 px-2 w-full group border border-transparent border-solid focus:outline-none focus:bg-slate-25 focus:border-slate-500 dark:focus:border-slate-400 dark:focus:bg-slate-800 cursor-pointer" class="flex flex-col w-full gap-1 px-2 py-1 bg-white border border-transparent border-solid rounded-md cursor-pointer dark:bg-slate-900 hover:bg-slate-25 hover:dark:bg-slate-800 group focus:outline-none focus:bg-slate-25 focus:border-slate-500 dark:focus:border-slate-400 dark:focus:bg-slate-800"
@click="handlePreview" @click="handlePreview"
> >
<h4 <h4
class="text-sm ltr:text-left rtl:text-right w-full mb-0 text-slate-900 dark:text-slate-25 -mx-1 rounded-sm hover:underline group-hover:underline" class="w-full mb-0 -mx-1 text-sm rounded-sm ltr:text-left rtl:text-right text-slate-900 dark:text-slate-25 hover:underline group-hover:underline"
> >
{{ title }} {{ title }}
</h4> </h4>
<div class="flex content-between items-center gap-0.5 w-full"> <div class="flex content-between items-center gap-0.5 w-full">
<p <p
class="text-sm ltr:text-left rtl:text-right text-slate-600 dark:text-slate-300 mb-0 w-full" class="w-full mb-0 text-sm ltr:text-left rtl:text-right text-slate-600 dark:text-slate-300"
> >
{{ locale }} {{ locale }}
{{ ` / ` }} {{ ` / ` }}
@ -42,12 +42,11 @@
</template> </template>
<script> <script>
import { useAlert } from 'dashboard/composables';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
name: 'ArticleSearchResultItem', name: 'ArticleSearchResultItem',
mixins: [alertMixin],
props: { props: {
id: { id: {
type: Number, type: Number,
@ -86,7 +85,7 @@ export default {
async handleCopy(e) { async handleCopy(e) {
e.stopPropagation(); e.stopPropagation();
await copyTextToClipboard(this.url); await copyTextToClipboard(this.url);
this.showAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL')); useAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL'));
}, },
}, },
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="fixed flex items-center justify-center w-screen h-screen bg-modal-backdrop-light dark:bg-modal-backdrop-dark top-0 left-0 z-50" class="fixed top-0 left-0 z-50 flex items-center justify-center w-screen h-screen bg-modal-backdrop-light dark:bg-modal-backdrop-dark"
> >
<div <div
v-on-clickaway="onClose" v-on-clickaway="onClose"
@ -34,6 +34,7 @@
<script> <script>
import { debounce } from '@chatwoot/utils'; import { debounce } from '@chatwoot/utils';
import { useAlert } from 'dashboard/composables';
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import SearchHeader from './Header.vue'; import SearchHeader from './Header.vue';
@ -42,7 +43,6 @@ import ArticleView from './ArticleView.vue';
import ArticlesAPI from 'dashboard/api/helpCenter/articles'; import ArticlesAPI from 'dashboard/api/helpCenter/articles';
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper'; import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
import portalMixin from '../../mixins/portalMixin'; import portalMixin from '../../mixins/portalMixin';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
name: 'ArticleSearchPopover', name: 'ArticleSearchPopover',
@ -51,7 +51,7 @@ export default {
SearchResults, SearchResults,
ArticleView, ArticleView,
}, },
mixins: [portalMixin, alertMixin, keyboardEventListenerMixins], mixins: [portalMixin, keyboardEventListenerMixins],
props: { props: {
selectedPortalSlug: { selectedPortalSlug: {
type: String, type: String,
@ -145,9 +145,7 @@ export default {
const article = this.activeArticle(id || this.activeId); const article = this.activeArticle(id || this.activeId);
this.$emit('insert', article); this.$emit('insert', article);
this.showAlert( useAlert(this.$t('HELP_CENTER.ARTICLE_SEARCH.SUCCESS_ARTICLE_INSERTED'));
this.$t('HELP_CENTER.ARTICLE_SEARCH.SUCCESS_ARTICLE_INSERTED')
);
this.onClose(); this.onClose();
}, },
getKeyboardEvents() { getKeyboardEvents() {

View File

@ -108,14 +108,13 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
const { ARTICLE_STATUS_TYPES } = wootConstants; const { ARTICLE_STATUS_TYPES } = wootConstants;
export default { export default {
mixins: [alertMixin],
props: { props: {
isSidebarOpen: { isSidebarOpen: {
type: Boolean, type: Boolean,
@ -200,7 +199,7 @@ export default {
this.alertMessage = this.alertMessage =
error?.message || this.statusUpdateErrorMessage(status); error?.message || this.statusUpdateErrorMessage(status);
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
statusUpdateSuccessMessage(status) { statusUpdateSuccessMessage(status) {

View File

@ -1,10 +1,10 @@
<template> <template>
<div> <div>
<div <div
class="bg-white dark:bg-slate-900 rounded-md relative flex mb-3 p-4 border border-solid border-slate-100 dark:border-slate-600" class="relative flex p-4 mb-3 bg-white border border-solid rounded-md dark:bg-slate-900 border-slate-100 dark:border-slate-600"
> >
<thumbnail :username="portal.name" variant="square" /> <thumbnail :username="portal.name" variant="square" />
<div class="ml-2 rtl:ml-0 rtl:mr-2 flex-grow"> <div class="flex-grow ml-2 rtl:ml-0 rtl:mr-2">
<header class="flex items-start justify-between mb-8"> <header class="flex items-start justify-between mb-8">
<div> <div>
<div class="flex items-center"> <div class="flex items-center">
@ -16,10 +16,10 @@
:color-scheme="labelColor" :color-scheme="labelColor"
size="small" size="small"
variant="smooth" variant="smooth"
class="my-0 mx-2" class="mx-2 my-0"
/> />
</div> </div>
<p class="text-sm mb-0 text-slate-700 dark:text-slate-200"> <p class="mb-0 text-sm text-slate-700 dark:text-slate-200">
{{ articleCount }} {{ articleCount }}
{{ {{
$t( $t(
@ -75,7 +75,7 @@
</header> </header>
<div class="mb-12"> <div class="mb-12">
<h2 <h2
class="text-slate-800 dark:text-slate-100 font-medium mb-2 text-base" class="mb-2 text-base font-medium text-slate-800 dark:text-slate-100"
> >
{{ {{
$t( $t(
@ -87,7 +87,7 @@
class="flex justify-between mr-[6.25rem] rtl:mr-0 rtl:ml-[6.25rem] max-w-[80vw]" class="flex justify-between mr-[6.25rem] rtl:mr-0 rtl:ml-[6.25rem] max-w-[80vw]"
> >
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.NAME' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.NAME'
@ -97,7 +97,7 @@
{{ portal.name }} {{ portal.name }}
</span> </span>
</div> </div>
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.DOMAIN' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.DOMAIN'
@ -109,7 +109,7 @@
</div> </div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.SLUG' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.SLUG'
@ -119,7 +119,7 @@
{{ portal.slug }} {{ portal.slug }}
</span> </span>
</div> </div>
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.TITLE' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.TITLE'
@ -131,7 +131,7 @@
</div> </div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.THEME' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.THEME'
@ -139,12 +139,12 @@
}}</label> }}</label>
<div class="flex items-center"> <div class="flex items-center">
<div <div
class="w-4 h-4 rounded-md mr-1 rtl:mr-0 rtl:ml-1 border border-solid border-slate-25 dark:border-slate-800" class="w-4 h-4 mr-1 border border-solid rounded-md rtl:mr-0 rtl:ml-1 border-slate-25 dark:border-slate-800"
:style="{ background: portal.color }" :style="{ background: portal.color }"
/> />
</div> </div>
</div> </div>
<div class="flex items-start flex-col mb-4"> <div class="flex flex-col items-start mb-4">
<label>{{ <label>{{
$t( $t(
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.SUB_TEXT' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.SUB_TEXT'
@ -159,7 +159,7 @@
</div> </div>
<div class="mb-12"> <div class="mb-12">
<h2 <h2
class="text-slate-800 dark:text-slate-100 font-medium mb-2 text-base" class="mb-2 text-base font-medium text-slate-800 dark:text-slate-100"
> >
{{ {{
$t( $t(
@ -190,10 +190,10 @@
</template> </template>
<script> <script>
import { useAlert } from 'dashboard/composables';
import thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import LocaleItemTable from './PortalListItemTable.vue'; import LocaleItemTable from './PortalListItemTable.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import alertMixin from 'shared/mixins/alertMixin';
import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
export default { export default {
@ -201,7 +201,7 @@ export default {
thumbnail, thumbnail,
LocaleItemTable, LocaleItemTable,
}, },
mixins: [alertMixin, uiSettingsMixin], mixins: [uiSettingsMixin],
props: { props: {
portal: { portal: {
type: Object, type: Object,
@ -300,7 +300,7 @@ export default {
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.DELETE_PORTAL.API.DELETE_ERROR' 'HELP_CENTER.PORTAL.PORTAL_SETTINGS.DELETE_PORTAL.API.DELETE_ERROR'
); );
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
changeDefaultLocale({ localeCode }) { changeDefaultLocale({ localeCode }) {
@ -357,7 +357,7 @@ export default {
} catch (error) { } catch (error) {
this.alertMessage = error?.message || errorMessage; this.alertMessage = error?.message || errorMessage;
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
navigateToPortalEdit() { navigateToPortalEdit() {

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="article-container flex w-full overflow-auto"> <div class="flex w-full overflow-auto article-container">
<div <div
class="flex-1 flex-shrink-0 overflow-auto px-6" class="flex-1 flex-shrink-0 px-6 overflow-auto"
:class="{ 'flex-grow-1 flex-shrink-0': showArticleSettings }" :class="{ 'flex-grow-1 flex-shrink-0': showArticleSettings }"
> >
<edit-article-header <edit-article-header
@ -15,7 +15,7 @@
@show="showArticleInPortal" @show="showArticleInPortal"
@update-meta="updateMeta" @update-meta="updateMeta"
/> />
<div v-if="isFetching" class="text-center p-4 text-base h-full"> <div v-if="isFetching" class="h-full p-4 text-base text-center">
<spinner size="" /> <spinner size="" />
<span>{{ $t('HELP_CENTER.EDIT_ARTICLE.LOADING') }}</span> <span>{{ $t('HELP_CENTER.EDIT_ARTICLE.LOADING') }}</span>
</div> </div>
@ -48,12 +48,12 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import EditArticleHeader from '../../components/Header/EditArticleHeader.vue'; import EditArticleHeader from '../../components/Header/EditArticleHeader.vue';
import ArticleEditor from '../../components/ArticleEditor.vue'; import ArticleEditor from '../../components/ArticleEditor.vue';
import ArticleSettings from './ArticleSettings.vue'; import ArticleSettings from './ArticleSettings.vue';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import portalMixin from '../../mixins/portalMixin'; import portalMixin from '../../mixins/portalMixin';
import alertMixin from 'shared/mixins/alertMixin';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { buildPortalArticleURL } from 'dashboard/helper/portalHelper'; import { buildPortalArticleURL } from 'dashboard/helper/portalHelper';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
@ -66,7 +66,7 @@ export default {
Spinner, Spinner,
ArticleSettings, ArticleSettings,
}, },
mixins: [portalMixin, alertMixin], mixins: [portalMixin],
data() { data() {
return { return {
isUpdating: false, isUpdating: false,
@ -144,7 +144,7 @@ export default {
} catch (error) { } catch (error) {
this.alertMessage = this.alertMessage =
error?.message || this.$t('HELP_CENTER.EDIT_ARTICLE.API.ERROR'); error?.message || this.$t('HELP_CENTER.EDIT_ARTICLE.API.ERROR');
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} finally { } finally {
setTimeout(() => { setTimeout(() => {
this.isUpdating = false; this.isUpdating = false;
@ -174,7 +174,7 @@ export default {
error?.message || error?.message ||
this.$t('HELP_CENTER.DELETE_ARTICLE.API.ERROR_MESSAGE'); this.$t('HELP_CENTER.DELETE_ARTICLE.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
async archiveArticle() { async archiveArticle() {
@ -190,7 +190,7 @@ export default {
this.alertMessage = this.alertMessage =
error?.message || this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.ERROR'); error?.message || this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.ERROR');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
updateMeta() { updateMeta() {

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-1 overflow-auto"> <div class="flex flex-1 overflow-auto">
<div <div
class="flex-1 overflow-y-auto flex-shrink-0 px-6" class="flex-1 flex-shrink-0 px-6 overflow-y-auto"
:class="{ 'flex-grow-1': showArticleSettings }" :class="{ 'flex-grow-1': showArticleSettings }"
> >
<edit-article-header <edit-article-header
@ -25,10 +25,10 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import EditArticleHeader from 'dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue'; import EditArticleHeader from 'dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue';
import ArticleEditor from '../../components/ArticleEditor.vue'; import ArticleEditor from '../../components/ArticleEditor.vue';
import portalMixin from '../../mixins/portalMixin'; import portalMixin from '../../mixins/portalMixin';
import alertMixin from 'shared/mixins/alertMixin.js';
import ArticleSettings from './ArticleSettings.vue'; import ArticleSettings from './ArticleSettings.vue';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
export default { export default {
@ -37,7 +37,7 @@ export default {
ArticleEditor, ArticleEditor,
ArticleSettings, ArticleSettings,
}, },
mixins: [portalMixin, alertMixin], mixins: [portalMixin],
data() { data() {
return { return {
articleTitle: '', articleTitle: '',
@ -100,7 +100,7 @@ export default {
this.alertMessage = this.alertMessage =
error?.message || error?.message ||
this.$t('HELP_CENTER.CREATE_ARTICLE.API.ERROR_MESSAGE'); this.$t('HELP_CENTER.CREATE_ARTICLE.API.ERROR_MESSAGE');
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
} }
}, },
@ -112,7 +112,7 @@ export default {
}, },
saveArticle() { saveArticle() {
this.alertMessage = this.$t('HELP_CENTER.CREATE_ARTICLE.ERROR_MESSAGE'); this.alertMessage = this.$t('HELP_CENTER.CREATE_ARTICLE.ERROR_MESSAGE');
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
}, },
}, },
}; };

View File

@ -7,7 +7,7 @@
/> />
<form class="w-full" @submit.prevent="onCreate"> <form class="w-full" @submit.prevent="onCreate">
<div class="w-full"> <div class="w-full">
<div class="flex flex-row w-full mt-0 mx-0 mb-4"> <div class="flex flex-row w-full mx-0 mt-0 mb-4">
<div class="w-[50%]"> <div class="w-[50%]">
<label> <label>
<span>{{ $t('HELP_CENTER.CATEGORY.ADD.PORTAL') }}</span> <span>{{ $t('HELP_CENTER.CATEGORY.ADD.PORTAL') }}</span>
@ -52,7 +52,7 @@
/> />
</label> </label>
<div class="w-full"> <div class="w-full">
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button class="button clear" @click.prevent="onClose"> <woot-button class="button clear" @click.prevent="onClose">
{{ $t('HELP_CENTER.CATEGORY.ADD.BUTTONS.CANCEL') }} {{ $t('HELP_CENTER.CATEGORY.ADD.BUTTONS.CANCEL') }}
</woot-button> </woot-button>
@ -67,7 +67,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { convertToCategorySlug } from 'dashboard/helper/commons.js'; import { convertToCategorySlug } from 'dashboard/helper/commons.js';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
@ -75,7 +75,6 @@ import CategoryNameIconInput from './NameEmojiInput.vue';
export default { export default {
components: { CategoryNameIconInput }, components: { CategoryNameIconInput },
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@ -169,7 +168,7 @@ export default {
this.alertMessage = this.alertMessage =
errorMessage || this.$t('HELP_CENTER.CATEGORY.ADD.API.ERROR_MESSAGE'); errorMessage || this.$t('HELP_CENTER.CATEGORY.ADD.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
}, },

View File

@ -7,7 +7,7 @@
/> />
<form class="w-full" @submit.prevent="onUpdate"> <form class="w-full" @submit.prevent="onUpdate">
<div class="w-full"> <div class="w-full">
<div class="flex flex-row w-full mt-0 mx-0 mb-4"> <div class="flex flex-row w-full mx-0 mt-0 mb-4">
<div class="w-[50%]"> <div class="w-[50%]">
<label> <label>
<span>{{ $t('HELP_CENTER.CATEGORY.EDIT.PORTAL') }}</span> <span>{{ $t('HELP_CENTER.CATEGORY.EDIT.PORTAL') }}</span>
@ -54,7 +54,7 @@
/> />
</label> </label>
<div class="w-full"> <div class="w-full">
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button class="button clear" @click.prevent="onClose"> <woot-button class="button clear" @click.prevent="onClose">
{{ $t('HELP_CENTER.CATEGORY.EDIT.BUTTONS.CANCEL') }} {{ $t('HELP_CENTER.CATEGORY.EDIT.BUTTONS.CANCEL') }}
</woot-button> </woot-button>
@ -69,7 +69,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { convertToCategorySlug } from 'dashboard/helper/commons.js'; import { convertToCategorySlug } from 'dashboard/helper/commons.js';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
@ -77,7 +77,6 @@ import CategoryNameIconInput from './NameEmojiInput.vue';
export default { export default {
components: { CategoryNameIconInput }, components: { CategoryNameIconInput },
mixins: [alertMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@ -180,7 +179,7 @@ export default {
errorMessage || errorMessage ||
this.$t('HELP_CENTER.CATEGORY.EDIT.API.ERROR_MESSAGE'); this.$t('HELP_CENTER.CATEGORY.EDIT.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
}, },

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="py-2 px-4 w-full max-w-full"> <div class="w-full max-w-full px-4 py-2">
<div class="flex justify-between items-center mt-0 mb-2 mx-0 h-12"> <div class="flex items-center justify-between h-12 mx-0 mt-0 mb-2">
<div class="flex items-center"> <div class="flex items-center">
<woot-sidemenu-icon /> <woot-sidemenu-icon />
<h1 <h1
class="my-0 mx-2 text-2xl text-slate-800 dark:text-slate-100 font-medium" class="mx-2 my-0 text-2xl font-medium text-slate-800 dark:text-slate-100"
> >
{{ $t('HELP_CENTER.PORTAL.HEADER') }} {{ $t('HELP_CENTER.PORTAL.HEADER') }}
</h1> </h1>
@ -29,7 +29,7 @@
/> />
<div <div
v-if="isFetching" v-if="isFetching"
class="items-center flex text-base justify-center p-40" class="flex items-center justify-center p-40 text-base"
> >
<spinner /> <spinner />
<span>{{ $t('HELP_CENTER.PORTAL.LOADING_MESSAGE') }}</span> <span>{{ $t('HELP_CENTER.PORTAL.LOADING_MESSAGE') }}</span>
@ -54,7 +54,6 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import PortalListItem from '../../components/PortalListItem.vue'; import PortalListItem from '../../components/PortalListItem.vue';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import EmptyState from 'dashboard/components/widgets/EmptyState.vue'; import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
@ -68,7 +67,6 @@ export default {
Spinner, Spinner,
AddLocale, AddLocale,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
isAddLocaleModalOpen: false, isAddLocaleModalOpen: false,

View File

@ -12,7 +12,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import PortalSettingsBasicForm from 'dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue'; import PortalSettingsBasicForm from 'dashboard/routes/dashboard/helpcenter/components/PortalSettingsBasicForm.vue';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events'; import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
@ -21,7 +21,6 @@ export default {
components: { components: {
PortalSettingsBasicForm, PortalSettingsBasicForm,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
name: '', name: '',
@ -63,7 +62,7 @@ export default {
error?.message || error?.message ||
this.$t('HELP_CENTER.PORTAL.ADD.API.ERROR_MESSAGE_FOR_BASIC'); this.$t('HELP_CENTER.PORTAL.ADD.API.ERROR_MESSAGE_FOR_BASIC');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
}, },

View File

@ -25,11 +25,11 @@
@context-menu-close="isInboxContextMenuOpen = false" @context-menu-close="isInboxContextMenuOpen = false"
/> />
<div v-if="uiFlags.isFetching" class="text-center"> <div v-if="uiFlags.isFetching" class="text-center">
<span class="spinner mt-4 mb-4" /> <span class="mt-4 mb-4 spinner" />
</div> </div>
<p <p
v-if="showEmptyState" v-if="showEmptyState"
class="text-center text-slate-400 text-sm dark:text-slate-400 p-4 font-medium" class="p-4 text-sm font-medium text-center text-slate-400 dark:text-slate-400"
> >
{{ $t('INBOX.LIST.NO_NOTIFICATIONS') }} {{ $t('INBOX.LIST.NO_NOTIFICATIONS') }}
</p> </p>
@ -46,13 +46,13 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import InboxCard from './components/InboxCard.vue'; import InboxCard from './components/InboxCard.vue';
import InboxListHeader from './components/InboxListHeader.vue'; import InboxListHeader from './components/InboxListHeader.vue';
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue'; import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue';
import alertMixin from 'shared/mixins/alertMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
export default { export default {
@ -61,7 +61,7 @@ export default {
InboxListHeader, InboxListHeader,
IntersectionObserver, IntersectionObserver,
}, },
mixins: [alertMixin, uiSettingsMixin], mixins: [uiSettingsMixin],
data() { data() {
return { return {
infiniteLoaderOptions: { infiniteLoaderOptions: {
@ -151,7 +151,7 @@ export default {
unreadCount: this.meta.unreadCount, unreadCount: this.meta.unreadCount,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('INBOX.ALERTS.MARK_AS_READ')); useAlert(this.$t('INBOX.ALERTS.MARK_AS_READ'));
}); });
}, },
markNotificationAsUnRead(notification) { markNotificationAsUnRead(notification) {
@ -163,7 +163,7 @@ export default {
id, id,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('INBOX.ALERTS.MARK_AS_UNREAD')); useAlert(this.$t('INBOX.ALERTS.MARK_AS_UNREAD'));
}); });
}, },
deleteNotification(notification) { deleteNotification(notification) {
@ -176,7 +176,7 @@ export default {
count: this.meta.count, count: this.meta.count,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('INBOX.ALERTS.DELETE')); useAlert(this.$t('INBOX.ALERTS.DELETE'));
}); });
}, },
onFilterChange(option) { onFilterChange(option) {

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="flex gap-2 py-2 ltr:pl-4 rtl:pl-2 h-14 ltr:pr-2 rtl:pr-4 rtl:border-r justify-between items-center w-full border-b border-slate-50 dark:border-slate-800/50" class="flex items-center justify-between w-full gap-2 py-2 border-b ltr:pl-4 rtl:pl-2 h-14 ltr:pr-2 rtl:pr-4 rtl:border-r border-slate-50 dark:border-slate-800/50"
> >
<woot-button <woot-button
variant="clear link" variant="clear link"
@ -56,6 +56,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { getUnixTime } from 'date-fns'; import { getUnixTime } from 'date-fns';
import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents'; import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
@ -63,14 +64,12 @@ import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import PaginationButton from './PaginationButton.vue'; import PaginationButton from './PaginationButton.vue';
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue'; import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
PaginationButton, PaginationButton,
CustomSnoozeModal, CustomSnoozeModal,
}, },
mixins: [alertMixin],
props: { props: {
totalLength: { totalLength: {
type: Number, type: Number,
@ -112,7 +111,7 @@ export default {
snoozedUntil, snoozedUntil,
}); });
this.showAlert(this.$t('INBOX.ALERTS.SNOOZE')); useAlert(this.$t('INBOX.ALERTS.SNOOZE'));
} catch (error) { } catch (error) {
// Silently fail without any change in the UI // Silently fail without any change in the UI
} }
@ -141,7 +140,7 @@ export default {
count: this.meta.count, count: this.meta.count,
}) })
.then(() => { .then(() => {
this.showAlert(this.$t('INBOX.ALERTS.DELETE')); useAlert(this.$t('INBOX.ALERTS.DELETE'));
}); });
this.$router.replace({ name: 'inbox_view' }); this.$router.replace({ name: 'inbox_view' });
}, },

View File

@ -1,19 +1,19 @@
<template> <template>
<div <div
class="flex w-full ltr:pl-4 rtl:pl-2 rtl:pr-4 ltr:pr-2 py-2 h-14 justify-between items-center border-b border-slate-50 dark:border-slate-800/50" class="flex items-center justify-between w-full py-2 border-b ltr:pl-4 rtl:pl-2 rtl:pr-4 ltr:pr-2 h-14 border-slate-50 dark:border-slate-800/50"
> >
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-1.5">
<h1 class="font-medium text-slate-900 dark:text-slate-25 text-xl"> <h1 class="text-xl font-medium text-slate-900 dark:text-slate-25">
{{ $t('INBOX.LIST.TITLE') }} {{ $t('INBOX.LIST.TITLE') }}
</h1> </h1>
<div class="relative"> <div class="relative">
<div <div
role="button" role="button"
class="flex gap-1 items-center py-1 px-2 border border-slate-100 dark:border-slate-700/50 rounded-md" class="flex items-center gap-1 px-2 py-1 border rounded-md border-slate-100 dark:border-slate-700/50"
@click="openInboxDisplayMenu" @click="openInboxDisplayMenu"
> >
<span <span
class="text-slate-600 dark:text-slate-200 text-xs text-center font-medium" class="text-xs font-medium text-center text-slate-600 dark:text-slate-200"
> >
{{ $t('INBOX.LIST.DISPLAY_DROPDOWN') }} {{ $t('INBOX.LIST.DISPLAY_DROPDOWN') }}
</span> </span>
@ -31,7 +31,7 @@
/> />
</div> </div>
</div> </div>
<div class="flex relative gap-1 items-center"> <div class="relative flex items-center gap-1">
<!-- <woot-button <!-- <woot-button
variant="clear" variant="clear"
size="small" size="small"
@ -57,17 +57,16 @@
</template> </template>
<script> <script>
import InboxOptionMenu from './InboxOptionMenu.vue'; import { useAlert } from 'dashboard/composables';
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import InboxOptionMenu from './InboxOptionMenu.vue';
import InboxDisplayMenu from './InboxDisplayMenu.vue'; import InboxDisplayMenu from './InboxDisplayMenu.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
InboxOptionMenu, InboxOptionMenu,
InboxDisplayMenu, InboxDisplayMenu,
}, },
mixins: [alertMixin],
props: { props: {
isContextMenuOpen: { isContextMenuOpen: {
type: Boolean, type: Boolean,
@ -95,17 +94,17 @@ export default {
markAllRead() { markAllRead() {
this.$track(INBOX_EVENTS.MARK_ALL_NOTIFICATIONS_AS_READ); this.$track(INBOX_EVENTS.MARK_ALL_NOTIFICATIONS_AS_READ);
this.$store.dispatch('notifications/readAll').then(() => { this.$store.dispatch('notifications/readAll').then(() => {
this.showAlert(this.$t('INBOX.ALERTS.MARK_ALL_READ')); useAlert(this.$t('INBOX.ALERTS.MARK_ALL_READ'));
}); });
}, },
deleteAll() { deleteAll() {
this.$store.dispatch('notifications/deleteAll').then(() => { this.$store.dispatch('notifications/deleteAll').then(() => {
this.showAlert(this.$t('INBOX.ALERTS.DELETE_ALL')); useAlert(this.$t('INBOX.ALERTS.DELETE_ALL'));
}); });
}, },
deleteAllRead() { deleteAllRead() {
this.$store.dispatch('notifications/deleteAllRead').then(() => { this.$store.dispatch('notifications/deleteAllRead').then(() => {
this.showAlert(this.$t('INBOX.ALERTS.DELETE_ALL_READ')); useAlert(this.$t('INBOX.ALERTS.DELETE_ALL_READ'));
}); });
}, },
openInboxDisplayMenu() { openInboxDisplayMenu() {

View File

@ -3,7 +3,7 @@
class="flex justify-between items-center h-14 min-h-[3.5rem] px-4 py-2 bg-white dark:bg-slate-900 border-b border-slate-50 dark:border-slate-800/50" class="flex justify-between items-center h-14 min-h-[3.5rem] px-4 py-2 bg-white dark:bg-slate-900 border-b border-slate-50 dark:border-slate-800/50"
> >
<h1 <h1
class="text-2xl mb-0 flex items-center text-slate-900 dark:text-slate-100" class="flex items-center mb-0 text-2xl text-slate-900 dark:text-slate-100"
> >
<woot-sidemenu-icon v-if="showSidemenuIcon" /> <woot-sidemenu-icon v-if="showSidemenuIcon" />
<back-button <back-button
@ -15,10 +15,10 @@
v-if="icon" v-if="icon"
:icon="icon" :icon="icon"
:class="iconClass" :class="iconClass"
class="mr-2 ml-1 rtl:ml-2 rtl:mr-1 hidden md:block" class="hidden ml-1 mr-2 rtl:ml-2 rtl:mr-1 md:block"
/> />
<slot /> <slot />
<span class="text-slate-900 font-medium text-2xl dark:text-slate-100"> <span class="text-2xl font-medium text-slate-900 dark:text-slate-100">
{{ headerTitle }} {{ headerTitle }}
</span> </span>
</h1> </h1>
@ -36,14 +36,13 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAdmin } from 'dashboard/composables/useAdmin';
import BackButton from '../../../components/widgets/BackButton.vue'; import BackButton from '../../../components/widgets/BackButton.vue';
import adminMixin from '../../../mixins/isAdmin';
export default { export default {
components: { components: {
BackButton, BackButton,
}, },
mixins: [adminMixin],
props: { props: {
headerTitle: { headerTitle: {
default: '', default: '',
@ -76,6 +75,12 @@ export default {
default: true, default: true,
}, },
}, },
setup() {
const { isAdmin } = useAdmin();
return {
isAdmin,
};
},
computed: { computed: {
...mapGetters({ ...mapGetters({
currentUser: 'getCurrentUser', currentUser: 'getCurrentUser',

View File

@ -131,7 +131,7 @@
<script> <script>
import { required, minValue, maxValue } from 'vuelidate/lib/validators'; import { required, minValue, maxValue } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import configMixin from 'shared/mixins/configMixin'; import configMixin from 'shared/mixins/configMixin';
import accountMixin from '../../../../mixins/account'; import accountMixin from '../../../../mixins/account';
import { FEATURE_FLAGS } from '../../../../featureFlags'; import { FEATURE_FLAGS } from '../../../../featureFlags';
@ -140,7 +140,7 @@ import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages'; import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
export default { export default {
mixins: [accountMixin, alertMixin, configMixin, uiSettingsMixin], mixins: [accountMixin, configMixin, uiSettingsMixin],
data() { data() {
return { return {
id: '', id: '',
@ -253,7 +253,7 @@ export default {
async updateAccount() { async updateAccount() {
this.$v.$touch(); this.$v.$touch();
if (this.$v.$invalid) { if (this.$v.$invalid) {
this.showAlert(this.$t('GENERAL_SETTINGS.FORM.ERROR')); useAlert(this.$t('GENERAL_SETTINGS.FORM.ERROR'));
return; return;
} }
try { try {
@ -267,9 +267,9 @@ export default {
this.$root.$i18n.locale = this.locale; this.$root.$i18n.locale = this.locale;
this.getAccount(this.id).locale = this.locale; this.getAccount(this.id).locale = this.locale;
this.updateDirectionView(this.locale); this.updateDirectionView(this.locale);
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.SUCCESS')); useAlert(this.$t('GENERAL_SETTINGS.UPDATE.SUCCESS'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.ERROR')); useAlert(this.$t('GENERAL_SETTINGS.UPDATE.ERROR'));
} }
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex-1 overflow-auto p-4"> <div class="flex-1 p-4 overflow-auto">
<div class="flex flex-row gap-4"> <div class="flex flex-row gap-4">
<div class="w-full lg:w-3/5"> <div class="w-full lg:w-3/5">
<woot-loading-state <woot-loading-state
@ -18,12 +18,12 @@
/> />
</tbody> </tbody>
</table> </table>
<p v-else class="flex h-full items-center flex-col justify-center"> <p v-else class="flex flex-col items-center justify-center h-full">
{{ $t('AGENT_BOTS.LIST.404') }} {{ $t('AGENT_BOTS.LIST.404') }}
</p> </p>
</div> </div>
<div class="hidden lg:block w-1/3"> <div class="hidden w-1/3 lg:block">
<p v-html="$t('AGENT_BOTS.SIDEBAR_TXT')" /> <p v-html="$t('AGENT_BOTS.SIDEBAR_TXT')" />
</div> </div>
</div> </div>
@ -46,13 +46,12 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { frontendURL } from '../../../../helper/URLHelper'; import { frontendURL } from '../../../../helper/URLHelper';
import AgentBotRow from './components/AgentBotRow.vue'; import AgentBotRow from './components/AgentBotRow.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { AgentBotRow }, components: { AgentBotRow },
mixins: [alertMixin],
computed: { computed: {
...mapGetters({ ...mapGetters({
accountId: 'getCurrentAccountId', accountId: 'getCurrentAccountId',
@ -74,9 +73,9 @@ export default {
if (ok) { if (ok) {
try { try {
await this.$store.dispatch('agentBots/delete', bot.id); await this.$store.dispatch('agentBots/delete', bot.id);
this.showAlert(this.$t('AGENT_BOTS.DELETE.API.SUCCESS_MESSAGE')); useAlert(this.$t('AGENT_BOTS.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('AGENT_BOTS.DELETE.API.ERROR_MESSAGE')); useAlert(this.$t('AGENT_BOTS.DELETE.API.ERROR_MESSAGE'));
} }
} }
}, },

View File

@ -4,19 +4,18 @@
:agent-bot="agentBot" :agent-bot="agentBot"
@submit="updateBot" @submit="updateBot"
/> />
<div v-else class="h-auto overflow-auto flex flex-col no-padding"> <div v-else class="flex flex-col h-auto overflow-auto no-padding">
<spinner /> <spinner />
</div> </div>
</template> </template>
<script> <script>
import { useAlert } from 'dashboard/composables';
import Spinner from 'shared/components/Spinner.vue'; import Spinner from 'shared/components/Spinner.vue';
import CsmlBotEditor from '../components/CSMLBotEditor.vue'; import CsmlBotEditor from '../components/CSMLBotEditor.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
export default { export default {
components: { Spinner, CsmlBotEditor }, components: { Spinner, CsmlBotEditor },
mixins: [alertMixin],
computed: { computed: {
...mapGetters({ uiFlags: 'agentBots/uiFlags' }), ...mapGetters({ uiFlags: 'agentBots/uiFlags' }),
agentBot() { agentBot() {
@ -36,11 +35,9 @@ export default {
bot_type: 'csml', bot_type: 'csml',
bot_config: { csml_content: bot.csmlContent }, bot_config: { csml_content: bot.csmlContent },
}); });
this.showAlert(this.$t('AGENT_BOTS.EDIT.API.SUCCESS_MESSAGE')); useAlert(this.$t('AGENT_BOTS.EDIT.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert( useAlert(this.$t('AGENT_BOTS.CSML_BOT_EDITOR.BOT_CONFIG.API_ERROR'));
this.$t('AGENT_BOTS.CSML_BOT_EDITOR.BOT_CONFIG.API_ERROR')
);
} }
}, },
}, },

View File

@ -3,14 +3,13 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin';
import CsmlBotEditor from '../components/CSMLBotEditor.vue';
import { frontendURL } from '../../../../../helper/URLHelper';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { frontendURL } from '../../../../../helper/URLHelper';
import CsmlBotEditor from '../components/CSMLBotEditor.vue';
export default { export default {
components: { CsmlBotEditor }, components: { CsmlBotEditor },
mixins: [alertMixin],
computed: { computed: {
...mapGetters({ ...mapGetters({
accountId: 'getCurrentAccountId', accountId: 'getCurrentAccountId',
@ -32,9 +31,9 @@ export default {
) )
); );
} }
this.showAlert(this.$t('AGENT_BOTS.ADD.API.SUCCESS_MESSAGE')); useAlert(this.$t('AGENT_BOTS.ADD.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('AGENT_BOTS.ADD.API.ERROR_MESSAGE')); useAlert(this.$t('AGENT_BOTS.ADD.API.ERROR_MESSAGE'));
} }
}, },
}, },

View File

@ -69,10 +69,9 @@
<script> <script>
import { required, minLength, email } from 'vuelidate/lib/validators'; import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
export default { export default {
mixins: [alertMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,
@ -126,7 +125,7 @@ export default {
email: this.agentEmail, email: this.agentEmail,
role: this.agentType, role: this.agentType,
}); });
this.showAlert(this.$t('AGENT_MGMT.ADD.API.SUCCESS_MESSAGE')); useAlert(this.$t('AGENT_MGMT.ADD.API.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
const { const {
@ -145,7 +144,7 @@ export default {
} else { } else {
errorMessage = this.$t('AGENT_MGMT.ADD.API.ERROR_MESSAGE'); errorMessage = this.$t('AGENT_MGMT.ADD.API.ERROR_MESSAGE');
} }
this.showAlert(errorResponse || attrError || errorMessage); useAlert(errorResponse || attrError || errorMessage);
} }
}, },
}, },

View File

@ -1,6 +1,6 @@
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header :header-title="pageTitle" /> <woot-modal-header :header-title="pageTitle" />
<form class="w-full" @submit.prevent="editAgent()"> <form class="w-full" @submit.prevent="editAgent()">
<div class="w-full"> <div class="w-full">
@ -46,7 +46,7 @@
</span> </span>
</label> </label>
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<div class="w-[50%]"> <div class="w-[50%]">
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
@ -79,11 +79,11 @@
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue'; import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue';
import Modal from '../../../../components/Modal.vue'; import Modal from '../../../../components/Modal.vue';
import Auth from '../../../../api/auth'; import Auth from '../../../../api/auth';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import alertMixin from 'shared/mixins/alertMixin';
const { AVAILABILITY_STATUS_KEYS } = wootConstants; const { AVAILABILITY_STATUS_KEYS } = wootConstants;
@ -92,7 +92,6 @@ export default {
WootSubmitButton, WootSubmitButton,
Modal, Modal,
}, },
mixins: [alertMixin],
props: { props: {
id: { id: {
type: Number, type: Number,
@ -179,20 +178,20 @@ export default {
role: this.agentType, role: this.agentType,
availability: this.agentAvailability, availability: this.agentAvailability,
}); });
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.SUCCESS_MESSAGE')); useAlert(this.$t('AGENT_MGMT.EDIT.API.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.ERROR_MESSAGE')); useAlert(this.$t('AGENT_MGMT.EDIT.API.ERROR_MESSAGE'));
} }
}, },
async resetPassword() { async resetPassword() {
try { try {
await Auth.resetPassword(this.agentCredentials); await Auth.resetPassword(this.agentCredentials);
this.showAlert( useAlert(
this.$t('AGENT_MGMT.EDIT.PASSWORD_RESET.ADMIN_SUCCESS_MESSAGE') this.$t('AGENT_MGMT.EDIT.PASSWORD_RESET.ADMIN_SUCCESS_MESSAGE')
); );
} catch (error) { } catch (error) {
this.showAlert(this.$t('AGENT_MGMT.EDIT.PASSWORD_RESET.ERROR_MESSAGE')); useAlert(this.$t('AGENT_MGMT.EDIT.PASSWORD_RESET.ERROR_MESSAGE'));
} }
}, },
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex-1 overflow-auto p-4"> <div class="flex-1 p-4 overflow-auto">
<woot-button <woot-button
color-scheme="success" color-scheme="success"
class-names="button--fixed-top" class-names="button--fixed-top"
@ -84,7 +84,7 @@
</table> </table>
</div> </div>
</div> </div>
<div class="w-1/3 hidden lg:block"> <div class="hidden w-1/3 lg:block">
<span <span
v-dompurify-html=" v-dompurify-html="
useInstallationName( useInstallationName(
@ -126,11 +126,11 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import globalConfigMixin from 'shared/mixins/globalConfigMixin'; import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import Thumbnail from '../../../../components/widgets/Thumbnail.vue'; import Thumbnail from '../../../../components/widgets/Thumbnail.vue';
import AddAgent from './AddAgent.vue'; import AddAgent from './AddAgent.vue';
import EditAgent from './EditAgent.vue'; import EditAgent from './EditAgent.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
@ -138,7 +138,7 @@ export default {
EditAgent, EditAgent,
Thumbnail, Thumbnail,
}, },
mixins: [globalConfigMixin, alertMixin], mixins: [globalConfigMixin],
data() { data() {
return { return {
loading: {}, loading: {},
@ -243,7 +243,7 @@ export default {
this.currentAgent = {}; this.currentAgent = {};
// Show message // Show message
this.agentAPI.message = message; this.agentAPI.message = message;
this.showAlert(message); useAlert(message);
}, },
}, },
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<woot-modal :show.sync="show" :on-close="onClose"> <woot-modal :show.sync="show" :on-close="onClose">
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header :header-title="$t('ATTRIBUTES_MGMT.ADD.TITLE')" /> <woot-modal-header :header-title="$t('ATTRIBUTES_MGMT.ADD.TITLE')" />
<form class="flex w-full" @submit.prevent="addAttributes"> <form class="flex w-full" @submit.prevent="addAttributes">
@ -110,7 +110,7 @@
type="text" type="text"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')" :placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')"
/> />
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-submit-button <woot-submit-button
:disabled="isButtonDisabled" :disabled="isButtonDisabled"
:button-text="$t('ATTRIBUTES_MGMT.ADD.SUBMIT')" :button-text="$t('ATTRIBUTES_MGMT.ADD.SUBMIT')"
@ -128,12 +128,11 @@
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { convertToAttributeSlug } from 'dashboard/helper/commons.js'; import { convertToAttributeSlug } from 'dashboard/helper/commons.js';
import { ATTRIBUTE_MODELS, ATTRIBUTE_TYPES } from './constants'; import { ATTRIBUTE_MODELS, ATTRIBUTE_TYPES } from './constants';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
mixins: [alertMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,
@ -266,7 +265,7 @@ export default {
this.alertMessage = this.alertMessage =
errorMessage || this.$t('ATTRIBUTES_MGMT.ADD.API.ERROR_MESSAGE'); errorMessage || this.$t('ATTRIBUTES_MGMT.ADD.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
}, },

View File

@ -13,7 +13,7 @@
<div class="w-full"> <div class="w-full">
<p <p
v-if="!uiFlags.isFetching && !attributes.length" v-if="!uiFlags.isFetching && !attributes.length"
class="mt-12 flex items-center justify-center" class="flex items-center justify-center mt-12"
> >
{{ $t('ATTRIBUTES_MGMT.LIST.EMPTY_RESULT.404') }} {{ $t('ATTRIBUTES_MGMT.LIST.EMPTY_RESULT.404') }}
</p> </p>
@ -81,7 +81,7 @@
</table> </table>
</div> </div>
</div> </div>
<div class="hidden lg:block w-1/3"> <div class="hidden w-1/3 lg:block">
<span v-dompurify-html="$t('ATTRIBUTES_MGMT.SIDEBAR_TXT')" /> <span v-dompurify-html="$t('ATTRIBUTES_MGMT.SIDEBAR_TXT')" />
</div> </div>
<woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup"> <woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup">
@ -108,14 +108,13 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import EditAttribute from './EditAttribute.vue'; import EditAttribute from './EditAttribute.vue';
export default { export default {
components: { components: {
EditAttribute, EditAttribute,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
selectedTabIndex: 0, selectedTabIndex: 0,
@ -182,12 +181,12 @@ export default {
async deleteAttributes({ id }) { async deleteAttributes({ id }) {
try { try {
await this.$store.dispatch('attributes/delete', id); await this.$store.dispatch('attributes/delete', id);
this.showAlert(this.$t('ATTRIBUTES_MGMT.DELETE.API.SUCCESS_MESSAGE')); useAlert(this.$t('ATTRIBUTES_MGMT.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || error?.response?.message ||
this.$t('ATTRIBUTES_MGMT.DELETE.API.ERROR_MESSAGE'); this.$t('ATTRIBUTES_MGMT.DELETE.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
openEditPopup(response) { openEditPopup(response) {

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header :header-title="pageTitle" /> <woot-modal-header :header-title="pageTitle" />
<form class="flex flex-col w-full" @submit.prevent="editAttributes"> <form class="flex flex-col w-full" @submit.prevent="editAttributes">
<div class="w-full"> <div class="w-full">
@ -95,7 +95,7 @@
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')" :placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')"
/> />
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button :is-loading="isUpdating" :disabled="isButtonDisabled"> <woot-button :is-loading="isUpdating" :disabled="isButtonDisabled">
{{ $t('ATTRIBUTES_MGMT.EDIT.UPDATE_BUTTON_TEXT') }} {{ $t('ATTRIBUTES_MGMT.EDIT.UPDATE_BUTTON_TEXT') }}
</woot-button> </woot-button>
@ -109,13 +109,13 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { ATTRIBUTE_TYPES } from './constants'; import { ATTRIBUTE_TYPES } from './constants';
import alertMixin from 'shared/mixins/alertMixin';
import customAttributeMixin from '../../../../mixins/customAttributeMixin'; import customAttributeMixin from '../../../../mixins/customAttributeMixin';
export default { export default {
components: {}, components: {},
mixins: [alertMixin, customAttributeMixin], mixins: [customAttributeMixin],
props: { props: {
selectedAttribute: { selectedAttribute: {
type: Object, type: Object,
@ -263,7 +263,7 @@ export default {
this.alertMessage = this.alertMessage =
errorMessage || this.$t('ATTRIBUTES_MGMT.EDIT.API.ERROR_MESSAGE'); errorMessage || this.$t('ATTRIBUTES_MGMT.EDIT.API.ERROR_MESSAGE');
} finally { } finally {
this.showAlert(this.alertMessage); useAlert(this.alertMessage);
} }
}, },
toggleRegexEnabled() { toggleRegexEnabled() {

View File

@ -64,9 +64,9 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import TableFooter from 'dashboard/components/widgets/TableFooter.vue'; import { useAlert } from 'dashboard/composables';
import { messageTimestamp } from 'shared/helpers/timeHelper'; import { messageTimestamp } from 'shared/helpers/timeHelper';
import alertMixin from 'shared/mixins/alertMixin'; import TableFooter from 'dashboard/components/widgets/TableFooter.vue';
import { import {
generateTranslationPayload, generateTranslationPayload,
generateLogActionKey, generateLogActionKey,
@ -76,7 +76,6 @@ export default {
components: { components: {
TableFooter, TableFooter,
}, },
mixins: [alertMixin],
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {
// Fetch Audit Logs on page load without manual refresh // Fetch Audit Logs on page load without manual refresh
next(vm => { next(vm => {
@ -110,7 +109,7 @@ export default {
this.$store.dispatch('auditlogs/fetch', { page }).catch(error => { this.$store.dispatch('auditlogs/fetch', { page }).catch(error => {
const errorMessage = const errorMessage =
error?.message || this.$t('AUDIT_LOGS.API.ERROR_MESSAGE'); error?.message || this.$t('AUDIT_LOGS.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
}); });
}, },
generateLogText(auditLogItem) { generateLogText(auditLogItem) {
@ -129,7 +128,7 @@ export default {
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.message || this.$t('AUDIT_LOGS.API.ERROR_MESSAGE'); error?.message || this.$t('AUDIT_LOGS.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
}, },

View File

@ -55,7 +55,7 @@
{{ $t('AUTOMATION.ADD.FORM.CONDITIONS.LABEL') }} {{ $t('AUTOMATION.ADD.FORM.CONDITIONS.LABEL') }}
</label> </label>
<div <div
class="w-full p-4 bg-slate-25 dark:bg-slate-700 rounded-lg border border-solid border-slate-50 dark:border-slate-700 mb-4" class="w-full p-4 mb-4 border border-solid rounded-lg bg-slate-25 dark:bg-slate-700 border-slate-50 dark:border-slate-700"
> >
<filter-input-box <filter-input-box
v-for="(condition, i) in automation.conditions" v-for="(condition, i) in automation.conditions"
@ -97,7 +97,7 @@
{{ $t('AUTOMATION.ADD.FORM.ACTIONS.LABEL') }} {{ $t('AUTOMATION.ADD.FORM.ACTIONS.LABEL') }}
</label> </label>
<div <div
class="w-full p-4 bg-slate-25 dark:bg-slate-700 rounded-lg border border-solid border-slate-50 dark:border-slate-700 mb-4" class="w-full p-4 mb-4 border border-solid rounded-lg bg-slate-25 dark:bg-slate-700 border-slate-50 dark:border-slate-700"
> >
<automation-action-input <automation-action-input
v-for="(action, i) in automation.actions" v-for="(action, i) in automation.actions"
@ -129,7 +129,7 @@
</section> </section>
<!-- // Actions End --> <!-- // Actions End -->
<div class="w-full"> <div class="w-full">
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button class="button clear" @click.prevent="onClose"> <woot-button class="button clear" @click.prevent="onClose">
{{ $t('AUTOMATION.ADD.CANCEL_BUTTON_TEXT') }} {{ $t('AUTOMATION.ADD.CANCEL_BUTTON_TEXT') }}
</woot-button> </woot-button>
@ -145,7 +145,6 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin';
import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin';
import filterInputBox from 'dashboard/components/widgets/FilterInput/Index.vue'; import filterInputBox from 'dashboard/components/widgets/FilterInput/Index.vue';
@ -161,7 +160,7 @@ export default {
filterInputBox, filterInputBox,
automationActionInput, automationActionInput,
}, },
mixins: [alertMixin, automationMethodsMixin, automationValidationsMixin], mixins: [automationMethodsMixin, automationValidationsMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,

View File

@ -52,7 +52,7 @@
{{ $t('AUTOMATION.ADD.FORM.CONDITIONS.LABEL') }} {{ $t('AUTOMATION.ADD.FORM.CONDITIONS.LABEL') }}
</label> </label>
<div <div
class="w-full p-4 bg-slate-25 dark:bg-slate-700 rounded-lg border border-solid border-slate-50 dark:border-slate-700 mb-4" class="w-full p-4 mb-4 border border-solid rounded-lg bg-slate-25 dark:bg-slate-700 border-slate-50 dark:border-slate-700"
> >
<filter-input-box <filter-input-box
v-for="(condition, i) in automation.conditions" v-for="(condition, i) in automation.conditions"
@ -94,7 +94,7 @@
{{ $t('AUTOMATION.ADD.FORM.ACTIONS.LABEL') }} {{ $t('AUTOMATION.ADD.FORM.ACTIONS.LABEL') }}
</label> </label>
<div <div
class="w-full p-4 bg-slate-25 dark:bg-slate-700 rounded-lg border border-solid border-slate-50 dark:border-slate-700 mb-4" class="w-full p-4 mb-4 border border-solid rounded-lg bg-slate-25 dark:bg-slate-700 border-slate-50 dark:border-slate-700"
> >
<automation-action-input <automation-action-input
v-for="(action, i) in automation.actions" v-for="(action, i) in automation.actions"
@ -123,7 +123,7 @@
</section> </section>
<!-- // Actions End --> <!-- // Actions End -->
<div class="w-full"> <div class="w-full">
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button <woot-button
class="button" class="button"
variant="clear" variant="clear"
@ -143,7 +143,6 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin';
import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin';
import filterInputBox from 'dashboard/components/widgets/FilterInput/Index.vue'; import filterInputBox from 'dashboard/components/widgets/FilterInput/Index.vue';
@ -160,7 +159,7 @@ export default {
filterInputBox, filterInputBox,
automationActionInput, automationActionInput,
}, },
mixins: [alertMixin, automationMethodsMixin, automationValidationsMixin], mixins: [automationMethodsMixin, automationValidationsMixin],
props: { props: {
onClose: { onClose: {
type: Function, type: Function,

View File

@ -125,17 +125,16 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { messageStamp } from 'shared/helpers/timeHelper';
import AddAutomationRule from './AddAutomationRule.vue'; import AddAutomationRule from './AddAutomationRule.vue';
import EditAutomationRule from './EditAutomationRule.vue'; import EditAutomationRule from './EditAutomationRule.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { messageStamp } from 'shared/helpers/timeHelper';
export default { export default {
components: { components: {
AddAutomationRule, AddAutomationRule,
EditAutomationRule, EditAutomationRule,
}, },
mixins: [alertMixin],
data() { data() {
return { return {
loading: {}, loading: {},
@ -213,20 +212,20 @@ export default {
async deleteAutomation(id) { async deleteAutomation(id) {
try { try {
await this.$store.dispatch('automations/delete', id); await this.$store.dispatch('automations/delete', id);
this.showAlert(this.$t('AUTOMATION.DELETE.API.SUCCESS_MESSAGE')); useAlert(this.$t('AUTOMATION.DELETE.API.SUCCESS_MESSAGE'));
this.loading[this.selectedResponse.id] = false; this.loading[this.selectedResponse.id] = false;
} catch (error) { } catch (error) {
this.showAlert(this.$t('AUTOMATION.DELETE.API.ERROR_MESSAGE')); useAlert(this.$t('AUTOMATION.DELETE.API.ERROR_MESSAGE'));
} }
}, },
async cloneAutomation(id) { async cloneAutomation(id) {
try { try {
await this.$store.dispatch('automations/clone', id); await this.$store.dispatch('automations/clone', id);
this.showAlert(this.$t('AUTOMATION.CLONE.API.SUCCESS_MESSAGE')); useAlert(this.$t('AUTOMATION.CLONE.API.SUCCESS_MESSAGE'));
this.$store.dispatch('automations/get'); this.$store.dispatch('automations/get');
this.loading[this.selectedResponse.id] = false; this.loading[this.selectedResponse.id] = false;
} catch (error) { } catch (error) {
this.showAlert(this.$t('AUTOMATION.CLONE.API.ERROR_MESSAGE')); useAlert(this.$t('AUTOMATION.CLONE.API.ERROR_MESSAGE'));
} }
}, },
async submitAutomation(payload, mode) { async submitAutomation(payload, mode) {
@ -238,7 +237,7 @@ export default {
? this.$t('AUTOMATION.EDIT.API.SUCCESS_MESSAGE') ? this.$t('AUTOMATION.EDIT.API.SUCCESS_MESSAGE')
: this.$t('AUTOMATION.ADD.API.SUCCESS_MESSAGE'); : this.$t('AUTOMATION.ADD.API.SUCCESS_MESSAGE');
await this.$store.dispatch(action, payload); await this.$store.dispatch(action, payload);
this.showAlert(successMessage); useAlert(successMessage);
this.hideAddPopup(); this.hideAddPopup();
this.hideEditPopup(); this.hideEditPopup();
} catch (error) { } catch (error) {
@ -246,7 +245,7 @@ export default {
mode === 'edit' mode === 'edit'
? this.$t('AUTOMATION.EDIT.API.ERROR_MESSAGE') ? this.$t('AUTOMATION.EDIT.API.ERROR_MESSAGE')
: this.$t('AUTOMATION.ADD.API.ERROR_MESSAGE'); : this.$t('AUTOMATION.ADD.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
async toggleAutomation(automation, status) { async toggleAutomation(automation, status) {
@ -271,10 +270,10 @@ export default {
const message = status const message = status
? this.$t('AUTOMATION.TOGGLE.DEACTIVATION_SUCCESFUL') ? this.$t('AUTOMATION.TOGGLE.DEACTIVATION_SUCCESFUL')
: this.$t('AUTOMATION.TOGGLE.ACTIVATION_SUCCESFUL'); : this.$t('AUTOMATION.TOGGLE.ACTIVATION_SUCCESFUL');
this.showAlert(message); useAlert(message);
} }
} catch (error) { } catch (error) {
this.showAlert(this.$t('AUTOMATION.EDIT.API.ERROR_MESSAGE')); useAlert(this.$t('AUTOMATION.EDIT.API.ERROR_MESSAGE'));
} }
}, },
readableTime(date) { readableTime(date) {

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="overflow-auto flex-1 p-6 dark:bg-slate-900"> <div class="flex-1 p-6 overflow-auto dark:bg-slate-900">
<woot-loading-state v-if="uiFlags.isFetchingItem" /> <woot-loading-state v-if="uiFlags.isFetchingItem" />
<div v-else-if="!hasABillingPlan"> <div v-else-if="!hasABillingPlan">
<p>{{ $t('BILLING_SETTINGS.NO_BILLING_USER') }}</p> <p>{{ $t('BILLING_SETTINGS.NO_BILLING_USER') }}</p>
@ -39,13 +39,12 @@
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import accountMixin from '../../../../mixins/account'; import accountMixin from '../../../../mixins/account';
import BillingItem from './components/BillingItem.vue'; import BillingItem from './components/BillingItem.vue';
// sdds // sdds
export default { export default {
components: { BillingItem }, components: { BillingItem },
mixins: [accountMixin, alertMixin, messageFormatterMixin], mixins: [accountMixin, messageFormatterMixin],
computed: { computed: {
...mapGetters({ ...mapGetters({
getAccount: 'accounts/getAccount', getAccount: 'accounts/getAccount',

View File

@ -177,7 +177,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import campaignMixin from 'shared/mixins/campaignMixin'; import campaignMixin from 'shared/mixins/campaignMixin';
import WootDateTimePicker from 'dashboard/components/ui/DateTimePicker.vue'; import WootDateTimePicker from 'dashboard/components/ui/DateTimePicker.vue';
@ -190,7 +190,7 @@ export default {
WootMessageEditor, WootMessageEditor,
}, },
mixins: [alertMixin, campaignMixin], mixins: [campaignMixin],
data() { data() {
return { return {
title: '', title: '',
@ -305,7 +305,7 @@ export default {
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE'); error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
getCampaignDetails() { getCampaignDetails() {
@ -356,12 +356,12 @@ export default {
type: this.campaignType, type: this.campaignType,
}); });
this.showAlert(this.$t('CAMPAIGN.ADD.API.SUCCESS_MESSAGE')); useAlert(this.$t('CAMPAIGN.ADD.API.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE'); error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
}, },

View File

@ -27,7 +27,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import { useAlert } from 'dashboard/composables';
import campaignMixin from 'shared/mixins/campaignMixin'; import campaignMixin from 'shared/mixins/campaignMixin';
import CampaignsTable from './CampaignsTable.vue'; import CampaignsTable from './CampaignsTable.vue';
import EditCampaign from './EditCampaign.vue'; import EditCampaign from './EditCampaign.vue';
@ -36,7 +36,7 @@ export default {
CampaignsTable, CampaignsTable,
EditCampaign, EditCampaign,
}, },
mixins: [alertMixin, campaignMixin], mixins: [campaignMixin],
props: { props: {
type: { type: {
type: String, type: String,
@ -87,9 +87,9 @@ export default {
async deleteCampaign(id) { async deleteCampaign(id) {
try { try {
await this.$store.dispatch('campaigns/delete', id); await this.$store.dispatch('campaigns/delete', id);
this.showAlert(this.$t('CAMPAIGN.DELETE.API.SUCCESS_MESSAGE')); useAlert(this.$t('CAMPAIGN.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) { } catch (error) {
this.showAlert(this.$t('CAMPAIGN.DELETE.API.ERROR_MESSAGE')); useAlert(this.$t('CAMPAIGN.DELETE.API.ERROR_MESSAGE'));
} }
}, },
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header :header-title="pageTitle" /> <woot-modal-header :header-title="pageTitle" />
<form class="flex flex-col w-full" @submit.prevent="editCampaign"> <form class="flex flex-col w-full" @submit.prevent="editCampaign">
<div class="w-full"> <div class="w-full">
@ -99,7 +99,7 @@
{{ $t('CAMPAIGN.ADD.FORM.TRIGGER_ONLY_BUSINESS_HOURS') }} {{ $t('CAMPAIGN.ADD.FORM.TRIGGER_ONLY_BUSINESS_HOURS') }}
</label> </label>
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-button :is-loading="uiFlags.isCreating"> <woot-button :is-loading="uiFlags.isCreating">
{{ $t('CAMPAIGN.EDIT.UPDATE_BUTTON_TEXT') }} {{ $t('CAMPAIGN.EDIT.UPDATE_BUTTON_TEXT') }}
</woot-button> </woot-button>
@ -114,8 +114,8 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import { useAlert } from 'dashboard/composables';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import alertMixin from 'shared/mixins/alertMixin';
import campaignMixin from 'shared/mixins/campaignMixin'; import campaignMixin from 'shared/mixins/campaignMixin';
import { URLPattern } from 'urlpattern-polyfill'; import { URLPattern } from 'urlpattern-polyfill';
@ -123,7 +123,7 @@ export default {
components: { components: {
WootMessageEditor, WootMessageEditor,
}, },
mixins: [alertMixin, campaignMixin], mixins: [campaignMixin],
props: { props: {
selectedCampaign: { selectedCampaign: {
type: Object, type: Object,
@ -225,7 +225,7 @@ export default {
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE'); error?.response?.message || this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
} }
}, },
onChangeInbox() { onChangeInbox() {
@ -272,10 +272,10 @@ export default {
time_on_page: this.timeOnPage, time_on_page: this.timeOnPage,
}, },
}); });
this.showAlert(this.$t('CAMPAIGN.EDIT.API.SUCCESS_MESSAGE')); useAlert(this.$t('CAMPAIGN.EDIT.API.SUCCESS_MESSAGE'));
this.onClose(); this.onClose();
} catch (error) { } catch (error) {
this.showAlert(this.$t('CAMPAIGN.EDIT.API.ERROR_MESSAGE')); useAlert(this.$t('CAMPAIGN.EDIT.API.ERROR_MESSAGE'));
} }
}, },
}, },

View File

@ -1,6 +1,6 @@
<template> <template>
<modal :show.sync="show" :on-close="onClose"> <modal :show.sync="show" :on-close="onClose">
<div class="h-auto overflow-auto flex flex-col"> <div class="flex flex-col h-auto overflow-auto">
<woot-modal-header <woot-modal-header
:header-title="$t('CANNED_MGMT.ADD.TITLE')" :header-title="$t('CANNED_MGMT.ADD.TITLE')"
:header-content="$t('CANNED_MGMT.ADD.DESC')" :header-content="$t('CANNED_MGMT.ADD.DESC')"
@ -34,7 +34,7 @@
/> />
</div> </div>
</div> </div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full"> <div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
<woot-submit-button <woot-submit-button
:disabled=" :disabled="
$v.content.$invalid || $v.content.$invalid ||
@ -55,11 +55,11 @@
<script> <script>
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';
import { useAlert } from 'dashboard/composables';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue'; import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue';
import Modal from '../../../../components/Modal.vue'; import Modal from '../../../../components/Modal.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {
@ -67,7 +67,6 @@ export default {
Modal, Modal,
WootMessageEditor, WootMessageEditor,
}, },
mixins: [alertMixin],
props: { props: {
responseContent: { responseContent: {
type: String, type: String,
@ -117,7 +116,7 @@ export default {
.then(() => { .then(() => {
// Reset Form, Show success message // Reset Form, Show success message
this.addCanned.showLoading = false; this.addCanned.showLoading = false;
this.showAlert(this.$t('CANNED_MGMT.ADD.API.SUCCESS_MESSAGE')); useAlert(this.$t('CANNED_MGMT.ADD.API.SUCCESS_MESSAGE'));
this.resetForm(); this.resetForm();
this.onClose(); this.onClose();
}) })
@ -125,7 +124,7 @@ export default {
this.addCanned.showLoading = false; this.addCanned.showLoading = false;
const errorMessage = const errorMessage =
error?.message || this.$t('CANNED_MGMT.ADD.API.ERROR_MESSAGE'); error?.message || this.$t('CANNED_MGMT.ADD.API.ERROR_MESSAGE');
this.showAlert(errorMessage); useAlert(errorMessage);
}); });
}, },
}, },

Some files were not shown because too many files have changed in this diff Show More