This reverts commit 5ea0436051
.
This commit is contained in:
parent
7e5ec7925c
commit
bc7bcc20b8
10 changed files with 24 additions and 202 deletions
|
@ -12,11 +12,12 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||||
import { LocalStorage, LOCAL_STORAGE_KEYS } from '../../helper/localStorage';
|
import LocalStorage from '../../helper/localStorage';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import adminMixin from 'dashboard/mixins/isAdmin';
|
import adminMixin from 'dashboard/mixins/isAdmin';
|
||||||
|
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
|
const dismissedUpdates = new LocalStorage('dismissedUpdates');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -56,22 +57,16 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isVersionNotificationDismissed(version) {
|
isVersionNotificationDismissed(version) {
|
||||||
const dismissedVersions =
|
return dismissedUpdates.get().includes(version);
|
||||||
LocalStorage.get(LOCAL_STORAGE_KEYS.DISMISSED_UPDATES) || [];
|
|
||||||
return dismissedVersions.includes(version);
|
|
||||||
},
|
},
|
||||||
dismissUpdateBanner() {
|
dismissUpdateBanner() {
|
||||||
let updatedDismissedItems =
|
let updatedDismissedItems = dismissedUpdates.get();
|
||||||
LocalStorage.get(LOCAL_STORAGE_KEYS.DISMISSED_UPDATES) || [];
|
|
||||||
if (updatedDismissedItems instanceof Array) {
|
if (updatedDismissedItems instanceof Array) {
|
||||||
updatedDismissedItems.push(this.latestChatwootVersion);
|
updatedDismissedItems.push(this.latestChatwootVersion);
|
||||||
} else {
|
} else {
|
||||||
updatedDismissedItems = [this.latestChatwootVersion];
|
updatedDismissedItems = [this.latestChatwootVersion];
|
||||||
}
|
}
|
||||||
LocalStorage.set(
|
dismissedUpdates.store(updatedDismissedItems);
|
||||||
LOCAL_STORAGE_KEYS.DISMISSED_UPDATES,
|
|
||||||
updatedDismissedItems
|
|
||||||
);
|
|
||||||
this.latestChatwootVersion = this.globalConfig.appVersion;
|
this.latestChatwootVersion = this.globalConfig.appVersion;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -148,8 +148,8 @@ export default {
|
||||||
showCannedMenu(updatedValue) {
|
showCannedMenu(updatedValue) {
|
||||||
this.$emit('toggle-canned-menu', !this.isPrivate && updatedValue);
|
this.$emit('toggle-canned-menu', !this.isPrivate && updatedValue);
|
||||||
},
|
},
|
||||||
value(newValue = '', oldValue = '') {
|
value(newValue = '') {
|
||||||
if (newValue !== oldValue) {
|
if (newValue !== this.lastValue) {
|
||||||
const { tr } = this.state;
|
const { tr } = this.state;
|
||||||
if (this.isFormatMode) {
|
if (this.isFormatMode) {
|
||||||
this.state = createState(
|
this.state = createState(
|
||||||
|
|
|
@ -137,7 +137,6 @@ import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
||||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||||
import { MAXIMUM_FILE_UPLOAD_SIZE } from 'shared/constants/messages';
|
import { MAXIMUM_FILE_UPLOAD_SIZE } from 'shared/constants/messages';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { debounce } from 'shared/helpers/TimeHelpers';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isEscape,
|
isEscape,
|
||||||
|
@ -150,8 +149,6 @@ import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||||
import { DirectUpload } from 'activestorage';
|
import { DirectUpload } from 'activestorage';
|
||||||
import { frontendURL } from '../../../helper/URLHelper';
|
import { frontendURL } from '../../../helper/URLHelper';
|
||||||
import { LocalStorage, LOCAL_STORAGE_KEYS } from '../../../helper/localStorage';
|
|
||||||
import { trimMessage } from '../../../store/modules/conversations/helpers';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -204,7 +201,6 @@ export default {
|
||||||
hasSlashCommand: false,
|
hasSlashCommand: false,
|
||||||
bccEmails: '',
|
bccEmails: '',
|
||||||
ccEmails: '',
|
ccEmails: '',
|
||||||
doAutoSaveDraft: () => {},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -410,19 +406,10 @@ export default {
|
||||||
profilePath() {
|
profilePath() {
|
||||||
return frontendURL(`accounts/${this.accountId}/profile/settings`);
|
return frontendURL(`accounts/${this.accountId}/profile/settings`);
|
||||||
},
|
},
|
||||||
conversationId() {
|
|
||||||
return this.currentChat.id;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
currentChat(conversation, oldConversation) {
|
currentChat(conversation) {
|
||||||
const { can_reply: canReply } = conversation;
|
const { can_reply: canReply } = conversation;
|
||||||
|
|
||||||
if (oldConversation.id !== conversation.id) {
|
|
||||||
this.setToDraft(oldConversation.id, this.replyType);
|
|
||||||
this.getFromDraft();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isOnPrivateNote) {
|
if (this.isOnPrivateNote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -447,87 +434,22 @@ export default {
|
||||||
this.mentionSearchKey = '';
|
this.mentionSearchKey = '';
|
||||||
this.showMentions = false;
|
this.showMentions = false;
|
||||||
}
|
}
|
||||||
this.doAutoSaveDraft();
|
|
||||||
},
|
|
||||||
replyType(updatedReplyType, oldReplyType) {
|
|
||||||
this.setToDraft(this.conversationId, oldReplyType);
|
|
||||||
this.getFromDraft();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getFromDraft();
|
|
||||||
// Donot use the keyboard listener mixin here as the events here are supposed to be
|
// Donot use the keyboard listener mixin here as the events here are supposed to be
|
||||||
// working even if input/textarea is focussed.
|
// working even if input/textarea is focussed.
|
||||||
document.addEventListener('keydown', this.handleKeyEvents);
|
document.addEventListener('keydown', this.handleKeyEvents);
|
||||||
document.addEventListener('paste', this.onPaste);
|
document.addEventListener('paste', this.onPaste);
|
||||||
|
|
||||||
this.setCCEmailFromLastChat();
|
this.setCCEmailFromLastChat();
|
||||||
this.doAutoSaveDraft = debounce(
|
|
||||||
() => {
|
|
||||||
this.saveDraft(this.conversationId, this.replyType);
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
document.removeEventListener('keydown', this.handleKeyEvents);
|
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||||
document.removeEventListener('paste', this.onPaste);
|
document.removeEventListener('paste', this.onPaste);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getSavedDraftMessages() {
|
|
||||||
return LocalStorage.get(LOCAL_STORAGE_KEYS.DRAFT_MESSAGES) || {};
|
|
||||||
},
|
|
||||||
saveDraft(conversationId, replyType) {
|
|
||||||
if (this.message || this.message === '') {
|
|
||||||
const savedDraftMessages = this.getSavedDraftMessages();
|
|
||||||
const key = `draft-${conversationId}-${replyType}`;
|
|
||||||
const draftToSave = trimMessage(this.message || '');
|
|
||||||
const {
|
|
||||||
[key]: currentDraft,
|
|
||||||
...restOfDraftMessages
|
|
||||||
} = savedDraftMessages;
|
|
||||||
|
|
||||||
const updatedDraftMessages = draftToSave
|
|
||||||
? {
|
|
||||||
...restOfDraftMessages,
|
|
||||||
[key]: draftToSave,
|
|
||||||
}
|
|
||||||
: restOfDraftMessages;
|
|
||||||
|
|
||||||
LocalStorage.set(
|
|
||||||
LOCAL_STORAGE_KEYS.DRAFT_MESSAGES,
|
|
||||||
updatedDraftMessages
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setToDraft(conversationId, replyType) {
|
|
||||||
this.saveDraft(conversationId, replyType);
|
|
||||||
this.message = '';
|
|
||||||
},
|
|
||||||
getFromDraft() {
|
|
||||||
if (this.conversationId) {
|
|
||||||
try {
|
|
||||||
const key = `draft-${this.conversationId}-${this.replyType}`;
|
|
||||||
const savedDraftMessages = this.getSavedDraftMessages();
|
|
||||||
this.message = `${savedDraftMessages[key] || ''}`;
|
|
||||||
} catch (error) {
|
|
||||||
this.message = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeFromDraft() {
|
|
||||||
if (this.conversationId) {
|
|
||||||
const key = `draft-${this.conversationId}-${this.replyType}`;
|
|
||||||
const draftMessages = this.getSavedDraftMessages();
|
|
||||||
const { [key]: toBeRemoved, ...updatedDraftMessages } = draftMessages;
|
|
||||||
LocalStorage.set(
|
|
||||||
LOCAL_STORAGE_KEYS.DRAFT_MESSAGES,
|
|
||||||
updatedDraftMessages
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onPaste(e) {
|
onPaste(e) {
|
||||||
const data = e.clipboardData.files;
|
const data = e.clipboardData.files;
|
||||||
if (!this.showRichContentEditor && data.length !== 0) {
|
if (!this.showRichContentEditor && data.length !== 0) {
|
||||||
|
@ -615,7 +537,6 @@ export default {
|
||||||
messagePayload
|
messagePayload
|
||||||
);
|
);
|
||||||
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
|
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
|
||||||
this.removeFromDraft();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error?.response?.data?.error ||
|
error?.response?.data?.error ||
|
||||||
|
@ -687,7 +608,6 @@ export default {
|
||||||
},
|
},
|
||||||
onBlur() {
|
onBlur() {
|
||||||
this.isFocused = false;
|
this.isFocused = false;
|
||||||
this.saveDraft(this.conversationId, this.replyType);
|
|
||||||
},
|
},
|
||||||
onFocus() {
|
onFocus() {
|
||||||
this.isFocused = true;
|
this.isFocused = true;
|
||||||
|
|
|
@ -1,32 +1,17 @@
|
||||||
export const LOCAL_STORAGE_KEYS = {
|
class LocalStorage {
|
||||||
DISMISSED_UPDATES: 'dismissedUpdates',
|
constructor(key) {
|
||||||
DRAFT_MESSAGES: 'draftMessages',
|
this.key = key;
|
||||||
};
|
|
||||||
|
|
||||||
export const LocalStorage = {
|
|
||||||
clearAll() {
|
|
||||||
window.localStorage.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
get(key) {
|
|
||||||
const value = window.localStorage.getItem(key);
|
|
||||||
try {
|
|
||||||
return typeof value === 'string' ? JSON.parse(value) : value;
|
|
||||||
} catch (error) {
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
set(key, value) {
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
window.localStorage.setItem(key, JSON.stringify(value));
|
|
||||||
} else {
|
|
||||||
window.localStorage.setItem(key, value);
|
|
||||||
}
|
|
||||||
window.localStorage.setItem(key + ':ts', Date.now());
|
|
||||||
},
|
|
||||||
|
|
||||||
remove(key) {
|
store(allItems) {
|
||||||
window.localStorage.removeItem(key);
|
localStorage.setItem(this.key, JSON.stringify(allItems));
|
||||||
window.localStorage.removeItem(key + ':ts');
|
localStorage.setItem(this.key + ':ts', Date.now());
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
get() {
|
||||||
|
let stored = localStorage.getItem(this.key);
|
||||||
|
return JSON.parse(stored) || [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LocalStorage;
|
||||||
|
|
|
@ -5,12 +5,7 @@ import * as types from '../mutation-types';
|
||||||
import authAPI from '../../api/auth';
|
import authAPI from '../../api/auth';
|
||||||
import createAxios from '../../helper/APIHelper';
|
import createAxios from '../../helper/APIHelper';
|
||||||
import actionCable from '../../helper/actionCable';
|
import actionCable from '../../helper/actionCable';
|
||||||
import {
|
import { setUser, getHeaderExpiry, clearCookiesOnLogout } from '../utils/api';
|
||||||
setUser,
|
|
||||||
getHeaderExpiry,
|
|
||||||
clearCookiesOnLogout,
|
|
||||||
clearLocalStorageOnLogout,
|
|
||||||
} from '../utils/api';
|
|
||||||
import { getLoginRedirectURL } from '../../helper/URLHelper';
|
import { getLoginRedirectURL } from '../../helper/URLHelper';
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
@ -99,9 +94,9 @@ export const actions = {
|
||||||
.login(credentials)
|
.login(credentials)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
commit(types.default.SET_CURRENT_USER);
|
commit(types.default.SET_CURRENT_USER);
|
||||||
clearLocalStorageOnLogout();
|
|
||||||
window.axios = createAxios(axios);
|
window.axios = createAxios(axios);
|
||||||
actionCable.init(Vue);
|
actionCable.init(Vue);
|
||||||
|
|
||||||
window.location = getLoginRedirectURL(ssoAccountId, response.data);
|
window.location = getLoginRedirectURL(ssoAccountId, response.data);
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,10 +35,3 @@ export const applyPageFilters = (conversation, filters) => {
|
||||||
|
|
||||||
return shouldFilter;
|
return shouldFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const trimMessage = (content = '', maxLength = 1024) => {
|
|
||||||
if (content.length > maxLength) {
|
|
||||||
return content.substring(0, maxLength);
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {
|
import {
|
||||||
findPendingMessageIndex,
|
findPendingMessageIndex,
|
||||||
applyPageFilters,
|
applyPageFilters,
|
||||||
trimMessage,
|
|
||||||
} from '../../conversations/helpers';
|
} from '../../conversations/helpers';
|
||||||
|
|
||||||
const conversationList = [
|
const conversationList = [
|
||||||
|
@ -120,9 +119,3 @@ describe('#applyPageFilters', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#trimMessage', () => {
|
|
||||||
expect(trimMessage('Hello world', 5)).toEqual('Hello');
|
|
||||||
expect(trimMessage('Hello', 5)).toEqual('Hello');
|
|
||||||
expect(trimMessage(undefined, 5)).toEqual('');
|
|
||||||
});
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
CHATWOOT_RESET,
|
CHATWOOT_RESET,
|
||||||
CHATWOOT_SET_USER,
|
CHATWOOT_SET_USER,
|
||||||
} from '../../helper/scriptHelpers';
|
} from '../../helper/scriptHelpers';
|
||||||
import { LocalStorage, LOCAL_STORAGE_KEYS } from '../../helper/localStorage';
|
|
||||||
|
|
||||||
Cookies.defaults = { sameSite: 'Lax' };
|
Cookies.defaults = { sameSite: 'Lax' };
|
||||||
|
|
||||||
|
@ -44,15 +43,10 @@ export const clearBrowserSessionCookies = () => {
|
||||||
Cookies.remove('user');
|
Cookies.remove('user');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clearLocalStorageOnLogout = () => {
|
|
||||||
LocalStorage.remove(LOCAL_STORAGE_KEYS.DRAFT_MESSAGES);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const clearCookiesOnLogout = () => {
|
export const clearCookiesOnLogout = () => {
|
||||||
window.bus.$emit(CHATWOOT_RESET);
|
window.bus.$emit(CHATWOOT_RESET);
|
||||||
window.bus.$emit(ANALYTICS_RESET);
|
window.bus.$emit(ANALYTICS_RESET);
|
||||||
clearBrowserSessionCookies();
|
clearBrowserSessionCookies();
|
||||||
clearLocalStorageOnLogout();
|
|
||||||
const globalConfig = window.globalConfig || {};
|
const globalConfig = window.globalConfig || {};
|
||||||
const logoutRedirectLink =
|
const logoutRedirectLink =
|
||||||
globalConfig.LOGOUT_REDIRECT_LINK || frontendURL('login');
|
globalConfig.LOGOUT_REDIRECT_LINK || frontendURL('login');
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Returns a function, that, as long as it continues to be invoked, will not
|
|
||||||
// be triggered. The function will be called after it stops being called for
|
|
||||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
|
||||||
// leading edge, instead of the trailing.
|
|
||||||
|
|
||||||
export const debounce = (func, delay, immediate) => {
|
|
||||||
let timerId;
|
|
||||||
return (...args) => {
|
|
||||||
const boundFunc = func.bind(this, ...args);
|
|
||||||
clearTimeout(timerId);
|
|
||||||
if (immediate && !timerId) {
|
|
||||||
boundFunc();
|
|
||||||
}
|
|
||||||
const calleeFunc = immediate
|
|
||||||
? () => {
|
|
||||||
timerId = null;
|
|
||||||
}
|
|
||||||
: boundFunc;
|
|
||||||
timerId = setTimeout(calleeFunc, delay);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
import { debounce } from '../TimeHelpers';
|
|
||||||
// Tell Jest to mock all timeout functions
|
|
||||||
jest.useFakeTimers('modern');
|
|
||||||
|
|
||||||
describe('debounce', () => {
|
|
||||||
test('execute just once with immediate false', () => {
|
|
||||||
let func = jest.fn();
|
|
||||||
let debouncedFunc = debounce(func, 1000);
|
|
||||||
|
|
||||||
for (let i = 0; i < 100; i += 1) {
|
|
||||||
debouncedFunc();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast-forward time
|
|
||||||
jest.runAllTimers();
|
|
||||||
|
|
||||||
expect(func).toBeCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('execute just once with immediate true', () => {
|
|
||||||
let func = jest.fn();
|
|
||||||
let debouncedFunc = debounce(func, 1000, true);
|
|
||||||
|
|
||||||
for (let i = 0; i < 100; i += 1) {
|
|
||||||
debouncedFunc();
|
|
||||||
}
|
|
||||||
|
|
||||||
jest.runAllTimers();
|
|
||||||
|
|
||||||
expect(func).toBeCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in a new issue