Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
164b4df679 | ||
|
|
2014a82ff8 | ||
|
|
f60ab0eb1d | ||
|
|
dc6757df3d | ||
|
|
cfeddcbec2 |
@@ -150,6 +150,8 @@ import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
|
||||
import { generateBotMessageContent } from './helpers/botMessageContentHelper';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { ACCOUNT_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
||||
import { LocalStorage } from 'shared/helpers/localStorage';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -274,8 +276,7 @@ export default {
|
||||
copy: this.hasText,
|
||||
delete: this.hasText || this.hasAttachments,
|
||||
cannedResponse: this.isOutgoing && this.hasText,
|
||||
replyTo: false,
|
||||
// replyTo: !this.data.private && this.inboxSupportsReplyTo,
|
||||
replyTo: !this.data.private && this.inboxSupportsReplyTo,
|
||||
};
|
||||
},
|
||||
contentAttributes() {
|
||||
@@ -502,10 +503,11 @@ export default {
|
||||
this.contextMenuPosition = { x: null, y: null };
|
||||
},
|
||||
handleReplyTo() {
|
||||
this.$store.dispatch('draftMessages/setInReplyTo', {
|
||||
conversationId: this.data.conversation_id,
|
||||
inReplyToMessage: this.data.id,
|
||||
});
|
||||
const replyStorageKey = LOCAL_STORAGE_KEYS.MESSAGE_REPLY_TO;
|
||||
const { conversation_id: conversationId, id: replyTo } = this.data;
|
||||
|
||||
LocalStorage.updateJsonStore(replyStorageKey, conversationId, replyTo);
|
||||
bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
|
||||
},
|
||||
setupHighlightTimer() {
|
||||
if (Number(this.$route.query.messageId) !== Number(this.data.id)) {
|
||||
|
||||
@@ -124,6 +124,7 @@ import { LocalStorage } from 'shared/helpers/localStorage';
|
||||
|
||||
// constants
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||
import { REPLY_POLICY } from 'shared/constants/links';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
||||
@@ -165,12 +166,14 @@ export default {
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
accountId: 'getCurrentAccountId',
|
||||
currentChat: 'getSelectedChat',
|
||||
allConversations: 'getAllConversations',
|
||||
inboxesList: 'inboxes/getInboxes',
|
||||
listLoadingStatus: 'getAllMessagesLoaded',
|
||||
loadingChatList: 'getChatListLoadingStatus',
|
||||
appIntegrations: 'integrations/getAppIntegrations',
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
currentAccountId: 'getCurrentAccountId',
|
||||
}),
|
||||
isOpen() {
|
||||
@@ -318,7 +321,13 @@ export default {
|
||||
return this.currentChat.unread_count || 0;
|
||||
},
|
||||
inboxSupportsReplyTo() {
|
||||
return this.inboxHasFeature(INBOX_FEATURES.REPLY_TO);
|
||||
return (
|
||||
this.inboxHasFeature(INBOX_FEATURES.REPLY_TO) &&
|
||||
this.isFeatureEnabledonAccount(
|
||||
this.accountId,
|
||||
FEATURE_FLAGS.MESSAGE_REPLY_TO
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ export const LOCAL_STORAGE_KEYS = {
|
||||
DISMISSED_UPDATES: 'dismissedUpdates',
|
||||
WIDGET_BUILDER: 'widgetBubble_',
|
||||
DRAFT_MESSAGES: 'draftMessages',
|
||||
MESSAGE_IN_REPLY_TO: 'messageInReplyTo',
|
||||
COLOR_SCHEME: 'color_scheme',
|
||||
DISMISSED_LABEL_SUGGESTIONS: 'labelSuggestionsDismissed',
|
||||
MESSAGE_REPLY_TO: 'messageReplyTo',
|
||||
};
|
||||
|
||||
@@ -16,4 +16,5 @@ export const FEATURE_FLAGS = {
|
||||
TEAM_MANAGEMENT: 'team_management',
|
||||
VOICE_RECORDER: 'voice_recorder',
|
||||
AUDIT_LOGS: 'audit_logs',
|
||||
MESSAGE_REPLY_TO: 'message_reply_to',
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
||||
|
||||
const state = {
|
||||
records: LocalStorage.get(LOCAL_STORAGE_KEYS.DRAFT_MESSAGES) || {},
|
||||
inReplyTo: LocalStorage.get(LOCAL_STORAGE_KEYS.MESSAGE_IN_REPLY_TO) || {},
|
||||
replyEditorMode: REPLY_EDITOR_MODES.REPLY,
|
||||
};
|
||||
|
||||
@@ -15,9 +14,6 @@ export const getters = {
|
||||
get: _state => key => {
|
||||
return _state.records[key] || '';
|
||||
},
|
||||
getInReplyTo: _state => conversationId => {
|
||||
return _state.inReplyTo[conversationId];
|
||||
},
|
||||
getReplyEditorMode: _state => _state.replyEditorMode,
|
||||
};
|
||||
|
||||
@@ -28,12 +24,6 @@ export const actions = {
|
||||
delete: ({ commit }, { key }) => {
|
||||
commit(types.SET_DRAFT_MESSAGES, { key });
|
||||
},
|
||||
setInReplyTo({ commit }, { conversationId, inReplyToMessage }) {
|
||||
commit(types.SET_IN_REPLY_TO, { conversationId, inReplyToMessage });
|
||||
},
|
||||
deleteInReplyTo({ commit }, { conversationId }) {
|
||||
commit(types.REMOVE_IN_REPLY_TO, { conversationId });
|
||||
},
|
||||
setReplyEditorMode: ({ commit }, { mode }) => {
|
||||
commit(types.SET_REPLY_EDITOR_MODE, { mode });
|
||||
},
|
||||
@@ -49,16 +39,6 @@ export const mutations = {
|
||||
Vue.set($state, 'records', updatedRecords);
|
||||
LocalStorage.set(LOCAL_STORAGE_KEYS.DRAFT_MESSAGES, $state.records);
|
||||
},
|
||||
[types.SET_IN_REPLY_TO]($state, { conversationId, inReplyToMessage }) {
|
||||
Vue.set($state.inReplyTo, conversationId, inReplyToMessage);
|
||||
LocalStorage.set(LOCAL_STORAGE_KEYS.MESSAGE_IN_REPLY_TO, $state.inReplyTo);
|
||||
},
|
||||
[types.REMOVE_IN_REPLY_TO]($state, { conversationId }) {
|
||||
const { [conversationId]: messageIdToBeRemoved, ...newRecords } =
|
||||
$state.inReplyTo;
|
||||
Vue.set($state, 'inReplyTo', newRecords);
|
||||
LocalStorage.set(LOCAL_STORAGE_KEYS.DRAFT_MESSAGES, $state.inReplyTo);
|
||||
},
|
||||
[types.SET_REPLY_EDITOR_MODE]($state, { mode }) {
|
||||
Vue.set($state, 'replyEditorMode', mode);
|
||||
},
|
||||
|
||||
@@ -73,49 +73,4 @@ describe('#actions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setInReplyTo', () => {
|
||||
it('sends correct actions', async () => {
|
||||
await actions.setInReplyTo(
|
||||
{
|
||||
commit,
|
||||
state: {
|
||||
inReplyTo: {},
|
||||
},
|
||||
},
|
||||
{ conversationId: 45534, inReplyToMessage: 24332 }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_IN_REPLY_TO,
|
||||
{
|
||||
conversationId: 45534,
|
||||
inReplyToMessage: 24332,
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#deleteInReplyTo', () => {
|
||||
it('sends correct actions', async () => {
|
||||
await actions.deleteInReplyTo(
|
||||
{
|
||||
commit,
|
||||
state: {
|
||||
inReplyTo: {},
|
||||
},
|
||||
},
|
||||
{ conversationId: 45534 }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.REMOVE_IN_REPLY_TO,
|
||||
{
|
||||
conversationId: 45534,
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,24 +22,4 @@ describe('#getters', () => {
|
||||
};
|
||||
expect(getters.getReplyEditorMode(state)).toEqual('reply');
|
||||
});
|
||||
|
||||
describe('#getInReplyTo', () => {
|
||||
it('returns the inReplyTo value if key is present', () => {
|
||||
const state = {
|
||||
inReplyTo: {
|
||||
1234: 9876,
|
||||
},
|
||||
};
|
||||
expect(getters.getInReplyTo(state)(1234)).toEqual(9876);
|
||||
});
|
||||
|
||||
it('returns undefined if key is not present', () => {
|
||||
const state = {
|
||||
inReplyTo: {
|
||||
1234: 9876,
|
||||
},
|
||||
};
|
||||
expect(getters.getInReplyTo(state)('message-22')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,35 +31,6 @@ describe('#mutations', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_IN_REPLY_TO', () => {
|
||||
it('sets the inReplyTo value', () => {
|
||||
const state = {
|
||||
inReplyTo: {},
|
||||
};
|
||||
mutations[types.SET_IN_REPLY_TO](state, {
|
||||
conversationId: 1234,
|
||||
inReplyToMessage: 9876,
|
||||
});
|
||||
expect(state.inReplyTo).toEqual({
|
||||
1234: 9876,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#REMOVE_IN_REPLY_TO', () => {
|
||||
it('removes the inReplyTo value', () => {
|
||||
const state = {
|
||||
inReplyTo: {
|
||||
1234: 9876,
|
||||
},
|
||||
};
|
||||
mutations[types.REMOVE_IN_REPLY_TO](state, {
|
||||
conversationId: 1234,
|
||||
});
|
||||
expect(state.inReplyTo).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_REPLY_EDITOR_MODE', () => {
|
||||
it('sets the reply editor mode', () => {
|
||||
const state = {
|
||||
|
||||
@@ -28,8 +28,6 @@ export default {
|
||||
SET_DRAFT_MESSAGES: 'SET_DRAFT_MESSAGES',
|
||||
REMOVE_DRAFT_MESSAGES: 'REMOVE_DRAFT_MESSAGES',
|
||||
SET_REPLY_EDITOR_MODE: 'SET_REPLY_EDITOR_MODE',
|
||||
SET_IN_REPLY_TO: 'SET_IN_REPLY_TO',
|
||||
REMOVE_IN_REPLY_TO: 'REMOVE_IN_REPLY_TO',
|
||||
|
||||
SET_CURRENT_CHAT_WINDOW: 'SET_CURRENT_CHAT_WINDOW',
|
||||
CLEAR_CURRENT_CHAT_WINDOW: 'CLEAR_CURRENT_CHAT_WINDOW',
|
||||
|
||||
@@ -9,5 +9,6 @@ export const BUS_EVENTS = {
|
||||
TOGGLE_SIDEMENU: 'TOGGLE_SIDEMENU',
|
||||
ON_MESSAGE_LIST_SCROLL: 'ON_MESSAGE_LIST_SCROLL',
|
||||
WEBSOCKET_DISCONNECT: 'WEBSOCKET_DISCONNECT',
|
||||
TOGGLE_REPLY_TO_MESSAGE: 'TOGGLE_REPLY_TO_MESSAGE',
|
||||
SHOW_TOAST: 'newToastMessage',
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ export const LocalStorage = {
|
||||
} else {
|
||||
window.localStorage.setItem(key, value);
|
||||
}
|
||||
window.localStorage.setItem(key + ':ts', Date.now());
|
||||
window.localStorage.setItem(key + ':ts', Date.now().toString());
|
||||
},
|
||||
|
||||
setFlag(store, accountId, key, expiry = 24 * 60 * 60 * 1000) {
|
||||
@@ -46,4 +46,39 @@ export const LocalStorage = {
|
||||
window.localStorage.removeItem(key);
|
||||
window.localStorage.removeItem(key + ':ts');
|
||||
},
|
||||
|
||||
updateJsonStore(storeName, key, value) {
|
||||
try {
|
||||
const storedValue = this.get(storeName) || {};
|
||||
storedValue[key] = value;
|
||||
this.set(storeName, storedValue);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error updating JSON store in localStorage', e);
|
||||
}
|
||||
},
|
||||
|
||||
getFromJsonStore(storeName, key) {
|
||||
try {
|
||||
const storedValue = this.get(storeName) || {};
|
||||
return storedValue[key] || null;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error getting value from JSON store in localStorage', e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
deleteFromJsonStore(storeName, key) {
|
||||
try {
|
||||
const storedValue = this.get(storeName);
|
||||
if (storedValue && key in storedValue) {
|
||||
delete storedValue[key];
|
||||
this.set(storeName, storedValue);
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error deleting entry from JSON store in localStorage', e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import { LocalStorage } from '../localStorage';
|
||||
|
||||
// Mocking localStorage
|
||||
const localStorageMock = (() => {
|
||||
let store = {};
|
||||
return {
|
||||
getItem: key => store[key] || null,
|
||||
setItem: (key, value) => {
|
||||
store[key] = String(value);
|
||||
},
|
||||
removeItem: key => delete store[key],
|
||||
clear: () => {
|
||||
store = {};
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
value: localStorageMock,
|
||||
});
|
||||
|
||||
describe('LocalStorage utility', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('set and get methods', () => {
|
||||
LocalStorage.set('testKey', { a: 1 });
|
||||
expect(LocalStorage.get('testKey')).toEqual({ a: 1 });
|
||||
});
|
||||
|
||||
it('remove method', () => {
|
||||
LocalStorage.set('testKey', 'testValue');
|
||||
LocalStorage.remove('testKey');
|
||||
expect(LocalStorage.get('testKey')).toBeNull();
|
||||
});
|
||||
|
||||
it('updateJsonStore method', () => {
|
||||
LocalStorage.updateJsonStore('testStore', 'testKey', 'testValue');
|
||||
expect(LocalStorage.get('testStore')).toEqual({ testKey: 'testValue' });
|
||||
});
|
||||
|
||||
it('getFromJsonStore method', () => {
|
||||
LocalStorage.set('testStore', { testKey: 'testValue' });
|
||||
expect(LocalStorage.getFromJsonStore('testStore', 'testKey')).toBe(
|
||||
'testValue'
|
||||
);
|
||||
});
|
||||
|
||||
it('deleteFromJsonStore method', () => {
|
||||
LocalStorage.set('testStore', { testKey: 'testValue' });
|
||||
LocalStorage.deleteFromJsonStore('testStore', 'testKey');
|
||||
expect(LocalStorage.getFromJsonStore('testStore', 'testKey')).toBeNull();
|
||||
});
|
||||
|
||||
it('setFlag and getFlag methods', () => {
|
||||
const store = 'testStore';
|
||||
const accountId = '123';
|
||||
const key = 'flagKey';
|
||||
const expiry = 1000; // 1 second
|
||||
|
||||
// Set flag and verify it's set
|
||||
LocalStorage.setFlag(store, accountId, key, expiry);
|
||||
expect(LocalStorage.getFlag(store, accountId, key)).toBe(true);
|
||||
|
||||
// Wait for expiry and verify flag is not set
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
expect(LocalStorage.getFlag(store, accountId, key)).toBe(false);
|
||||
resolve();
|
||||
}, expiry + 100); // wait a bit more than expiry time to ensure the flag has expired
|
||||
});
|
||||
});
|
||||
|
||||
it('clearAll method', () => {
|
||||
LocalStorage.set('testKey1', 'testValue1');
|
||||
LocalStorage.set('testKey2', 'testValue2');
|
||||
LocalStorage.clearAll();
|
||||
expect(LocalStorage.get('testKey1')).toBeNull();
|
||||
expect(LocalStorage.get('testKey2')).toBeNull();
|
||||
});
|
||||
|
||||
it('set method with non-object value', () => {
|
||||
LocalStorage.set('testKey', 'testValue');
|
||||
expect(LocalStorage.get('testKey')).toBe('testValue');
|
||||
});
|
||||
|
||||
it('set and get methods with null value', () => {
|
||||
LocalStorage.set('testKey', null);
|
||||
expect(LocalStorage.get('testKey')).toBeNull();
|
||||
});
|
||||
|
||||
it('set and get methods with undefined value', () => {
|
||||
LocalStorage.set('testKey', undefined);
|
||||
expect(LocalStorage.get('testKey')).toBe('undefined');
|
||||
});
|
||||
|
||||
it('set and get methods with boolean value', () => {
|
||||
LocalStorage.set('testKey', true);
|
||||
expect(LocalStorage.get('testKey')).toBe(true);
|
||||
});
|
||||
|
||||
it('set and get methods with number value', () => {
|
||||
LocalStorage.set('testKey', 42);
|
||||
expect(LocalStorage.get('testKey')).toBe(42);
|
||||
});
|
||||
});
|
||||
@@ -57,3 +57,5 @@
|
||||
enabled: false
|
||||
- name: response_bot
|
||||
enabled: false
|
||||
- name: message_reply_to
|
||||
enabled: false
|
||||
|
||||
Reference in New Issue
Block a user