aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/announcements/store.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/announcements/store.js')
-rw-r--r--src/features/announcements/store.js144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/features/announcements/store.js b/src/features/announcements/store.js
new file mode 100644
index 000000000..ad78a0979
--- /dev/null
+++ b/src/features/announcements/store.js
@@ -0,0 +1,144 @@
1import {
2 action,
3 computed,
4 observable,
5} from 'mobx';
6import semver from 'semver';
7import localStorage from 'mobx-localstorage';
8
9import { FeatureStore } from '../utils/FeatureStore';
10import { ANNOUNCEMENTS_ROUTES, GA_CATEGORY_ANNOUNCEMENTS } from '.';
11import { getAnnouncementRequest, getChangelogRequest, getCurrentVersionRequest } from './api';
12import { announcementActions } from './actions';
13import { createActionBindings } from '../utils/ActionBinding';
14import { createReactions } from '../../stores/lib/Reaction';
15import { gaEvent } from '../../lib/analytics';
16import { matchRoute } from '../../helpers/routing-helpers';
17
18const LOCAL_STORAGE_KEY = 'announcements';
19
20const debug = require('debug')('Franz:feature:announcements:store');
21
22export class AnnouncementsStore extends FeatureStore {
23 @observable targetVersion = null;
24
25 @observable isFeatureActive = false;
26
27 @computed get changelog() {
28 return getChangelogRequest.result;
29 }
30
31 @computed get announcement() {
32 if (!this.stores || !getAnnouncementRequest.result) return null;
33 const { locale, defaultLocale } = this.stores.app;
34 const announcement = getAnnouncementRequest.result;
35 // User locale
36 if (announcement[locale]) return announcement[locale];
37 // Default locale
38 if (announcement[defaultLocale]) return announcement[defaultLocale];
39 // No locales specified
40 return announcement;
41 }
42
43 @computed get areNewsAvailable() {
44 const isChangelogAvailable = getChangelogRequest.wasExecuted && !!this.changelog;
45 const isAnnouncementAvailable = getAnnouncementRequest.wasExecuted && !!this.announcement;
46 return isChangelogAvailable || isAnnouncementAvailable;
47 }
48
49 @computed get settings() {
50 return localStorage.getItem(LOCAL_STORAGE_KEY) || {};
51 }
52
53 @computed get lastSeenAnnouncementVersion() {
54 return this.settings.lastSeenAnnouncementVersion || null;
55 }
56
57 @computed get currentVersion() {
58 return getCurrentVersionRequest.result;
59 }
60
61 @computed get isNewUser() {
62 return this.stores.settings.stats.appStarts <= 1;
63 }
64
65 async start(stores, actions) {
66 debug('AnnouncementsStore::start');
67 this.stores = stores;
68 this.actions = actions;
69 getCurrentVersionRequest.execute();
70
71 this._registerActions(createActionBindings([
72 [announcementActions.show, this._showAnnouncement],
73 ]));
74
75 this._reactions = createReactions([
76 this._showAnnouncementOnRouteMatch,
77 this._showAnnouncementToUsersWhoUpdatedApp,
78 this._fetchAnnouncements,
79 ]);
80 this._registerReactions(this._reactions);
81 this.isFeatureActive = true;
82 }
83
84 stop() {
85 super.stop();
86 debug('AnnouncementsStore::stop');
87 this.isFeatureActive = false;
88 }
89
90 // ======= HELPERS ======= //
91
92 _updateSettings = (changes) => {
93 localStorage.setItem(LOCAL_STORAGE_KEY, {
94 ...this.settings,
95 ...changes,
96 });
97 };
98
99 // ======= ACTIONS ======= //
100
101 @action _showAnnouncement = ({ targetVersion } = {}) => {
102 const { router } = this.stores;
103 this.targetVersion = targetVersion || this.currentVersion;
104 this._updateSettings({
105 lastSeenAnnouncementVersion: this.currentVersion,
106 });
107 const targetRoute = `/announcements/${this.targetVersion}`;
108 if (router.location.pathname !== targetRoute) {
109 this.stores.router.push(targetRoute);
110 }
111 gaEvent(GA_CATEGORY_ANNOUNCEMENTS, 'show');
112 };
113
114 // ======= REACTIONS ========
115
116 _showAnnouncementToUsersWhoUpdatedApp = () => {
117 const { announcement, isNewUser } = this;
118 // Check if there is an announcement and don't show announcements to new users
119 if (!announcement || isNewUser) return;
120
121 // Check if the user has already used current version (= has seen the announcement)
122 const { currentVersion, lastSeenAnnouncementVersion } = this;
123 if (semver.gt(currentVersion, lastSeenAnnouncementVersion || '0.0.0')) {
124 debug(`${currentVersion} > ${lastSeenAnnouncementVersion}: announcement is shown`);
125 this._showAnnouncement();
126 }
127 };
128
129 _fetchAnnouncements = () => {
130 const targetVersion = this.targetVersion || this.currentVersion;
131 if (!targetVersion) return;
132 getChangelogRequest.reset().execute(targetVersion);
133 getAnnouncementRequest.reset().execute(targetVersion);
134 };
135
136 _showAnnouncementOnRouteMatch = () => {
137 const { router } = this.stores;
138 const match = matchRoute(ANNOUNCEMENTS_ROUTES.TARGET, router.location.pathname);
139 if (match) {
140 const targetVersion = match.id;
141 this._showAnnouncement({ targetVersion });
142 }
143 }
144}