mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 03:57:52 +00:00
feat: Inbox header actions (Snooze/Delete) (#8858)
* feat: Inbox header actions (Snooze/Delete) * chore: Minor fix * chore: Fix eslint * Update inboxHotKeys.js * feat: custom snooze * Update actions.spec.js * chore: Clean up * chore: add snoozed_until to notification end point * chore: Minor fix * chore: Minor style fix * chore:Clean up * chore: review fixes * chore: Minor fix * chore: Adds alert --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -42,6 +42,12 @@ class NotificationsAPI extends ApiClient {
|
|||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snooze({ id, snoozedUntil = null }) {
|
||||||
|
return axios.post(`${this.url}/${id}/snooze`, {
|
||||||
|
snoozed_until: snoozedUntil,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new NotificationsAPI();
|
export default new NotificationsAPI();
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ import MoreActions from './MoreActions.vue';
|
|||||||
import Thumbnail from '../Thumbnail.vue';
|
import Thumbnail from '../Thumbnail.vue';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import { conversationListPageURL } from 'dashboard/helper/URLHelper';
|
import { conversationListPageURL } from 'dashboard/helper/URLHelper';
|
||||||
import { conversationReopenTime } from 'dashboard/helper/snoozeHelpers';
|
import { snoozedReopenTime } from 'dashboard/helper/snoozeHelpers';
|
||||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -158,7 +158,7 @@ export default {
|
|||||||
if (snoozedUntil) {
|
if (snoozedUntil) {
|
||||||
return `${this.$t(
|
return `${this.$t(
|
||||||
'CONVERSATION.HEADER.SNOOZED_UNTIL'
|
'CONVERSATION.HEADER.SNOOZED_UNTIL'
|
||||||
)} ${conversationReopenTime(snoozedUntil)}`;
|
)} ${snoozedReopenTime(snoozedUntil)}`;
|
||||||
}
|
}
|
||||||
return this.$t('CONVERSATION.HEADER.SNOOZED_UNTIL_NEXT_REPLY');
|
return this.$t('CONVERSATION.HEADER.SNOOZED_UNTIL_NEXT_REPLY');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -86,3 +86,6 @@ export const getConversationDashboardRoute = routeName => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isAInboxViewRoute = routeName =>
|
||||||
|
['inbox_view_conversation'].includes(routeName);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const findSnoozeTime = (snoozeType, currentDate = new Date()) => {
|
|||||||
|
|
||||||
return parsedDate ? getUnixTime(parsedDate) : null;
|
return parsedDate ? getUnixTime(parsedDate) : null;
|
||||||
};
|
};
|
||||||
export const conversationReopenTime = snoozedUntil => {
|
export const snoozedReopenTime = snoozedUntil => {
|
||||||
if (!snoozedUntil) {
|
if (!snoozedUntil) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
isAConversationRoute,
|
isAConversationRoute,
|
||||||
routeIsAccessibleFor,
|
routeIsAccessibleFor,
|
||||||
validateLoggedInRoutes,
|
validateLoggedInRoutes,
|
||||||
|
isAInboxViewRoute,
|
||||||
} from '../routeHelpers';
|
} from '../routeHelpers';
|
||||||
|
|
||||||
describe('#getCurrentAccount', () => {
|
describe('#getCurrentAccount', () => {
|
||||||
@@ -134,3 +135,10 @@ describe('getConversationDashboardRoute', () => {
|
|||||||
expect(getConversationDashboardRoute('non_existent_route')).toBeNull();
|
expect(getConversationDashboardRoute('non_existent_route')).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isAInboxViewRoute', () => {
|
||||||
|
it('returns true if inbox view route name is provided', () => {
|
||||||
|
expect(isAInboxViewRoute('inbox_view_conversation')).toBe(true);
|
||||||
|
expect(isAInboxViewRoute('inbox_conversation')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
findSnoozeTime,
|
findSnoozeTime,
|
||||||
conversationReopenTime,
|
snoozedReopenTime,
|
||||||
findStartOfNextWeek,
|
findStartOfNextWeek,
|
||||||
findStartOfNextMonth,
|
findStartOfNextMonth,
|
||||||
findNextDay,
|
findNextDay,
|
||||||
@@ -88,13 +88,13 @@ describe('#Snooze Helpers', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('conversationReopenTime', () => {
|
describe('snoozedReopenTime', () => {
|
||||||
it('should return nil if snoozedUntil is nil', () => {
|
it('should return nil if snoozedUntil is nil', () => {
|
||||||
expect(conversationReopenTime(null)).toEqual(null);
|
expect(snoozedReopenTime(null)).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return formatted date if snoozedUntil is not nil', () => {
|
it('should return formatted date if snoozedUntil is not nil', () => {
|
||||||
expect(conversationReopenTime('2023-06-07T09:00:00.000Z')).toEqual(
|
expect(snoozedReopenTime('2023-06-07T09:00:00.000Z')).toEqual(
|
||||||
'7 Jun, 9.00am'
|
'7 Jun, 9.00am'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -112,7 +112,8 @@
|
|||||||
"REMOVE_LABEL": "Remove label from the conversation",
|
"REMOVE_LABEL": "Remove label from the conversation",
|
||||||
"SETTINGS": "Settings",
|
"SETTINGS": "Settings",
|
||||||
"AI_ASSIST": "AI Assist",
|
"AI_ASSIST": "AI Assist",
|
||||||
"APPEARANCE": "Appearance"
|
"APPEARANCE": "Appearance",
|
||||||
|
"SNOOZE_NOTIFICATION": "Snooze Notification"
|
||||||
},
|
},
|
||||||
"COMMANDS": {
|
"COMMANDS": {
|
||||||
"GO_TO_CONVERSATION_DASHBOARD": "Go to Conversation Dashboard",
|
"GO_TO_CONVERSATION_DASHBOARD": "Go to Conversation Dashboard",
|
||||||
@@ -153,7 +154,8 @@
|
|||||||
"CHANGE_APPEARANCE": "Change Appearance",
|
"CHANGE_APPEARANCE": "Change Appearance",
|
||||||
"LIGHT_MODE": "Light",
|
"LIGHT_MODE": "Light",
|
||||||
"DARK_MODE": "Dark",
|
"DARK_MODE": "Dark",
|
||||||
"SYSTEM_MODE": "System"
|
"SYSTEM_MODE": "System",
|
||||||
|
"SNOOZE_NOTIFICATION": "Snooze Notification"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DASHBOARD_APPS": {
|
"DASHBOARD_APPS": {
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
"LOADING": "Fetching notifications",
|
"LOADING": "Fetching notifications",
|
||||||
"EOF": "All notifications loaded 🎉",
|
"EOF": "All notifications loaded 🎉",
|
||||||
"404": "There are no active notifications in this group.",
|
"404": "There are no active notifications in this group.",
|
||||||
"NOTE": "Notifications from all subscribed inboxes"
|
"NOTE": "Notifications from all subscribed inboxes",
|
||||||
|
"SNOOZED_UNTIL": "Snoozed until",
|
||||||
|
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
|
||||||
|
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week"
|
||||||
},
|
},
|
||||||
"ACTION_HEADER": {
|
"ACTION_HEADER": {
|
||||||
"SNOOZE": "Snooze notification",
|
"SNOOZE": "Snooze notification",
|
||||||
@@ -42,6 +45,15 @@
|
|||||||
"LABELS": "Labels",
|
"LABELS": "Labels",
|
||||||
"CONVERSATION_ID": "Conversation ID"
|
"CONVERSATION_ID": "Conversation ID"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ALERTS": {
|
||||||
|
"MARK_AS_READ": "Notification marked as read",
|
||||||
|
"MARK_AS_UNREAD": "Notification marked as unread",
|
||||||
|
"SNOOZE": "Notification snoozed",
|
||||||
|
"DELETE": "Notification deleted",
|
||||||
|
"MARK_ALL_READ": "All notifications marked as read",
|
||||||
|
"DELETE_ALL": "All notifications deleted",
|
||||||
|
"DELETE_ALL_READ": "All read notifications deleted"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,3 +71,5 @@ export const ICON_APPEARANCE = `<svg role="img" class="ninja-icon ninja-icon--fl
|
|||||||
export const ICON_LIGHT_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2Zm5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0Zm4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5h1.5ZM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19Zm-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5h1.5Zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06Zm1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06l-1.5 1.5Zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06Zm-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06l1.5 1.5Z"/></svg>`;
|
export const ICON_LIGHT_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 2Zm5 10a5 5 0 1 1-10 0a5 5 0 0 1 10 0Zm4.25.75a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5h1.5ZM12 19a.75.75 0 0 1 .75.75v1.5a.75.75 0 0 1-1.5 0v-1.5A.75.75 0 0 1 12 19Zm-7.75-6.25a.75.75 0 0 0 0-1.5h-1.5a.75.75 0 0 0 0 1.5h1.5Zm-.03-8.53a.75.75 0 0 1 1.06 0l1.5 1.5a.75.75 0 0 1-1.06 1.06l-1.5-1.5a.75.75 0 0 1 0-1.06Zm1.06 15.56a.75.75 0 1 1-1.06-1.06l1.5-1.5a.75.75 0 1 1 1.06 1.06l-1.5 1.5Zm14.5-15.56a.75.75 0 0 0-1.06 0l-1.5 1.5a.75.75 0 0 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06Zm-1.06 15.56a.75.75 0 1 0 1.06-1.06l-1.5-1.5a.75.75 0 1 0-1.06 1.06l1.5 1.5Z"/></svg>`;
|
||||||
export const ICON_DARK_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A9.965 9.965 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.232-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.961 9.961 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662Zm-8.248-4.903c-1.25 2.389-3.31 4.1-6.817 5.499a8.49 8.49 0 0 0 2.152 1.766a8.502 8.502 0 0 0 8.502-14.725a8.484 8.484 0 0 0-2.792-1.015c.647 3.384.23 6.043-1.045 8.475Z"/></svg>`;
|
export const ICON_DARK_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M20.026 17.001c-2.762 4.784-8.879 6.423-13.663 3.661A9.965 9.965 0 0 1 3.13 17.68a.75.75 0 0 1 .365-1.132c3.767-1.348 5.785-2.91 6.956-5.146c1.232-2.353 1.551-4.93.689-8.463a.75.75 0 0 1 .769-.927a9.961 9.961 0 0 1 4.457 1.327c4.784 2.762 6.423 8.879 3.66 13.662Zm-8.248-4.903c-1.25 2.389-3.31 4.1-6.817 5.499a8.49 8.49 0 0 0 2.152 1.766a8.502 8.502 0 0 0 8.502-14.725a8.484 8.484 0 0 0-2.792-1.015c.647 3.384.23 6.043-1.045 8.475Z"/></svg>`;
|
||||||
export const ICON_SYSTEM_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M4.25 3A2.25 2.25 0 0 0 2 5.25v10.5A2.25 2.25 0 0 0 4.25 18H9.5v1.25c0 .69-.56 1.25-1.25 1.25h-.5a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-.5c-.69 0-1.25-.56-1.25-1.25V18h5.25A2.25 2.25 0 0 0 22 15.75V5.25A2.25 2.25 0 0 0 19.75 3H4.25ZM13 18v1.25c0 .45.108.875.3 1.25h-2.6c.192-.375.3-.8.3-1.25V18h2ZM3.5 5.25a.75.75 0 0 1 .75-.75h15.5a.75.75 0 0 1 .75.75V13h-17V5.25Zm0 9.25h17v1.25a.75.75 0 0 1-.75.75H4.25a.75.75 0 0 1-.75-.75V14.5Z"/></svg>`;
|
export const ICON_SYSTEM_MODE = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M4.25 3A2.25 2.25 0 0 0 2 5.25v10.5A2.25 2.25 0 0 0 4.25 18H9.5v1.25c0 .69-.56 1.25-1.25 1.25h-.5a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-.5c-.69 0-1.25-.56-1.25-1.25V18h5.25A2.25 2.25 0 0 0 22 15.75V5.25A2.25 2.25 0 0 0 19.75 3H4.25ZM13 18v1.25c0 .45.108.875.3 1.25h-2.6c.192-.375.3-.8.3-1.25V18h2ZM3.5 5.25a.75.75 0 0 1 .75-.75h15.5a.75.75 0 0 1 .75.75V13h-17V5.25Zm0 9.25h17v1.25a.75.75 0 0 1-.75.75H4.25a.75.75 0 0 1-.75-.75V14.5Z"/></svg>`;
|
||||||
|
|
||||||
|
export const ICON_SNOOZE_NOTIFICATION = `<svg role="img" class="ninja-icon ninja-icon--fluent" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="currentColor" d="M12 3.5c-3.104 0-6 2.432-6 6.25v4.153L4.682 17h14.67l-1.354-3.093V11.75a.75.75 0 0 1 1.5 0v1.843l1.381 3.156a1.25 1.25 0 0 1-1.145 1.751H15a3.002 3.002 0 0 1-6.003 0H4.305a1.25 1.25 0 0 1-1.15-1.739l1.344-3.164V9.75C4.5 5.068 8.103 2 12 2c.86 0 1.705.15 2.5.432a.75.75 0 0 1-.502 1.413A5.964 5.964 0 0 0 12 3.5ZM12 20c.828 0 1.5-.671 1.501-1.5h-3.003c0 .829.673 1.5 1.502 1.5Zm3.25-13h-2.5l-.101.007A.75.75 0 0 0 12.75 8.5h1.043l-1.653 2.314l-.055.09A.75.75 0 0 0 12.75 12h2.5l.102-.007a.75.75 0 0 0-.102-1.493h-1.042l1.653-2.314l.055-.09A.75.75 0 0 0 15.25 7Zm6-5h-3.5l-.101.007A.75.75 0 0 0 17.75 3.5h2.134l-2.766 4.347l-.05.09A.75.75 0 0 0 17.75 9h3.5l.102-.007A.75.75 0 0 0 21.25 7.5h-2.133l2.766-4.347l.05-.09A.75.75 0 0 0 21.25 2Z"/></svg>`;
|
||||||
|
|||||||
@@ -15,3 +15,6 @@ export const CMD_REOPEN_CONVERSATION = 'CMD_REOPEN_CONVERSATION';
|
|||||||
export const CMD_RESOLVE_CONVERSATION = 'CMD_RESOLVE_CONVERSATION';
|
export const CMD_RESOLVE_CONVERSATION = 'CMD_RESOLVE_CONVERSATION';
|
||||||
export const CMD_SNOOZE_CONVERSATION = 'CMD_SNOOZE_CONVERSATION';
|
export const CMD_SNOOZE_CONVERSATION = 'CMD_SNOOZE_CONVERSATION';
|
||||||
export const CMD_AI_ASSIST = 'CMD_AI_ASSIST';
|
export const CMD_AI_ASSIST = 'CMD_AI_ASSIST';
|
||||||
|
|
||||||
|
// Inbox Commands (Notifications)
|
||||||
|
export const CMD_SNOOZE_NOTIFICATION = 'CMD_SNOOZE_NOTIFICATION';
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import 'ninja-keys';
|
import 'ninja-keys';
|
||||||
import conversationHotKeysMixin from './conversationHotKeys';
|
import conversationHotKeysMixin from './conversationHotKeys';
|
||||||
|
import inboxHotKeysMixin from './inboxHotKeys';
|
||||||
import goToCommandHotKeys from './goToCommandHotKeys';
|
import goToCommandHotKeys from './goToCommandHotKeys';
|
||||||
import appearanceHotKeys from './appearanceHotKeys';
|
import appearanceHotKeys from './appearanceHotKeys';
|
||||||
import agentMixin from 'dashboard/mixins/agentMixin';
|
import agentMixin from 'dashboard/mixins/agentMixin';
|
||||||
@@ -25,6 +26,7 @@ export default {
|
|||||||
adminMixin,
|
adminMixin,
|
||||||
agentMixin,
|
agentMixin,
|
||||||
conversationHotKeysMixin,
|
conversationHotKeysMixin,
|
||||||
|
inboxHotKeysMixin,
|
||||||
conversationLabelMixin,
|
conversationLabelMixin,
|
||||||
conversationTeamMixin,
|
conversationTeamMixin,
|
||||||
appearanceHotKeys,
|
appearanceHotKeys,
|
||||||
@@ -42,6 +44,7 @@ export default {
|
|||||||
},
|
},
|
||||||
hotKeys() {
|
hotKeys() {
|
||||||
return [
|
return [
|
||||||
|
...this.inboxHotKeys,
|
||||||
...this.conversationHotKeys,
|
...this.conversationHotKeys,
|
||||||
...this.goToCommandHotKeys,
|
...this.goToCommandHotKeys,
|
||||||
...this.goToAppearanceHotKeys,
|
...this.goToAppearanceHotKeys,
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ import {
|
|||||||
UNMUTE_ACTION,
|
UNMUTE_ACTION,
|
||||||
MUTE_ACTION,
|
MUTE_ACTION,
|
||||||
} from './commandBarActions';
|
} from './commandBarActions';
|
||||||
import { isAConversationRoute } from '../../../helper/routeHelpers';
|
import {
|
||||||
|
isAConversationRoute,
|
||||||
|
isAInboxViewRoute,
|
||||||
|
} from '../../../helper/routeHelpers';
|
||||||
export default {
|
export default {
|
||||||
mixins: [aiMixin],
|
mixins: [aiMixin],
|
||||||
watch: {
|
watch: {
|
||||||
@@ -325,7 +328,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
conversationHotKeys() {
|
conversationHotKeys() {
|
||||||
if (isAConversationRoute(this.$route.name)) {
|
if (
|
||||||
|
isAConversationRoute(this.$route.name) ||
|
||||||
|
isAInboxViewRoute(this.$route.name)
|
||||||
|
) {
|
||||||
const defaultConversationHotKeys = [
|
const defaultConversationHotKeys = [
|
||||||
...this.statusActions,
|
...this.statusActions,
|
||||||
...this.conversationAdditionalActions,
|
...this.conversationAdditionalActions,
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
|
|
||||||
|
import { CMD_SNOOZE_NOTIFICATION } from './commandBarBusEvents';
|
||||||
|
import { ICON_SNOOZE_NOTIFICATION } from './CommandBarIcons';
|
||||||
|
|
||||||
|
import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
|
||||||
|
|
||||||
|
const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
|
||||||
|
|
||||||
|
const INBOX_SNOOZE_EVENTS = [
|
||||||
|
{
|
||||||
|
id: 'snooze_notification',
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.SNOOZE_NOTIFICATION',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
children: Object.values(SNOOZE_OPTIONS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: SNOOZE_OPTIONS.AN_HOUR_FROM_NOW,
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.AN_HOUR_FROM_NOW',
|
||||||
|
parent: 'snooze_notification',
|
||||||
|
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
handler: () =>
|
||||||
|
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: SNOOZE_OPTIONS.UNTIL_TOMORROW,
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.UNTIL_TOMORROW',
|
||||||
|
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||||
|
parent: 'snooze_notification',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
handler: () =>
|
||||||
|
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK,
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_WEEK',
|
||||||
|
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||||
|
parent: 'snooze_notification',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
handler: () =>
|
||||||
|
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH,
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.UNTIL_NEXT_MONTH',
|
||||||
|
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||||
|
parent: 'snooze_notification',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
handler: () =>
|
||||||
|
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME,
|
||||||
|
title: 'COMMAND_BAR.COMMANDS.CUSTOM',
|
||||||
|
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||||
|
parent: 'snooze_notification',
|
||||||
|
icon: ICON_SNOOZE_NOTIFICATION,
|
||||||
|
handler: () =>
|
||||||
|
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
inboxHotKeys() {
|
||||||
|
if (isAInboxViewRoute(this.$route.name)) {
|
||||||
|
return this.prepareActions(INBOX_SNOOZE_EVENTS);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
prepareActions(actions) {
|
||||||
|
return actions.map(action => ({
|
||||||
|
...action,
|
||||||
|
title: this.$t(action.title),
|
||||||
|
section: this.$t(action.section),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -40,12 +40,14 @@ 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';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
InboxCard,
|
InboxCard,
|
||||||
InboxListHeader,
|
InboxListHeader,
|
||||||
IntersectionObserver,
|
IntersectionObserver,
|
||||||
},
|
},
|
||||||
|
mixins: [alertMixin],
|
||||||
props: {
|
props: {
|
||||||
conversationId: {
|
conversationId: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
@@ -86,10 +88,6 @@ export default {
|
|||||||
if (this.$route.name === 'inbox') return;
|
if (this.$route.name === 'inbox') return;
|
||||||
this.$router.push({ name: 'inbox' });
|
this.$router.push({ name: 'inbox' });
|
||||||
},
|
},
|
||||||
onMarkAllDoneClick() {
|
|
||||||
this.$track(INBOX_EVENTS.MARK_ALL_NOTIFICATIONS_AS_READ);
|
|
||||||
this.$store.dispatch('notifications/readAll');
|
|
||||||
},
|
|
||||||
loadMoreNotifications() {
|
loadMoreNotifications() {
|
||||||
if (this.uiFlags.isAllNotificationsLoaded) return;
|
if (this.uiFlags.isAllNotificationsLoaded) return;
|
||||||
this.$store.dispatch('notifications/index', { page: this.page + 1 });
|
this.$store.dispatch('notifications/index', { page: this.page + 1 });
|
||||||
@@ -102,29 +100,41 @@ export default {
|
|||||||
primary_actor_id: primaryActorId,
|
primary_actor_id: primaryActorId,
|
||||||
primary_actor_type: primaryActorType,
|
primary_actor_type: primaryActorType,
|
||||||
} = notification;
|
} = notification;
|
||||||
this.$store.dispatch('notifications/read', {
|
this.$store
|
||||||
id,
|
.dispatch('notifications/read', {
|
||||||
primaryActorId,
|
id,
|
||||||
primaryActorType,
|
primaryActorId,
|
||||||
unreadCount: this.meta.unreadCount,
|
primaryActorType,
|
||||||
});
|
unreadCount: this.meta.unreadCount,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.MARK_AS_READ'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
markNotificationAsUnRead(notification) {
|
markNotificationAsUnRead(notification) {
|
||||||
this.$track(INBOX_EVENTS.MARK_NOTIFICATION_AS_UNREAD);
|
this.$track(INBOX_EVENTS.MARK_NOTIFICATION_AS_UNREAD);
|
||||||
this.redirectToInbox();
|
this.redirectToInbox();
|
||||||
const { id } = notification;
|
const { id } = notification;
|
||||||
this.$store.dispatch('notifications/unread', {
|
this.$store
|
||||||
id,
|
.dispatch('notifications/unread', {
|
||||||
});
|
id,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.MARK_AS_UNREAD'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deleteNotification(notification) {
|
deleteNotification(notification) {
|
||||||
this.$track(INBOX_EVENTS.DELETE_NOTIFICATION);
|
this.$track(INBOX_EVENTS.DELETE_NOTIFICATION);
|
||||||
this.redirectToInbox();
|
this.redirectToInbox();
|
||||||
this.$store.dispatch('notifications/delete', {
|
this.$store
|
||||||
notification,
|
.dispatch('notifications/delete', {
|
||||||
unread_count: this.meta.unreadCount,
|
notification,
|
||||||
count: this.meta.count,
|
unread_count: this.meta.unreadCount,
|
||||||
});
|
count: this.meta.count,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.DELETE'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<inbox-item-header
|
<inbox-item-header
|
||||||
:total-length="totalNotifications"
|
:total-length="totalNotifications"
|
||||||
:current-index="activeNotificationIndex"
|
:current-index="activeNotificationIndex"
|
||||||
|
:active-notification="activeNotification"
|
||||||
@next="onClickNext"
|
@next="onClickNext"
|
||||||
@prev="onClickPrev"
|
@prev="onClickPrev"
|
||||||
/>
|
/>
|
||||||
@@ -76,6 +77,11 @@ export default {
|
|||||||
allConversation: 'getAllConversations',
|
allConversation: 'getAllConversations',
|
||||||
uiFlags: 'notifications/getUIFlags',
|
uiFlags: 'notifications/getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
activeNotification() {
|
||||||
|
return this.notifications.find(
|
||||||
|
n => n.primary_actor.id === Number(this.conversationId)
|
||||||
|
);
|
||||||
|
},
|
||||||
isInboxViewEnabled() {
|
isInboxViewEnabled() {
|
||||||
return this.$store.getters['accounts/isFeatureEnabledGlobally'](
|
return this.$store.getters['accounts/isFeatureEnabledGlobally'](
|
||||||
this.currentAccountId,
|
this.currentAccountId,
|
||||||
|
|||||||
@@ -33,11 +33,10 @@
|
|||||||
/>
|
/>
|
||||||
<div class="flex min-w-0">
|
<div class="flex min-w-0">
|
||||||
<span
|
<span
|
||||||
class="font-medium text-slate-800 dark:text-slate-50 text-sm overflow-hidden text-ellipsis whitespace-nowrap"
|
class="text-slate-800 dark:text-slate-50 text-sm overflow-hidden text-ellipsis whitespace-nowrap"
|
||||||
|
:class="isUnread ? 'font-medium' : 'font-normal'"
|
||||||
>
|
>
|
||||||
<span class="font-normal text-sm">
|
{{ pushTitle }}
|
||||||
{{ pushTitle }}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,6 +46,11 @@
|
|||||||
{{ lastActivityAt }}
|
{{ lastActivityAt }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="snoozedUntilTime" class="flex items-center">
|
||||||
|
<span class="text-woot-500 dark:text-woot-500 text-xs font-medium">
|
||||||
|
{{ snoozedDisplayText }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<inbox-context-menu
|
<inbox-context-menu
|
||||||
v-if="isContextMenuOpen"
|
v-if="isContextMenuOpen"
|
||||||
:context-menu-position="contextMenuPosition"
|
:context-menu-position="contextMenuPosition"
|
||||||
@@ -63,6 +67,7 @@ import InboxNameAndId from './InboxNameAndId.vue';
|
|||||||
import InboxContextMenu from './InboxContextMenu.vue';
|
import InboxContextMenu from './InboxContextMenu.vue';
|
||||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
import timeMixin from 'dashboard/mixins/time';
|
import timeMixin from 'dashboard/mixins/time';
|
||||||
|
import { snoozedReopenTime } from 'dashboard/helper/snoozeHelpers';
|
||||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -138,6 +143,18 @@ export default {
|
|||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
},
|
},
|
||||||
|
snoozedUntilTime() {
|
||||||
|
const { snoozed_until: snoozedUntil } = this.notificationItem;
|
||||||
|
return snoozedUntil;
|
||||||
|
},
|
||||||
|
snoozedDisplayText() {
|
||||||
|
if (this.snoozedUntilTime) {
|
||||||
|
return `${this.$t('INBOX.LIST.SNOOZED_UNTIL')} ${snoozedReopenTime(
|
||||||
|
this.snoozedUntilTime
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.closeContextMenu();
|
this.closeContextMenu();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bg-white dark:bg-slate-900 w-40 py-1 border shadow-md border-slate-100 dark:border-slate-500 rounded-xl"
|
class="bg-white dark:bg-slate-900 w-40 py-1 border shadow-md border-slate-100 dark:border-slate-700/50 rounded-xl"
|
||||||
>
|
>
|
||||||
<menu-item
|
<menu-item
|
||||||
v-for="item in menuItems"
|
v-for="item in menuItems"
|
||||||
|
|||||||
@@ -3,18 +3,20 @@
|
|||||||
class="flex gap-2 py-2 pl-4 h-14 pr-2 justify-between items-center w-full border-b border-slate-50 dark:border-slate-800/50"
|
class="flex gap-2 py-2 pl-4 h-14 pr-2 justify-between items-center w-full border-b border-slate-50 dark:border-slate-800/50"
|
||||||
>
|
>
|
||||||
<pagination-button
|
<pagination-button
|
||||||
|
v-if="totalLength > 1"
|
||||||
:total-length="totalLength"
|
:total-length="totalLength"
|
||||||
:current-index="currentIndex"
|
:current-index="currentIndex"
|
||||||
@next="onClickNext"
|
@next="onClickNext"
|
||||||
@prev="onClickPrev"
|
@prev="onClickPrev"
|
||||||
/>
|
/>
|
||||||
|
<div v-else />
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<woot-button
|
<woot-button
|
||||||
variant="hollow"
|
variant="hollow"
|
||||||
size="small"
|
size="small"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
icon="snooze"
|
icon="snooze"
|
||||||
@click="onSnooze"
|
@click="openSnoozeNotificationModal"
|
||||||
>
|
>
|
||||||
{{ $t('INBOX.ACTION_HEADER.SNOOZE') }}
|
{{ $t('INBOX.ACTION_HEADER.SNOOZE') }}
|
||||||
</woot-button>
|
</woot-button>
|
||||||
@@ -23,20 +25,39 @@
|
|||||||
size="small"
|
size="small"
|
||||||
color-scheme="secondary"
|
color-scheme="secondary"
|
||||||
variant="hollow"
|
variant="hollow"
|
||||||
@click="onDelete"
|
@click="deleteNotification"
|
||||||
>
|
>
|
||||||
{{ $t('INBOX.ACTION_HEADER.DELETE') }}
|
{{ $t('INBOX.ACTION_HEADER.DELETE') }}
|
||||||
</woot-button>
|
</woot-button>
|
||||||
</div>
|
</div>
|
||||||
|
<woot-modal
|
||||||
|
:show.sync="showCustomSnoozeModal"
|
||||||
|
:on-close="hideCustomSnoozeModal"
|
||||||
|
>
|
||||||
|
<custom-snooze-modal
|
||||||
|
@close="hideCustomSnoozeModal"
|
||||||
|
@choose-time="scheduleCustomSnooze"
|
||||||
|
/>
|
||||||
|
</woot-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
import { getUnixTime } from 'date-fns';
|
||||||
|
import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
||||||
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
|
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
|
||||||
|
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 alertMixin from 'shared/mixins/alertMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PaginationButton,
|
PaginationButton,
|
||||||
|
CustomSnoozeModal,
|
||||||
},
|
},
|
||||||
|
mixins: [alertMixin],
|
||||||
props: {
|
props: {
|
||||||
totalLength: {
|
totalLength: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -46,10 +67,73 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
activeNotification: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showCustomSnoozeModal: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
meta: 'notifications/getMeta',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
bus.$on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
bus.$off(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSnooze() {},
|
openSnoozeNotificationModal() {
|
||||||
onDelete() {},
|
const ninja = document.querySelector('ninja-keys');
|
||||||
|
ninja.open({ parent: 'snooze_notification' });
|
||||||
|
},
|
||||||
|
hideCustomSnoozeModal() {
|
||||||
|
this.showCustomSnoozeModal = false;
|
||||||
|
},
|
||||||
|
snoozeNotification(snoozedUntil) {
|
||||||
|
this.$store
|
||||||
|
.dispatch('notifications/snooze', {
|
||||||
|
id: this.activeNotification?.id,
|
||||||
|
snoozedUntil,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.SNOOZE'));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCmdSnoozeNotification(snoozeType) {
|
||||||
|
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||||
|
this.showCustomSnoozeModal = true;
|
||||||
|
} else {
|
||||||
|
const snoozedUntil = findSnoozeTime(snoozeType) || null;
|
||||||
|
this.snoozeNotification(snoozedUntil);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scheduleCustomSnooze(customSnoozeTime) {
|
||||||
|
this.showCustomSnoozeModal = false;
|
||||||
|
if (customSnoozeTime) {
|
||||||
|
const snoozedUntil = getUnixTime(customSnoozeTime) || null;
|
||||||
|
this.snoozeNotification(snoozedUntil);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteNotification() {
|
||||||
|
this.$track(INBOX_EVENTS.DELETE_NOTIFICATION);
|
||||||
|
this.$store
|
||||||
|
.dispatch('notifications/delete', {
|
||||||
|
notification: this.activeNotification,
|
||||||
|
unread_count: this.meta.unreadCount,
|
||||||
|
count: this.meta.count,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.DELETE'));
|
||||||
|
});
|
||||||
|
this.$router.push({ name: 'inbox' });
|
||||||
|
},
|
||||||
onClickNext() {
|
onClickNext() {
|
||||||
this.$emit('next');
|
this.$emit('next');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,12 +60,14 @@ import { mixin as clickaway } from 'vue-clickaway';
|
|||||||
import InboxOptionMenu from './InboxOptionMenu.vue';
|
import InboxOptionMenu from './InboxOptionMenu.vue';
|
||||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
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: [clickaway],
|
mixins: [clickaway, alertMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showInboxDisplayMenu: false,
|
showInboxDisplayMenu: false,
|
||||||
@@ -75,13 +77,19 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
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');
|
this.$store.dispatch('notifications/readAll').then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.MARK_ALL_READ'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deleteAll() {
|
deleteAll() {
|
||||||
this.$store.dispatch('notifications/deleteAll');
|
this.$store.dispatch('notifications/deleteAll').then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.DELETE_ALL'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deleteAllRead() {
|
deleteAllRead() {
|
||||||
this.$store.dispatch('notifications/deleteAllRead');
|
this.$store.dispatch('notifications/deleteAllRead').then(() => {
|
||||||
|
this.showAlert(this.$t('INBOX.ALERTS.DELETE_ALL_READ'));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
openInboxDisplayMenu() {
|
openInboxDisplayMenu() {
|
||||||
this.showInboxDisplayMenu = !this.showInboxDisplayMenu;
|
this.showInboxDisplayMenu = !this.showInboxDisplayMenu;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col gap-1 bg-white z-50 dark:bg-slate-900 w-40 py-1 border shadow-md border-slate-100 dark:border-slate-500 rounded-xl divide-y divide-slate-100 dark:divide-slate-700/50"
|
class="flex flex-col gap-1 bg-white z-50 dark:bg-slate-900 w-40 py-1 border shadow-md border-slate-100 dark:border-slate-700/50 rounded-xl divide-y divide-slate-100 dark:divide-slate-700/50"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<menu-item
|
<menu-item
|
||||||
|
|||||||
@@ -119,6 +119,27 @@ export const actions = {
|
|||||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
snooze: async ({ commit }, { id, snoozedUntil }) => {
|
||||||
|
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true });
|
||||||
|
try {
|
||||||
|
const response = await NotificationsAPI.snooze({
|
||||||
|
id,
|
||||||
|
snoozedUntil,
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
data: { snoozed_until = null },
|
||||||
|
} = response;
|
||||||
|
commit(types.SNOOZE_NOTIFICATION, {
|
||||||
|
id,
|
||||||
|
snoozed_until,
|
||||||
|
});
|
||||||
|
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||||
|
} catch (error) {
|
||||||
|
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
addNotification({ commit }, data) {
|
addNotification({ commit }, data) {
|
||||||
commit(types.ADD_NOTIFICATION, data);
|
commit(types.ADD_NOTIFICATION, data);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,4 +72,8 @@ export const mutations = {
|
|||||||
[types.DELETE_ALL_NOTIFICATIONS]: $state => {
|
[types.DELETE_ALL_NOTIFICATIONS]: $state => {
|
||||||
Vue.set($state, 'records', {});
|
Vue.set($state, 'records', {});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[types.SNOOZE_NOTIFICATION]: ($state, { id, snoozed_until }) => {
|
||||||
|
Vue.set($state.records[id], 'snoozed_until', snoozed_until);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ describe('#actions', () => {
|
|||||||
await actions.deleteAllRead({ commit });
|
await actions.deleteAllRead({ commit });
|
||||||
expect(commit.mock.calls).toEqual([
|
expect(commit.mock.calls).toEqual([
|
||||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||||
|
[types.DELETE_READ_NOTIFICATIONS],
|
||||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -255,8 +256,29 @@ describe('#actions', () => {
|
|||||||
await actions.deleteAll({ commit });
|
await actions.deleteAll({ commit });
|
||||||
expect(commit.mock.calls).toEqual([
|
expect(commit.mock.calls).toEqual([
|
||||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||||
|
[types.DELETE_ALL_NOTIFICATIONS],
|
||||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('snooze', () => {
|
||||||
|
it('sends correct actions if API is success', async () => {
|
||||||
|
axios.post.mockResolvedValue({});
|
||||||
|
await actions.snooze({ commit }, { id: 1, snoozedUntil: 1703057715 });
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||||
|
[types.SNOOZE_NOTIFICATION, { id: 1, snoozed_until: 1703057715 }],
|
||||||
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('sends correct actions if API is error', async () => {
|
||||||
|
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||||
|
await actions.snooze({ commit }, { id: 1, snoozedUntil: 1703057715 });
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||||
|
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ export default {
|
|||||||
SET_ALL_NOTIFICATIONS_LOADED: 'SET_ALL_NOTIFICATIONS_LOADED',
|
SET_ALL_NOTIFICATIONS_LOADED: 'SET_ALL_NOTIFICATIONS_LOADED',
|
||||||
DELETE_READ_NOTIFICATIONS: 'DELETE_READ_NOTIFICATIONS',
|
DELETE_READ_NOTIFICATIONS: 'DELETE_READ_NOTIFICATIONS',
|
||||||
DELETE_ALL_NOTIFICATIONS: 'DELETE_ALL_NOTIFICATIONS',
|
DELETE_ALL_NOTIFICATIONS: 'DELETE_ALL_NOTIFICATIONS',
|
||||||
|
SNOOZE_NOTIFICATION: 'SNOOZE_NOTIFICATION',
|
||||||
|
|
||||||
// Contact Conversation
|
// Contact Conversation
|
||||||
SET_CONTACT_CONVERSATIONS_UI_FLAG: 'SET_CONTACT_CONVERSATIONS_UI_FLAG',
|
SET_CONTACT_CONVERSATIONS_UI_FLAG: 'SET_CONTACT_CONVERSATIONS_UI_FLAG',
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class Notification < ApplicationRecord
|
|||||||
user: user&.push_event_data,
|
user: user&.push_event_data,
|
||||||
created_at: created_at.to_i,
|
created_at: created_at.to_i,
|
||||||
last_activity_at: last_activity_at.to_i,
|
last_activity_at: last_activity_at.to_i,
|
||||||
|
snoozed_until: snoozed_until,
|
||||||
account_id: account_id
|
account_id: account_id
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ json.data do
|
|||||||
json.user notification.user.push_event_data
|
json.user notification.user.push_event_data
|
||||||
json.created_at notification.created_at.to_i
|
json.created_at notification.created_at.to_i
|
||||||
json.last_activity_at notification.last_activity_at.to_i
|
json.last_activity_at notification.last_activity_at.to_i
|
||||||
|
json.snoozed_until notification.snoozed_until
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user