feat: Display "Snoozed Until" time on conversation header (#3028)
This commit is contained in:
parent
49ac4a4400
commit
57abdc4d5f
19 changed files with 217 additions and 172 deletions
|
@ -14,6 +14,7 @@
|
|||
@import 'helper-classes';
|
||||
@import 'formulate';
|
||||
@import 'date-picker';
|
||||
@import 'utility-helpers';
|
||||
|
||||
@import 'foundation-sites/scss/foundation';
|
||||
@import '~bourbon/core/bourbon';
|
||||
|
|
|
@ -42,14 +42,6 @@ $resolve-button-width: 13.2rem;
|
|||
margin-right: var(--space-normal);
|
||||
min-width: 0;
|
||||
|
||||
.user--name {
|
||||
@include margin(0);
|
||||
display: inline-block;
|
||||
font-size: $font-size-medium;
|
||||
line-height: 1.3;
|
||||
text-transform: capitalize;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user--profile__meta {
|
||||
align-items: flex-start;
|
||||
|
@ -59,12 +51,6 @@ $resolve-button-width: 13.2rem;
|
|||
margin-left: $space-slab;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.user--profile__button {
|
||||
font-size: $font-size-mini;
|
||||
margin-top: $space-micro;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
35
app/javascript/dashboard/components/widgets/InboxName.vue
Normal file
35
app/javascript/dashboard/components/widgets/InboxName.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<span class="inbox--name">
|
||||
<i :class="computedInboxClass" />
|
||||
{{ inbox.name }}
|
||||
</span>
|
||||
</template>
|
||||
<script>
|
||||
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
computedInboxClass() {
|
||||
const { phone_number: phoneNumber, channel_type: type } = this.inbox;
|
||||
const classByType = getInboxClassByType(type, phoneNumber);
|
||||
return classByType;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.inbox--name {
|
||||
padding: var(--space-micro) 0;
|
||||
line-height: var(--space-slab);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: none;
|
||||
color: var(--s-500);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
</style>
|
|
@ -19,11 +19,7 @@
|
|||
/>
|
||||
<div class="conversation--details columns">
|
||||
<div class="conversation--metadata">
|
||||
<span v-if="showInboxName" class="label">
|
||||
<i :class="computedInboxClass" />
|
||||
{{ inboxName }}
|
||||
</span>
|
||||
|
||||
<inbox-name v-if="showInboxName" :inbox="inbox" />
|
||||
<span
|
||||
v-if="showAssignee && assignee"
|
||||
class="label assignee-label text-truncate"
|
||||
|
@ -72,16 +68,17 @@
|
|||
import { mapGetters } from 'vuex';
|
||||
import { MESSAGE_TYPE } from 'widget/helpers/constants';
|
||||
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
||||
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
||||
import Thumbnail from '../Thumbnail';
|
||||
import conversationMixin from '../../../mixins/conversations';
|
||||
import timeMixin from '../../../mixins/time';
|
||||
import router from '../../../routes';
|
||||
import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
|
||||
import InboxName from '../InboxName';
|
||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InboxName,
|
||||
Thumbnail,
|
||||
},
|
||||
|
||||
|
@ -192,12 +189,6 @@ export default {
|
|||
return stateInbox;
|
||||
},
|
||||
|
||||
computedInboxClass() {
|
||||
const { phone_number: phoneNumber, channel_type: type } = this.inbox;
|
||||
const classByType = getInboxClassByType(type, phoneNumber);
|
||||
return classByType;
|
||||
},
|
||||
|
||||
showInboxName() {
|
||||
return (
|
||||
!this.hideInboxName &&
|
||||
|
@ -244,15 +235,6 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.conversation--details .label {
|
||||
padding: var(--space-micro) 0 var(--space-micro) 0;
|
||||
line-height: var(--space-slab);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: none;
|
||||
color: var(--s-500);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
.conversation--details {
|
||||
.conversation--user {
|
||||
padding-top: var(--space-micro);
|
||||
|
@ -276,6 +258,15 @@ export default {
|
|||
justify-content: space-between;
|
||||
padding-right: var(--space-normal);
|
||||
|
||||
.label {
|
||||
padding: var(--space-micro) 0 var(--space-micro) 0;
|
||||
line-height: var(--space-slab);
|
||||
font-weight: var(--font-weight-medium);
|
||||
background: none;
|
||||
color: var(--s-500);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
.assignee-label {
|
||||
max-width: 50%;
|
||||
}
|
||||
|
|
|
@ -12,20 +12,23 @@
|
|||
<h3 class="user--name text-truncate">
|
||||
{{ currentContact.name }}
|
||||
</h3>
|
||||
<woot-button
|
||||
class="user--profile__button"
|
||||
size="small"
|
||||
variant="link"
|
||||
@click="$emit('contact-panel-toggle')"
|
||||
>
|
||||
{{
|
||||
`${
|
||||
isContactPanelOpen
|
||||
? $t('CONVERSATION.HEADER.CLOSE')
|
||||
: $t('CONVERSATION.HEADER.OPEN')
|
||||
} ${$t('CONVERSATION.HEADER.DETAILS')}`
|
||||
}}
|
||||
</woot-button>
|
||||
<div class="conversation--header--actions">
|
||||
<inbox-name :inbox="inbox" class="margin-right-small" />
|
||||
<span
|
||||
v-if="isSnoozed"
|
||||
class="snoozed--display-text margin-right-small"
|
||||
>
|
||||
{{ snoozedDisplayText }}
|
||||
</span>
|
||||
<woot-button
|
||||
class="user--profile__button margin-right-small"
|
||||
size="small"
|
||||
variant="link"
|
||||
@click="$emit('contact-panel-toggle')"
|
||||
>
|
||||
{{ contactPanelToggleText }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -44,9 +47,13 @@ import agentMixin from '../../../mixins/agentMixin.js';
|
|||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||
import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers';
|
||||
import wootConstants from '../../../constants';
|
||||
import differenceInHours from 'date-fns/differenceInHours';
|
||||
import InboxName from '../InboxName';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
InboxName,
|
||||
MoreActions,
|
||||
Thumbnail,
|
||||
},
|
||||
|
@ -61,39 +68,50 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
currentChatAssignee: null,
|
||||
inboxId: null,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'inboxAssignableAgents/getUIFlags',
|
||||
currentChat: 'getSelectedChat',
|
||||
}),
|
||||
|
||||
chatMetadata() {
|
||||
return this.chat.meta;
|
||||
},
|
||||
|
||||
inbox() {
|
||||
const { inbox_id: inboxId } = this.chat;
|
||||
const stateInbox = this.$store.getters['inboxes/getInbox'](inboxId);
|
||||
return stateInbox;
|
||||
},
|
||||
|
||||
currentContact() {
|
||||
return this.$store.getters['contacts/getContact'](
|
||||
this.chat.meta.sender.id
|
||||
);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const { inbox_id: inboxId } = this.chat;
|
||||
this.inboxId = inboxId;
|
||||
isSnoozed() {
|
||||
return this.currentChat.status === wootConstants.STATUS_TYPE.SNOOZED;
|
||||
},
|
||||
snoozedDisplayText() {
|
||||
const { snoozed_until: snoozedUntil } = this.currentChat;
|
||||
if (snoozedUntil) {
|
||||
// When the snooze is applied, it schedules the unsnooze event to next day/week 9AM.
|
||||
// By that logic if the time difference is less than or equal to 24 + 9 hours we can consider it tomorrow.
|
||||
const MAX_TIME_DIFFERENCE = 33;
|
||||
const isSnoozedUntilTomorrow =
|
||||
differenceInHours(new Date(snoozedUntil), new Date()) <=
|
||||
MAX_TIME_DIFFERENCE;
|
||||
return this.$t(
|
||||
isSnoozedUntilTomorrow
|
||||
? 'CONVERSATION.HEADER.SNOOZED_UNTIL_TOMORROW'
|
||||
: 'CONVERSATION.HEADER.SNOOZED_UNTIL_NEXT_WEEK'
|
||||
);
|
||||
}
|
||||
return this.$t('CONVERSATION.HEADER.SNOOZED_UNTIL_NEXT_REPLY');
|
||||
},
|
||||
contactPanelToggleText() {
|
||||
return `${
|
||||
this.isContactPanelOpen
|
||||
? this.$t('CONVERSATION.HEADER.CLOSE')
|
||||
: this.$t('CONVERSATION.HEADER.OPEN')
|
||||
} ${this.$t('CONVERSATION.HEADER.DETAILS')}`;
|
||||
},
|
||||
inbox() {
|
||||
const { inbox_id: inboxId } = this.chat;
|
||||
return this.$store.getters['inboxes/getInbox'](inboxId);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -129,4 +147,28 @@ export default {
|
|||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.user--name {
|
||||
display: inline-block;
|
||||
font-size: var(--font-size-medium);
|
||||
line-height: 1.3;
|
||||
margin: 0;
|
||||
text-transform: capitalize;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.conversation--header--actions {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-size: var(--font-size-mini);
|
||||
|
||||
.user--profile__button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.snoozed--display-text {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--y-900);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,41 +1,29 @@
|
|||
<template>
|
||||
<div class="flex-container actions--container">
|
||||
<woot-button
|
||||
v-if="!currentChat.muted"
|
||||
v-tooltip="$t('CONTACT_PANEL.MUTE_CONTACT')"
|
||||
class="hollow secondary actions--button"
|
||||
icon="ion-volume-mute"
|
||||
@click="mute"
|
||||
/>
|
||||
<woot-button
|
||||
v-else
|
||||
v-tooltip.left="$t('CONTACT_PANEL.UNMUTE_CONTACT')"
|
||||
class="hollow secondary actions--button"
|
||||
icon="ion-volume-medium"
|
||||
@click="unmute"
|
||||
/>
|
||||
<woot-button
|
||||
v-tooltip="$t('CONTACT_PANEL.SEND_TRANSCRIPT')"
|
||||
class="hollow secondary actions--button"
|
||||
icon="ion-share"
|
||||
@click="toggleEmailActionsModal"
|
||||
/>
|
||||
<resolve-action
|
||||
:conversation-id="currentChat.id"
|
||||
:status="currentChat.status"
|
||||
/>
|
||||
<woot-button
|
||||
class="more--button"
|
||||
variant="clear"
|
||||
size="large"
|
||||
color-scheme="secondary"
|
||||
icon="ion-android-more-vertical"
|
||||
@click="toggleConversationActions"
|
||||
/>
|
||||
<div
|
||||
v-if="showConversationActions"
|
||||
v-on-clickaway="hideConversationActions"
|
||||
class="dropdown-pane dropdowm--bottom"
|
||||
:class="{ 'dropdown-pane--open': showConversationActions }"
|
||||
>
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item v-if="!currentChat.muted">
|
||||
<button class="button clear alert " @click="mute">
|
||||
<span>{{ $t('CONTACT_PANEL.MUTE_CONTACT') }}</span>
|
||||
</button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item v-else>
|
||||
<button class="button clear alert" @click="unmute">
|
||||
<span>{{ $t('CONTACT_PANEL.UNMUTE_CONTACT') }}</span>
|
||||
</button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item>
|
||||
<button class="button clear" @click="toggleEmailActionsModal">
|
||||
{{ $t('CONTACT_PANEL.SEND_TRANSCRIPT') }}
|
||||
</button>
|
||||
</woot-dropdown-item>
|
||||
</woot-dropdown-menu>
|
||||
</div>
|
||||
<email-transcript-modal
|
||||
v-if="showEmailActionsModal"
|
||||
:show="showEmailActionsModal"
|
||||
|
@ -50,13 +38,9 @@ import { mixin as clickaway } from 'vue-clickaway';
|
|||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import EmailTranscriptModal from './EmailTranscriptModal';
|
||||
import ResolveAction from '../../buttons/ResolveAction';
|
||||
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
|
||||
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WootDropdownMenu,
|
||||
WootDropdownItem,
|
||||
EmailTranscriptModal,
|
||||
ResolveAction,
|
||||
},
|
||||
|
@ -97,7 +81,16 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
.actions--container {
|
||||
align-items: center;
|
||||
|
||||
.button {
|
||||
font-size: var(--font-size-large);
|
||||
margin-right: var(--space-small);
|
||||
border-color: var(--color-border);
|
||||
color: var(--s-400);
|
||||
}
|
||||
}
|
||||
|
||||
.more--button {
|
||||
align-items: center;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import VueI18n from 'vue-i18n';
|
||||
import VTooltip from 'v-tooltip';
|
||||
|
||||
import Button from 'dashboard/components/buttons/Button';
|
||||
import i18n from 'dashboard/i18n';
|
||||
|
@ -10,6 +11,7 @@ import MoreActions from '../MoreActions';
|
|||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
localVue.use(VueI18n);
|
||||
localVue.use(VTooltip);
|
||||
|
||||
localVue.component('woot-button', Button);
|
||||
|
||||
|
@ -63,21 +65,9 @@ describe('MoveActions', () => {
|
|||
moreActions = mount(MoreActions, { store, localVue, i18n: i18nConfig });
|
||||
});
|
||||
|
||||
it('opens the menu when user clicks "more"', async () => {
|
||||
expect(moreActions.find('.dropdown-pane').exists()).toBe(false);
|
||||
|
||||
await moreActions.find('.more--button').trigger('click');
|
||||
|
||||
expect(moreActions.find('.dropdown-pane').exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('muting discussion', () => {
|
||||
it('triggers "muteConversation"', async () => {
|
||||
await moreActions.find('.more--button').trigger('click');
|
||||
|
||||
await moreActions
|
||||
.find('.dropdown-pane button:first-child')
|
||||
.trigger('click');
|
||||
await moreActions.find('button:first-child').trigger('click');
|
||||
|
||||
expect(muteConversation).toBeCalledWith(
|
||||
expect.any(Object),
|
||||
|
@ -87,11 +77,7 @@ describe('MoveActions', () => {
|
|||
});
|
||||
|
||||
it('shows alert', async () => {
|
||||
await moreActions.find('.more--button').trigger('click');
|
||||
|
||||
await moreActions
|
||||
.find('.dropdown-pane button:first-child')
|
||||
.trigger('click');
|
||||
await moreActions.find('button:first-child').trigger('click');
|
||||
|
||||
expect(window.bus.$emit).toBeCalledWith(
|
||||
'newToastMessage',
|
||||
|
@ -106,11 +92,7 @@ describe('MoveActions', () => {
|
|||
});
|
||||
|
||||
it('triggers "unmuteConversation"', async () => {
|
||||
await moreActions.find('.more--button').trigger('click');
|
||||
|
||||
await moreActions
|
||||
.find('.dropdown-pane button:first-child')
|
||||
.trigger('click');
|
||||
await moreActions.find('button:first-child').trigger('click');
|
||||
|
||||
expect(unmuteConversation).toBeCalledWith(
|
||||
expect.any(Object),
|
||||
|
@ -120,11 +102,7 @@ describe('MoveActions', () => {
|
|||
});
|
||||
|
||||
it('shows alert', async () => {
|
||||
await moreActions.find('.more--button').trigger('click');
|
||||
|
||||
await moreActions
|
||||
.find('.dropdown-pane button:first-child')
|
||||
.trigger('click');
|
||||
await moreActions.find('button:first-child').trigger('click');
|
||||
|
||||
expect(window.bus.$emit).toBeCalledWith(
|
||||
'newToastMessage',
|
||||
|
|
|
@ -39,7 +39,10 @@
|
|||
"OPEN_ACTION": "Open",
|
||||
"OPEN": "More",
|
||||
"CLOSE": "Close",
|
||||
"DETAILS": "details"
|
||||
"DETAILS": "details",
|
||||
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
|
||||
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week",
|
||||
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply"
|
||||
},
|
||||
"RESOLVE_DROPDOWN": {
|
||||
"MARK_PENDING": "Mark as pending",
|
||||
|
|
|
@ -91,7 +91,6 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/_utility-helpers.scss';
|
||||
.page-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ const actions = {
|
|||
commit(types.default.SET_LIST_LOADING_STATUS);
|
||||
try {
|
||||
const response = await ConversationApi.get(params);
|
||||
const { data } = response.data;
|
||||
const { payload: chatList, meta: metaData } = data;
|
||||
const {
|
||||
data: { payload: chatList, meta: metaData },
|
||||
} = response.data;
|
||||
commit(types.default.SET_ALL_CONVERSATION, chatList);
|
||||
dispatch('conversationStats/set', metaData);
|
||||
dispatch('conversationLabels/setBulkConversationLabels', chatList);
|
||||
|
@ -36,10 +37,7 @@ const actions = {
|
|||
);
|
||||
dispatch(
|
||||
'conversationPage/setCurrentPage',
|
||||
{
|
||||
filter: params.assigneeType,
|
||||
page: params.page,
|
||||
},
|
||||
{ filter: params.assigneeType, page: params.page },
|
||||
{ root: true }
|
||||
);
|
||||
if (!chatList.length) {
|
||||
|
@ -69,10 +67,7 @@ const actions = {
|
|||
} = await MessageApi.getPreviousMessages(data);
|
||||
commit(
|
||||
`conversationMetadata/${types.default.SET_CONVERSATION_METADATA}`,
|
||||
{
|
||||
id: data.conversationId,
|
||||
data: meta,
|
||||
}
|
||||
{ id: data.conversationId, data: meta }
|
||||
);
|
||||
commit(types.default.SET_PREVIOUS_CONVERSATIONS, {
|
||||
id: data.conversationId,
|
||||
|
@ -140,14 +135,22 @@ const actions = {
|
|||
{ conversationId, status, snoozedUntil = null }
|
||||
) => {
|
||||
try {
|
||||
const response = await ConversationApi.toggleStatus({
|
||||
const {
|
||||
data: {
|
||||
payload: {
|
||||
current_status: updatedStatus,
|
||||
snoozed_until: updatedSnoozedUntil,
|
||||
} = {},
|
||||
} = {},
|
||||
} = await ConversationApi.toggleStatus({
|
||||
conversationId,
|
||||
status,
|
||||
snoozedUntil,
|
||||
});
|
||||
commit(types.default.RESOLVE_CONVERSATION, {
|
||||
commit(types.default.CHANGE_CONVERSATION_STATUS, {
|
||||
conversationId,
|
||||
status: response.data.payload.current_status,
|
||||
status: updatedStatus,
|
||||
snoozedUntil: updatedSnoozedUntil,
|
||||
});
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
|
@ -223,11 +226,7 @@ const actions = {
|
|||
data: { id, agent_last_seen_at: lastSeen },
|
||||
} = await ConversationApi.markMessageRead(data);
|
||||
setTimeout(
|
||||
() =>
|
||||
commit(types.default.MARK_MESSAGE_READ, {
|
||||
id,
|
||||
lastSeen,
|
||||
}),
|
||||
() => commit(types.default.MARK_MESSAGE_READ, { id, lastSeen }),
|
||||
4000
|
||||
);
|
||||
} catch (error) {
|
||||
|
|
|
@ -69,9 +69,13 @@ export const mutations = {
|
|||
Vue.set(chat.meta, 'team', team);
|
||||
},
|
||||
|
||||
[types.default.RESOLVE_CONVERSATION](_state, { conversationId, status }) {
|
||||
[types.default.CHANGE_CONVERSATION_STATUS](
|
||||
_state,
|
||||
{ conversationId, status, snoozedUntil }
|
||||
) {
|
||||
const conversation =
|
||||
getters.getConversationById(_state)(conversationId) || {};
|
||||
Vue.set(conversation, 'snoozed_until', snoozedUntil);
|
||||
Vue.set(conversation, 'status', status);
|
||||
},
|
||||
|
||||
|
|
|
@ -217,15 +217,24 @@ describe('#actions', () => {
|
|||
describe('#toggleStatus', () => {
|
||||
it('sends correct mutations if toggle status is successful', async () => {
|
||||
axios.post.mockResolvedValue({
|
||||
data: { payload: { conversation_id: 1, current_status: 'resolved' } },
|
||||
data: {
|
||||
payload: {
|
||||
conversation_id: 1,
|
||||
current_status: 'snoozed',
|
||||
snoozed_until: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
await actions.toggleStatus(
|
||||
{ commit },
|
||||
{ conversationId: 1, status: 'resolved' }
|
||||
{ conversationId: 1, status: 'snoozed' }
|
||||
);
|
||||
expect(commit).toHaveBeenCalledTimes(1);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
['RESOLVE_CONVERSATION', { conversationId: 1, status: 'resolved' }],
|
||||
[
|
||||
'CHANGE_CONVERSATION_STATUS',
|
||||
{ conversationId: 1, status: 'snoozed', snoozedUntil: null },
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -161,7 +161,7 @@ describe('#mutations', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#RESOLVE_CONVERSATION', () => {
|
||||
describe('#CHANGE_CONVERSATION_STATUS', () => {
|
||||
it('updates the conversation status correctly', () => {
|
||||
const state = {
|
||||
allConversations: [
|
||||
|
@ -173,7 +173,7 @@ describe('#mutations', () => {
|
|||
],
|
||||
};
|
||||
|
||||
mutations[types.RESOLVE_CONVERSATION](state, {
|
||||
mutations[types.CHANGE_CONVERSATION_STATUS](state, {
|
||||
conversationId: '1',
|
||||
status: 'resolved',
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
|||
SET_CURRENT_CHAT_WINDOW: 'SET_CURRENT_CHAT_WINDOW',
|
||||
CLEAR_CURRENT_CHAT_WINDOW: 'CLEAR_CURRENT_CHAT_WINDOW',
|
||||
CLEAR_ALL_MESSAGES: 'CLEAR_ALL_MESSAGES',
|
||||
RESOLVE_CONVERSATION: 'RESOLVE_CONVERSATION',
|
||||
CHANGE_CONVERSATION_STATUS: 'CHANGE_CONVERSATION_STATUS',
|
||||
ADD_CONVERSATION: 'ADD_CONVERSATION',
|
||||
UPDATE_CONVERSATION: 'UPDATE_CONVERSATION',
|
||||
MUTE_CONVERSATION: 'MUTE_CONVERSATION',
|
||||
|
|
|
@ -4,12 +4,13 @@ class Conversations::EventDataPresenter < SimpleDelegator
|
|||
additional_attributes: additional_attributes,
|
||||
can_reply: can_reply?,
|
||||
channel: inbox.try(:channel_type),
|
||||
contact_inbox: contact_inbox,
|
||||
id: display_id,
|
||||
inbox_id: inbox_id,
|
||||
contact_inbox: contact_inbox,
|
||||
messages: push_messages,
|
||||
meta: push_meta,
|
||||
status: status,
|
||||
snoozed_until: snoozed_until,
|
||||
unread_count: unread_incoming_messages.count,
|
||||
**push_timestamps
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ end
|
|||
|
||||
json.payload do
|
||||
json.success @status
|
||||
json.current_status @conversation.status
|
||||
json.conversation_id @conversation.display_id
|
||||
json.current_status @conversation.status
|
||||
json.snoozed_until @conversation.snoozed_until
|
||||
end
|
||||
|
|
|
@ -24,16 +24,17 @@ else
|
|||
json.messages conversation.unread_messages.includes([:user, { attachments: [{ file_attachment: [:blob] }] }]).last(10).map(&:push_event_data)
|
||||
end
|
||||
|
||||
json.inbox_id conversation.inbox_id
|
||||
json.status conversation.status
|
||||
json.muted conversation.muted?
|
||||
json.can_reply conversation.can_reply?
|
||||
json.timestamp conversation.last_activity_at.to_i
|
||||
json.contact_last_seen_at conversation.contact_last_seen_at.to_i
|
||||
json.account_id conversation.account_id
|
||||
json.additional_attributes conversation.additional_attributes
|
||||
json.agent_last_seen_at conversation.agent_last_seen_at.to_i
|
||||
json.assignee_last_seen_at conversation.assignee_last_seen_at.to_i
|
||||
json.unread_count conversation.unread_incoming_messages.count
|
||||
json.additional_attributes conversation.additional_attributes
|
||||
json.can_reply conversation.can_reply?
|
||||
json.contact_last_seen_at conversation.contact_last_seen_at.to_i
|
||||
json.custom_attributes conversation.custom_attributes
|
||||
json.account_id conversation.account_id
|
||||
json.inbox_id conversation.inbox_id
|
||||
json.labels conversation.label_list
|
||||
json.muted conversation.muted?
|
||||
json.snoozed_until conversation.snoozed_until
|
||||
json.status conversation.status
|
||||
json.timestamp conversation.last_activity_at.to_i
|
||||
json.unread_count conversation.unread_incoming_messages.count
|
||||
|
|
|
@ -354,6 +354,7 @@ RSpec.describe Conversation, type: :model do
|
|||
timestamp: conversation.last_activity_at.to_i,
|
||||
can_reply: true,
|
||||
channel: 'Channel::WebWidget',
|
||||
snoozed_until: conversation.snoozed_until,
|
||||
contact_last_seen_at: conversation.contact_last_seen_at.to_i,
|
||||
agent_last_seen_at: conversation.agent_last_seen_at.to_i,
|
||||
unread_count: 0
|
||||
|
|
|
@ -22,6 +22,7 @@ RSpec.describe Conversations::EventDataPresenter do
|
|||
can_reply: conversation.can_reply?,
|
||||
channel: conversation.inbox.channel_type,
|
||||
timestamp: conversation.last_activity_at.to_i,
|
||||
snoozed_until: conversation.snoozed_until,
|
||||
contact_last_seen_at: conversation.contact_last_seen_at.to_i,
|
||||
agent_last_seen_at: conversation.agent_last_seen_at.to_i,
|
||||
unread_count: 0
|
||||
|
|
Loading…
Reference in a new issue