chore: Cleanup update banner with localstorage updates (#5209)

Co-authored-by: Aswin Dev P.S <aswindevps@gmail.com>
This commit is contained in:
Pranav Raj S
2022-08-05 13:46:12 +05:30
committed by GitHub
parent fc9699d993
commit 124390a019
5 changed files with 104 additions and 63 deletions

View File

@@ -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;
}, },
}, },
}; };

View File

@@ -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);
});
});

View File

@@ -0,0 +1,8 @@
const semver = require('semver');
export const hasAnUpdateAvailable = (latestVersion, currentVersion) => {
if (!semver.valid(latestVersion)) {
return false;
}
return semver.lt(currentVersion, latestVersion);
};

View File

@@ -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');
},
};

View File

@@ -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),
};
}, },
}, },
}; };