chore: Cleanup update banner with localstorage updates (#5209)
Co-authored-by: Aswin Dev P.S <aswindevps@gmail.com>
This commit is contained in:
@@ -12,33 +12,26 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||||
import LocalStorage from '../../helper/localStorage';
|
import { LocalStorage, LOCAL_STORAGE_KEYS } from '../../helper/localStorage';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import adminMixin from 'dashboard/mixins/isAdmin';
|
import adminMixin from 'dashboard/mixins/isAdmin';
|
||||||
|
import { hasAnUpdateAvailable } from './versionCheckHelper';
|
||||||
const semver = require('semver');
|
|
||||||
const dismissedUpdates = new LocalStorage('dismissedUpdates');
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: { Banner },
|
||||||
Banner,
|
|
||||||
},
|
|
||||||
mixins: [adminMixin],
|
mixins: [adminMixin],
|
||||||
props: {
|
props: {
|
||||||
latestChatwootVersion: {
|
latestChatwootVersion: { type: String, default: '' },
|
||||||
type: String,
|
},
|
||||||
default: '',
|
data() {
|
||||||
},
|
return { userDismissedBanner: false };
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({ globalConfig: 'globalConfig/get' }),
|
...mapGetters({ globalConfig: 'globalConfig/get' }),
|
||||||
hasAnUpdateAvailable() {
|
updateAvailable() {
|
||||||
if (!semver.valid(this.latestChatwootVersion)) {
|
return hasAnUpdateAvailable(
|
||||||
return false;
|
this.latestChatwootVersion,
|
||||||
}
|
this.globalConfig.appVersion
|
||||||
return semver.lt(
|
|
||||||
this.globalConfig.appVersion,
|
|
||||||
this.latestChatwootVersion
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
bannerMessage() {
|
bannerMessage() {
|
||||||
@@ -48,8 +41,9 @@ export default {
|
|||||||
},
|
},
|
||||||
shouldShowBanner() {
|
shouldShowBanner() {
|
||||||
return (
|
return (
|
||||||
|
!this.userDismissedBanner &&
|
||||||
this.globalConfig.displayManifest &&
|
this.globalConfig.displayManifest &&
|
||||||
this.hasAnUpdateAvailable &&
|
this.updateAvailable &&
|
||||||
!this.isVersionNotificationDismissed(this.latestChatwootVersion) &&
|
!this.isVersionNotificationDismissed(this.latestChatwootVersion) &&
|
||||||
this.isAdmin
|
this.isAdmin
|
||||||
);
|
);
|
||||||
@@ -57,17 +51,23 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isVersionNotificationDismissed(version) {
|
isVersionNotificationDismissed(version) {
|
||||||
return dismissedUpdates.get().includes(version);
|
const dismissedVersions =
|
||||||
|
LocalStorage.get(LOCAL_STORAGE_KEYS.DISMISSED_UPDATES) || [];
|
||||||
|
return dismissedVersions.includes(version);
|
||||||
},
|
},
|
||||||
dismissUpdateBanner() {
|
dismissUpdateBanner() {
|
||||||
let updatedDismissedItems = dismissedUpdates.get();
|
let updatedDismissedItems =
|
||||||
|
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];
|
||||||
}
|
}
|
||||||
dismissedUpdates.store(updatedDismissedItems);
|
LocalStorage.set(
|
||||||
this.latestChatwootVersion = this.globalConfig.appVersion;
|
LOCAL_STORAGE_KEYS.DISMISSED_UPDATES,
|
||||||
|
updatedDismissedItems
|
||||||
|
);
|
||||||
|
this.userDismissedBanner = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { hasAnUpdateAvailable } from '../versionCheckHelper';
|
||||||
|
|
||||||
|
describe('#hasAnUpdateAvailable', () => {
|
||||||
|
it('return false if latest version is invalid', () => {
|
||||||
|
expect(hasAnUpdateAvailable('invalid', '1.0.0')).toBe(false);
|
||||||
|
expect(hasAnUpdateAvailable(null, '1.0.0')).toBe(false);
|
||||||
|
expect(hasAnUpdateAvailable(undefined, '1.0.0')).toBe(false);
|
||||||
|
expect(hasAnUpdateAvailable('', '1.0.0')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('return correct value if latest version is valid', () => {
|
||||||
|
expect(hasAnUpdateAvailable('1.1.0', '1.0.0')).toBe(true);
|
||||||
|
expect(hasAnUpdateAvailable('0.1.0', '1.0.0')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const semver = require('semver');
|
||||||
|
|
||||||
|
export const hasAnUpdateAvailable = (latestVersion, currentVersion) => {
|
||||||
|
if (!semver.valid(latestVersion)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return semver.lt(currentVersion, latestVersion);
|
||||||
|
};
|
||||||
@@ -1,17 +1,32 @@
|
|||||||
class LocalStorage {
|
export const LOCAL_STORAGE_KEYS = {
|
||||||
constructor(key) {
|
DISMISSED_UPDATES: 'dismissedUpdates',
|
||||||
this.key = key;
|
WIDGET_BUILDER: 'widgetBubble_',
|
||||||
}
|
};
|
||||||
|
|
||||||
store(allItems) {
|
export const LocalStorage = {
|
||||||
localStorage.setItem(this.key, JSON.stringify(allItems));
|
clearAll() {
|
||||||
localStorage.setItem(this.key + ':ts', Date.now());
|
window.localStorage.clear();
|
||||||
}
|
},
|
||||||
|
|
||||||
get() {
|
get(key) {
|
||||||
let stored = localStorage.getItem(this.key);
|
const value = window.localStorage.getItem(key);
|
||||||
return JSON.parse(stored) || [];
|
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());
|
||||||
|
},
|
||||||
|
|
||||||
export default LocalStorage;
|
remove(key) {
|
||||||
|
window.localStorage.removeItem(key);
|
||||||
|
window.localStorage.removeItem(key + ':ts');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@@ -158,7 +158,10 @@ import Widget from 'dashboard/modules/widget-preview/components/Widget';
|
|||||||
import InputRadioGroup from './components/InputRadioGroup';
|
import InputRadioGroup from './components/InputRadioGroup';
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import { required } from 'vuelidate/lib/validators';
|
import { required } from 'vuelidate/lib/validators';
|
||||||
import LocalStorage from 'dashboard/helper/localStorage';
|
import {
|
||||||
|
LocalStorage,
|
||||||
|
LOCAL_STORAGE_KEYS,
|
||||||
|
} from 'dashboard/helper/localStorage';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -225,6 +228,9 @@ export default {
|
|||||||
...mapGetters({
|
...mapGetters({
|
||||||
uiFlags: 'inboxes/getUIFlags',
|
uiFlags: 'inboxes/getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
storageKey() {
|
||||||
|
return `${LOCAL_STORAGE_KEYS.WIDGET_BUILDER}${this.inbox.id}`;
|
||||||
|
},
|
||||||
widgetScript() {
|
widgetScript() {
|
||||||
let options = {
|
let options = {
|
||||||
position: this.widgetBubblePosition,
|
position: this.widgetBubblePosition,
|
||||||
@@ -313,24 +319,25 @@ export default {
|
|||||||
this.replyTime = reply_time;
|
this.replyTime = reply_time;
|
||||||
this.avatarUrl = avatar_url;
|
this.avatarUrl = avatar_url;
|
||||||
|
|
||||||
// Widget Bubble Settings
|
const savedInformation = this.getSavedInboxInformation();
|
||||||
const { key, storage } = this.getLocalStorageWithKey(this.inbox.id);
|
if (savedInformation) {
|
||||||
this.widgetBubblePositions = this.widgetBubblePositions.map(item => {
|
this.widgetBubblePositions = this.widgetBubblePositions.map(item => {
|
||||||
if (item.id === storage.get(key).position) {
|
if (item.id === savedInformation.position) {
|
||||||
item.checked = true;
|
item.checked = true;
|
||||||
this.widgetBubblePosition = item.id;
|
this.widgetBubblePosition = item.id;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
this.widgetBubbleTypes = this.widgetBubbleTypes.map(item => {
|
this.widgetBubbleTypes = this.widgetBubbleTypes.map(item => {
|
||||||
if (item.id === storage.get(key).type) {
|
if (item.id === savedInformation.type) {
|
||||||
item.checked = true;
|
item.checked = true;
|
||||||
this.widgetBubbleType = item.id;
|
this.widgetBubbleType = item.id;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
this.widgetBubbleLauncherTitle =
|
this.widgetBubbleLauncherTitle =
|
||||||
storage.get(key).launcherTitle || 'Chat with us';
|
savedInformation.launcherTitle || 'Chat with us';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleWidgetBubblePositionChange(item) {
|
handleWidgetBubblePositionChange(item) {
|
||||||
this.widgetBubblePosition = item.id;
|
this.widgetBubblePosition = item.id;
|
||||||
@@ -372,7 +379,7 @@ export default {
|
|||||||
type: this.widgetBubbleType,
|
type: this.widgetBubbleType,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getLocalStorageWithKey(this.inbox.id).storage.store(bubbleSettings);
|
LocalStorage.set(this.storageKey, bubbleSettings);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -403,12 +410,8 @@ export default {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLocalStorageWithKey(id) {
|
getSavedInboxInformation() {
|
||||||
const storageKey = `widgetBubble_${id}`;
|
return LocalStorage.get(this.storageKey);
|
||||||
return {
|
|
||||||
key: storageKey,
|
|
||||||
storage: new LocalStorage(storageKey),
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user