mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-30 10:42:38 +00:00
Porting changes from https://github.com/chatwoot/chatwoot/pull/10552 --------- Co-authored-by: Pranav <pranav@chatwoot.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com> Co-authored-by: Sojan <sojan@pepalo.com> Co-authored-by: iamsivin <iamsivin@gmail.com> Co-authored-by: Pranav <pranavrajs@gmail.com>
220 lines
6.2 KiB
Vue
220 lines
6.2 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { useAlert } from 'dashboard/composables';
|
|
import { useToggle } from '@vueuse/core';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useStore, useStoreGetters } from 'dashboard/composables/store';
|
|
import { useEmitter } from 'dashboard/composables/emitter';
|
|
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
|
|
|
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
|
|
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
|
|
import wootConstants from 'dashboard/constants/globals';
|
|
import {
|
|
CMD_REOPEN_CONVERSATION,
|
|
CMD_RESOLVE_CONVERSATION,
|
|
} from 'dashboard/helper/commandbar/events';
|
|
|
|
import Button from 'dashboard/components-next/button/Button.vue';
|
|
|
|
const store = useStore();
|
|
const getters = useStoreGetters();
|
|
const { t } = useI18n();
|
|
|
|
const arrowDownButtonRef = ref(null);
|
|
const isLoading = ref(false);
|
|
|
|
const [showActionsDropdown, toggleDropdown] = useToggle();
|
|
const closeDropdown = () => toggleDropdown(false);
|
|
const openDropdown = () => toggleDropdown(true);
|
|
|
|
const currentChat = computed(() => getters.getSelectedChat.value);
|
|
|
|
const isOpen = computed(
|
|
() => currentChat.value.status === wootConstants.STATUS_TYPE.OPEN
|
|
);
|
|
const isPending = computed(
|
|
() => currentChat.value.status === wootConstants.STATUS_TYPE.PENDING
|
|
);
|
|
const isResolved = computed(
|
|
() => currentChat.value.status === wootConstants.STATUS_TYPE.RESOLVED
|
|
);
|
|
const isSnoozed = computed(
|
|
() => currentChat.value.status === wootConstants.STATUS_TYPE.SNOOZED
|
|
);
|
|
|
|
const showAdditionalActions = computed(
|
|
() => !isPending.value && !isSnoozed.value
|
|
);
|
|
|
|
const showOpenButton = computed(() => {
|
|
return isPending.value || isSnoozed.value;
|
|
});
|
|
|
|
const getConversationParams = () => {
|
|
const allConversations = document.querySelectorAll(
|
|
'.conversations-list .conversation'
|
|
);
|
|
|
|
const activeConversation = document.querySelector(
|
|
'div.conversations-list div.conversation.active'
|
|
);
|
|
const activeConversationIndex = [...allConversations].indexOf(
|
|
activeConversation
|
|
);
|
|
const lastConversationIndex = allConversations.length - 1;
|
|
|
|
return {
|
|
all: allConversations,
|
|
activeIndex: activeConversationIndex,
|
|
lastIndex: lastConversationIndex,
|
|
};
|
|
};
|
|
|
|
const openSnoozeModal = () => {
|
|
const ninja = document.querySelector('ninja-keys');
|
|
ninja.open({ parent: 'snooze_conversation' });
|
|
};
|
|
|
|
const toggleStatus = (status, snoozedUntil) => {
|
|
closeDropdown();
|
|
isLoading.value = true;
|
|
store
|
|
.dispatch('toggleStatus', {
|
|
conversationId: currentChat.value.id,
|
|
status,
|
|
snoozedUntil,
|
|
})
|
|
.then(() => {
|
|
useAlert(t('CONVERSATION.CHANGE_STATUS'));
|
|
isLoading.value = false;
|
|
});
|
|
};
|
|
|
|
const onCmdOpenConversation = () => {
|
|
toggleStatus(wootConstants.STATUS_TYPE.OPEN);
|
|
};
|
|
|
|
const onCmdResolveConversation = () => {
|
|
toggleStatus(wootConstants.STATUS_TYPE.RESOLVED);
|
|
};
|
|
|
|
const keyboardEvents = {
|
|
'Alt+KeyM': {
|
|
action: () => arrowDownButtonRef.value?.$el.click(),
|
|
allowOnFocusedInput: true,
|
|
},
|
|
'Alt+KeyE': {
|
|
action: async () => {
|
|
await toggleStatus(wootConstants.STATUS_TYPE.RESOLVED);
|
|
},
|
|
},
|
|
'$mod+Alt+KeyE': {
|
|
action: async event => {
|
|
const { all, activeIndex, lastIndex } = getConversationParams();
|
|
await toggleStatus(wootConstants.STATUS_TYPE.RESOLVED);
|
|
|
|
if (activeIndex < lastIndex) {
|
|
all[activeIndex + 1].click();
|
|
} else if (all.length > 1) {
|
|
all[0].click();
|
|
document.querySelector('.conversations-list').scrollTop = 0;
|
|
}
|
|
event.preventDefault();
|
|
},
|
|
},
|
|
};
|
|
|
|
useKeyboardEvents(keyboardEvents);
|
|
|
|
useEmitter(CMD_REOPEN_CONVERSATION, onCmdOpenConversation);
|
|
useEmitter(CMD_RESOLVE_CONVERSATION, onCmdResolveConversation);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative flex items-center justify-end resolve-actions">
|
|
<div
|
|
class="rounded-lg shadow button-group outline-1 outline"
|
|
:class="!showOpenButton ? 'outline-n-container' : 'outline-transparent'"
|
|
>
|
|
<Button
|
|
v-if="isOpen"
|
|
:label="t('CONVERSATION.HEADER.RESOLVE_ACTION')"
|
|
size="sm"
|
|
color="slate"
|
|
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
|
:is-loading="isLoading"
|
|
@click="onCmdResolveConversation"
|
|
/>
|
|
<Button
|
|
v-else-if="isResolved"
|
|
:label="t('CONVERSATION.HEADER.REOPEN_ACTION')"
|
|
size="sm"
|
|
color="slate"
|
|
class="ltr:rounded-r-none rtl:rounded-l-none !outline-0"
|
|
:is-loading="isLoading"
|
|
@click="onCmdOpenConversation"
|
|
/>
|
|
<Button
|
|
v-else-if="showOpenButton"
|
|
:label="t('CONVERSATION.HEADER.OPEN_ACTION')"
|
|
size="sm"
|
|
color="slate"
|
|
:is-loading="isLoading"
|
|
@click="onCmdOpenConversation"
|
|
/>
|
|
<Button
|
|
v-if="showAdditionalActions"
|
|
ref="arrowDownButtonRef"
|
|
icon="i-lucide-chevron-down"
|
|
:disabled="isLoading"
|
|
size="sm"
|
|
class="ltr:rounded-l-none rtl:rounded-r-none !outline-0"
|
|
color="slate"
|
|
trailing-icon
|
|
@click="openDropdown"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-if="showActionsDropdown"
|
|
v-on-clickaway="closeDropdown"
|
|
class="dropdown-pane dropdown-pane--open left-auto top-full mt-0.5 ltr:right-0 rtl:left-0 max-w-[12.5rem] min-w-[9.75rem]"
|
|
>
|
|
<WootDropdownMenu class="mb-0">
|
|
<WootDropdownItem v-if="!isPending">
|
|
<Button
|
|
:label="t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE_UNTIL')"
|
|
ghost
|
|
slate
|
|
sm
|
|
start
|
|
icon="i-lucide-alarm-clock-minus"
|
|
class="w-full"
|
|
@click="() => openSnoozeModal()"
|
|
/>
|
|
</WootDropdownItem>
|
|
<WootDropdownItem v-if="!isPending">
|
|
<Button
|
|
:label="t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING')"
|
|
ghost
|
|
slate
|
|
sm
|
|
start
|
|
icon="i-lucide-circle-dot-dashed"
|
|
class="w-full"
|
|
@click="() => toggleStatus(wootConstants.STATUS_TYPE.PENDING)"
|
|
/>
|
|
</WootDropdownItem>
|
|
</WootDropdownMenu>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.dropdown-pane {
|
|
.dropdown-menu__item {
|
|
@apply mb-0;
|
|
}
|
|
}
|
|
</style>
|