feat: add last snoozed time as a snooze option

This commit is contained in:
Vishnu Narayanan
2025-08-20 17:48:13 +05:30
parent 7fe94dc1a2
commit 1fed175e65
9 changed files with 134 additions and 3 deletions
@@ -1,6 +1,8 @@
<script>
import DatePicker from 'vue-datepicker-next';
import NextButton from 'dashboard/components-next/button/Button.vue';
import { getUnixTime } from 'date-fns';
import { saveLastCustomSnoozeTime } from 'dashboard/helper/customSnoozeStorage';
export default {
components: {
@@ -25,7 +27,12 @@ export default {
this.$emit('close');
},
chooseTime() {
this.$emit('chooseTime', this.snoozeTime);
if (this.snoozeTime) {
const unixTimestamp = getUnixTime(this.snoozeTime);
// Save the custom time to localStorage for future use
saveLastCustomSnoozeTime(unixTimestamp);
this.$emit('chooseTime', this.snoozeTime);
}
},
disabledDate(date) {
// Disable all the previous dates
@@ -1,6 +1,7 @@
<script>
import { getUnixTime } from 'date-fns';
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
import { getLastCustomSnoozeTime } from 'dashboard/helper/customSnoozeStorage';
import { emitter } from 'shared/helpers/mitt';
import wootConstants from 'dashboard/constants/globals';
import {
@@ -100,6 +101,17 @@ export default {
onCmdSnoozeConversation(snoozeType) {
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
this.showCustomTimeSnoozeModal = true;
} else if (
snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_LAST_CUSTOM_TIME
) {
// Use the saved custom time
const lastCustomTime = getLastCustomSnoozeTime();
if (lastCustomTime) {
this.updateConversations('snoozed', lastCustomTime);
} else {
// Fallback to showing custom modal if no saved time exists
this.showCustomTimeSnoozeModal = true;
}
} else {
this.updateConversations('snoozed', findSnoozeTime(snoozeType) || null);
}
@@ -2,6 +2,7 @@ import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useMapGetter } from 'dashboard/composables/store';
import wootConstants from 'dashboard/constants/globals';
import { hasLastCustomSnoozeTime } from 'dashboard/helper/customSnoozeStorage';
import {
CMD_BULK_ACTION_SNOOZE_CONVERSATION,
@@ -27,7 +28,16 @@ const SNOOZE_CONVERSATION_BULK_ACTIONS = [
title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
icon: ICON_SNOOZE_CONVERSATION,
children: Object.values(SNOOZE_OPTIONS),
children: () => {
const availableOptions = Object.values(SNOOZE_OPTIONS);
// Only include UNTIL_LAST_CUSTOM_TIME if there's a saved custom time
return availableOptions.filter(option => {
if (option === SNOOZE_OPTIONS.UNTIL_LAST_CUSTOM_TIME) {
return hasLastCustomSnoozeTime();
}
return true;
});
},
},
...createSnoozeHandlers(
CMD_BULK_ACTION_SNOOZE_CONVERSATION,
@@ -43,6 +43,7 @@ export default {
UNTIL_TOMORROW: 'until_tomorrow',
UNTIL_NEXT_WEEK: 'until_next_week',
UNTIL_NEXT_MONTH: 'until_next_month',
UNTIL_LAST_CUSTOM_TIME: 'until_last_custom_time',
UNTIL_CUSTOM_TIME: 'until_custom_time',
},
EXAMPLE_URL: 'example.com',
@@ -32,7 +32,30 @@ export const OPEN_CONVERSATION_ACTIONS = [
];
export const createSnoozeHandlers = (busEventName, parentId, section) => {
return Object.values(SNOOZE_OPTIONS).map(option => ({
// Only include UNTIL_LAST_CUSTOM_TIME in handlers if there's a saved custom time
const LAST_CUSTOM_SNOOZE_KEY = 'chatwoot_last_custom_snooze_time';
const hasLastCustomSnoozeTime = () => {
try {
const stored = localStorage.getItem(LAST_CUSTOM_SNOOZE_KEY);
if (!stored) return false;
const data = JSON.parse(stored);
const now = Date.now();
const sevenDaysInMs = 7 * 24 * 60 * 60 * 1000;
return now - data.savedAt <= sevenDaysInMs;
} catch {
return false;
}
};
const availableOptions = Object.values(SNOOZE_OPTIONS);
const snoozeOptions = availableOptions.filter(option => {
if (option === SNOOZE_OPTIONS.UNTIL_LAST_CUSTOM_TIME) {
return hasLastCustomSnoozeTime();
}
return true;
});
return snoozeOptions.map(option => ({
id: option,
title: `COMMAND_BAR.COMMANDS.${option.toUpperCase()}`,
parent: parentId,
@@ -0,0 +1,61 @@
const LAST_CUSTOM_SNOOZE_KEY = 'chatwoot_last_custom_snooze_time';
export const saveLastCustomSnoozeTime = snoozedUntil => {
if (!snoozedUntil) return;
try {
localStorage.setItem(
LAST_CUSTOM_SNOOZE_KEY,
JSON.stringify({
timestamp: snoozedUntil,
savedAt: Date.now(),
})
);
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to save custom snooze time:', error);
}
};
export const getLastCustomSnoozeTime = () => {
try {
const stored = localStorage.getItem(LAST_CUSTOM_SNOOZE_KEY);
if (!stored) return null;
const data = JSON.parse(stored);
// Check if the saved time is still in the future (within 7 days of when it was saved)
const now = Date.now();
const savedAt = data.savedAt;
const sevenDaysInMs = 7 * 24 * 60 * 60 * 1000;
// If saved more than 7 days ago, consider it stale
if (now - savedAt > sevenDaysInMs) {
localStorage.removeItem(LAST_CUSTOM_SNOOZE_KEY);
return null;
}
return data.timestamp;
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to get custom snooze time:', error);
localStorage.removeItem(LAST_CUSTOM_SNOOZE_KEY);
return null;
}
};
export const hasLastCustomSnoozeTime = () => {
return getLastCustomSnoozeTime() !== null;
};
export const formatLastCustomSnoozeTime = () => {
const timestamp = getLastCustomSnoozeTime();
if (!timestamp) return null;
try {
const date = new Date(timestamp * 1000); // Convert Unix timestamp to milliseconds
return date.toLocaleString();
} catch (error) {
return null;
}
};
@@ -12,6 +12,7 @@ import {
setSeconds,
} from 'date-fns';
import wootConstants from 'dashboard/constants/globals';
import { getLastCustomSnoozeTime } from './customSnoozeStorage';
const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
@@ -51,6 +52,9 @@ export const findSnoozeTime = (snoozeType, currentDate = new Date()) => {
parsedDate = setHoursToNine(findStartOfNextWeek(currentDate));
} else if (snoozeType === SNOOZE_OPTIONS.UNTIL_NEXT_MONTH) {
parsedDate = setHoursToNine(findStartOfNextMonth(currentDate));
} else if (snoozeType === SNOOZE_OPTIONS.UNTIL_LAST_CUSTOM_TIME) {
// Return the stored timestamp directly (already in Unix format)
return getLastCustomSnoozeTime();
}
return parsedDate ? getUnixTime(parsedDate) : null;
@@ -233,6 +233,7 @@
"UNTIL_TOMORROW": "Until tomorrow",
"UNTIL_NEXT_MONTH": "Until next month",
"AN_HOUR_FROM_NOW": "Until an hour from now",
"UNTIL_LAST_CUSTOM_TIME": "Use last custom time",
"UNTIL_CUSTOM_TIME": "Custom...",
"CHANGE_APPEARANCE": "Change Appearance",
"LIGHT_MODE": "Light",
@@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n';
import { useEmitter } from 'dashboard/composables/emitter';
import { getUnixTime } from 'date-fns';
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
import { getLastCustomSnoozeTime } from 'dashboard/helper/customSnoozeStorage';
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/helper/commandbar/events';
import wootConstants from 'dashboard/constants/globals';
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
@@ -31,6 +32,17 @@ const toggleStatus = async (status, snoozedUntil) => {
const onCmdSnoozeConversation = snoozeType => {
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
showCustomSnoozeModal.value = true;
} else if (
snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_LAST_CUSTOM_TIME
) {
// Use the saved custom time
const lastCustomTime = getLastCustomSnoozeTime();
if (lastCustomTime) {
toggleStatus(wootConstants.STATUS_TYPE.SNOOZED, lastCustomTime);
} else {
// Fallback to showing custom modal if no saved time exists
showCustomSnoozeModal.value = true;
}
} else {
toggleStatus(
wootConstants.STATUS_TYPE.SNOOZED,