diff options
Diffstat (limited to 'src/stores')
-rw-r--r-- | src/stores/AppStore.js | 53 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 5 | ||||
-rw-r--r-- | src/stores/PaymentStore.js | 38 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 8 | ||||
-rw-r--r-- | src/stores/UserStore.js | 8 | ||||
-rw-r--r-- | src/stores/index.js | 2 |
6 files changed, 109 insertions, 5 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 40d98cf42..c6724c20f 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -26,7 +26,9 @@ import { sleep } from '../helpers/async-helpers'; | |||
26 | 26 | ||
27 | const debug = require('debug')('Ferdi:AppStore'); | 27 | const debug = require('debug')('Ferdi:AppStore'); |
28 | 28 | ||
29 | const { app, systemPreferences, screen } = remote; | 29 | const { |
30 | app, systemPreferences, screen, powerMonitor, | ||
31 | } = remote; | ||
30 | 32 | ||
31 | const mainWindow = remote.getCurrentWindow(); | 33 | const mainWindow = remote.getCurrentWindow(); |
32 | 34 | ||
@@ -35,6 +37,8 @@ const autoLauncher = new AutoLaunch({ | |||
35 | name: 'Ferdi', | 37 | name: 'Ferdi', |
36 | }); | 38 | }); |
37 | 39 | ||
40 | const CATALINA_NOTIFICATION_HACK_KEY = '_temp_askedForCatalinaNotificationPermissions'; | ||
41 | |||
38 | export default class AppStore extends Store { | 42 | export default class AppStore extends Store { |
39 | updateStatusTypes = { | 43 | updateStatusTypes = { |
40 | CHECKING: 'CHECKING', | 44 | CHECKING: 'CHECKING', |
@@ -56,6 +60,8 @@ export default class AppStore extends Store { | |||
56 | 60 | ||
57 | @observable authRequestFailed = false; | 61 | @observable authRequestFailed = false; |
58 | 62 | ||
63 | @observable timeSuspensionStart; | ||
64 | |||
59 | @observable timeOfflineStart; | 65 | @observable timeOfflineStart; |
60 | 66 | ||
61 | @observable updateStatus = null; | 67 | @observable updateStatus = null; |
@@ -76,6 +82,8 @@ export default class AppStore extends Store { | |||
76 | 82 | ||
77 | dictionaries = []; | 83 | dictionaries = []; |
78 | 84 | ||
85 | fetchDataInterval = null; | ||
86 | |||
79 | constructor(...args) { | 87 | constructor(...args) { |
80 | super(...args); | 88 | super(...args); |
81 | 89 | ||
@@ -97,6 +105,7 @@ export default class AppStore extends Store { | |||
97 | this._setLocale.bind(this), | 105 | this._setLocale.bind(this), |
98 | this._muteAppHandler.bind(this), | 106 | this._muteAppHandler.bind(this), |
99 | this._handleFullScreen.bind(this), | 107 | this._handleFullScreen.bind(this), |
108 | this._handleLogout.bind(this), | ||
100 | ]); | 109 | ]); |
101 | } | 110 | } |
102 | 111 | ||
@@ -124,6 +133,12 @@ export default class AppStore extends Store { | |||
124 | this._systemDND(); | 133 | this._systemDND(); |
125 | setInterval(() => this._systemDND(), ms('5s')); | 134 | setInterval(() => this._systemDND(), ms('5s')); |
126 | 135 | ||
136 | this.fetchDataInterval = setInterval(() => { | ||
137 | this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); | ||
138 | this.stores.features.featuresRequest.invalidate({ immediately: true }); | ||
139 | this.stores.news.latestNewsRequest.invalidate({ immediately: true }); | ||
140 | }, ms('10m')); | ||
141 | |||
127 | // Check for updates once every 4 hours | 142 | // Check for updates once every 4 hours |
128 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); | 143 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); |
129 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) | 144 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) |
@@ -175,6 +190,36 @@ export default class AppStore extends Store { | |||
175 | 190 | ||
176 | debug('Window is visible/focused', isVisible); | 191 | debug('Window is visible/focused', isVisible); |
177 | }); | 192 | }); |
193 | |||
194 | powerMonitor.on('suspend', () => { | ||
195 | debug('System suspended starting timer'); | ||
196 | |||
197 | this.timeSuspensionStart = moment(); | ||
198 | }); | ||
199 | |||
200 | powerMonitor.on('resume', () => { | ||
201 | debug('System resumed, last suspended on', this.timeSuspensionStart.toString()); | ||
202 | |||
203 | if (this.timeSuspensionStart.add(10, 'm').isBefore(moment())) { | ||
204 | debug('Reloading services, user info and features'); | ||
205 | |||
206 | setTimeout(() => { | ||
207 | window.location.reload(); | ||
208 | }, ms('2s')); | ||
209 | } | ||
210 | }); | ||
211 | |||
212 | // macOS catalina notifications hack | ||
213 | // notifications got stuck after upgrade but forcing a notification | ||
214 | // via `new Notification` triggered the permission request | ||
215 | if (isMac && !localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) { | ||
216 | // eslint-disable-next-line no-new | ||
217 | new window.Notification('Welcome to Franz 5', { | ||
218 | body: 'Have a wonderful day & happy messaging.', | ||
219 | }); | ||
220 | |||
221 | localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, true); | ||
222 | } | ||
178 | } | 223 | } |
179 | 224 | ||
180 | @computed get cacheSize() { | 225 | @computed get cacheSize() { |
@@ -383,6 +428,12 @@ export default class AppStore extends Store { | |||
383 | } | 428 | } |
384 | } | 429 | } |
385 | 430 | ||
431 | _handleLogout() { | ||
432 | if (!this.stores.user.isLoggedIn) { | ||
433 | clearInterval(this.fetchDataInterval); | ||
434 | } | ||
435 | } | ||
436 | |||
386 | // Helpers | 437 | // Helpers |
387 | _appStartsCounter() { | 438 | _appStartsCounter() { |
388 | this.actions.settings.update({ | 439 | this.actions.settings.update({ |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 3d9542245..ab5d762c7 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -21,6 +21,8 @@ import serviceLimit from '../features/serviceLimit'; | |||
21 | import communityRecipes from '../features/communityRecipes'; | 21 | import communityRecipes from '../features/communityRecipes'; |
22 | import todos from '../features/todos'; | 22 | import todos from '../features/todos'; |
23 | import accentColor from '../features/accentColor'; | 23 | import accentColor from '../features/accentColor'; |
24 | import planSelection from '../features/planSelection'; | ||
25 | import trialStatusBar from '../features/trialStatusBar'; | ||
24 | 26 | ||
25 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 27 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
26 | 28 | ||
@@ -67,6 +69,7 @@ export default class FeaturesStore extends Store { | |||
67 | if (this.stores.user.isLoggedIn) { | 69 | if (this.stores.user.isLoggedIn) { |
68 | this.featuresRequest.invalidate({ immediately: true }); | 70 | this.featuresRequest.invalidate({ immediately: true }); |
69 | } else { | 71 | } else { |
72 | this.defaultFeaturesRequest.execute(); | ||
70 | this.defaultFeaturesRequest.invalidate({ immediately: true }); | 73 | this.defaultFeaturesRequest.invalidate({ immediately: true }); |
71 | } | 74 | } |
72 | } | 75 | } |
@@ -85,5 +88,7 @@ export default class FeaturesStore extends Store { | |||
85 | communityRecipes(this.stores, this.actions); | 88 | communityRecipes(this.stores, this.actions); |
86 | todos(this.stores, this.actions); | 89 | todos(this.stores, this.actions); |
87 | accentColor(this.stores, this.actions); | 90 | accentColor(this.stores, this.actions); |
91 | planSelection(this.stores, this.actions); | ||
92 | trialStatusBar(this.stores, this.actions); | ||
88 | } | 93 | } |
89 | } | 94 | } |
diff --git a/src/stores/PaymentStore.js b/src/stores/PaymentStore.js index 8579812ad..69e6eb9c3 100644 --- a/src/stores/PaymentStore.js +++ b/src/stores/PaymentStore.js | |||
@@ -1,9 +1,12 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { action, observable, computed } from 'mobx'; |
2 | import { remote } from 'electron'; | ||
2 | 3 | ||
3 | import Store from './lib/Store'; | 4 | import Store from './lib/Store'; |
4 | import CachedRequest from './lib/CachedRequest'; | 5 | import CachedRequest from './lib/CachedRequest'; |
5 | import Request from './lib/Request'; | 6 | import Request from './lib/Request'; |
6 | 7 | ||
8 | const { BrowserWindow } = remote; | ||
9 | |||
7 | export default class PaymentStore extends Store { | 10 | export default class PaymentStore extends Store { |
8 | @observable plansRequest = new CachedRequest(this.api.payment, 'plans'); | 11 | @observable plansRequest = new CachedRequest(this.api.payment, 'plans'); |
9 | 12 | ||
@@ -13,6 +16,7 @@ export default class PaymentStore extends Store { | |||
13 | super(...args); | 16 | super(...args); |
14 | 17 | ||
15 | this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); | 18 | this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); |
19 | this.actions.payment.upgradeAccount.listen(this._upgradeAccount.bind(this)); | ||
16 | } | 20 | } |
17 | 21 | ||
18 | @computed get plan() { | 22 | @computed get plan() { |
@@ -27,4 +31,38 @@ export default class PaymentStore extends Store { | |||
27 | 31 | ||
28 | return request; | 32 | return request; |
29 | } | 33 | } |
34 | |||
35 | @action _upgradeAccount({ planId, onCloseWindow = () => null }) { | ||
36 | let hostedPageURL = this.stores.features.features.subscribeURL; | ||
37 | |||
38 | const parsedUrl = new URL(hostedPageURL); | ||
39 | const params = new URLSearchParams(parsedUrl.search.slice(1)); | ||
40 | |||
41 | params.set('plan', planId); | ||
42 | |||
43 | hostedPageURL = this.stores.user.getAuthURL(`${parsedUrl.origin}${parsedUrl.pathname}?${params.toString()}`); | ||
44 | |||
45 | const win = new BrowserWindow({ | ||
46 | parent: remote.getCurrentWindow(), | ||
47 | modal: true, | ||
48 | title: '🔒 Upgrade Your Franz Account', | ||
49 | width: 800, | ||
50 | height: window.innerHeight - 100, | ||
51 | maxWidth: 800, | ||
52 | minWidth: 600, | ||
53 | autoHideMenuBar: true, | ||
54 | webPreferences: { | ||
55 | nodeIntegration: true, | ||
56 | webviewTag: true, | ||
57 | }, | ||
58 | }); | ||
59 | win.loadURL(`file://${__dirname}/../index.html#/payment/${encodeURIComponent(hostedPageURL)}`); | ||
60 | |||
61 | win.on('closed', () => { | ||
62 | this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); | ||
63 | this.stores.features.featuresRequest.invalidate({ immediately: true }); | ||
64 | |||
65 | onCloseWindow(); | ||
66 | }); | ||
67 | } | ||
30 | } | 68 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 185a6f0ae..934a8a6e0 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -1,4 +1,4 @@ | |||
1 | import { shell } from 'electron'; | 1 | import { shell, remote } from 'electron'; |
2 | import { | 2 | import { |
3 | action, | 3 | action, |
4 | reaction, | 4 | reaction, |
@@ -23,6 +23,8 @@ import { KEEP_WS_LOADED_USID } from '../config'; | |||
23 | 23 | ||
24 | const debug = require('debug')('Ferdi:ServiceStore'); | 24 | const debug = require('debug')('Ferdi:ServiceStore'); |
25 | 25 | ||
26 | const { app } = remote; | ||
27 | |||
26 | export default class ServicesStore extends Store { | 28 | export default class ServicesStore extends Store { |
27 | @observable allServicesRequest = new CachedRequest(this.api.services, 'all'); | 29 | @observable allServicesRequest = new CachedRequest(this.api.services, 'all'); |
28 | 30 | ||
@@ -818,7 +820,9 @@ export default class ServicesStore extends Store { | |||
818 | 820 | ||
819 | if (service.webview) { | 821 | if (service.webview) { |
820 | debug('Initialize recipe', service.recipe.id, service.name); | 822 | debug('Initialize recipe', service.recipe.id, service.name); |
821 | service.webview.send('initialize-recipe', service.shareWithWebview, service.recipe); | 823 | service.webview.send('initialize-recipe', Object.assign({ |
824 | franzVersion: app.getVersion(), | ||
825 | }, service.shareWithWebview), service.recipe); | ||
822 | } | 826 | } |
823 | } | 827 | } |
824 | 828 | ||
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 03aa79606..d6a2e5fde 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -78,6 +78,8 @@ export default class UserStore extends Store { | |||
78 | 78 | ||
79 | @observable logoutReason = null; | 79 | @observable logoutReason = null; |
80 | 80 | ||
81 | fetchUserInfoInterval = null; | ||
82 | |||
81 | constructor(...args) { | 83 | constructor(...args) { |
82 | super(...args); | 84 | super(...args); |
83 | 85 | ||
@@ -162,7 +164,7 @@ export default class UserStore extends Store { | |||
162 | } | 164 | } |
163 | 165 | ||
164 | @computed get isPremiumOverride() { | 166 | @computed get isPremiumOverride() { |
165 | return ((!this.team || !this.team.plan) && this.isPremium) || (this.team.state === 'expired' && this.isPremium); | 167 | return ((!this.team || !this.team.plan) && this.isPremium) || (this.team && this.team.state === 'expired' && this.isPremium); |
166 | } | 168 | } |
167 | 169 | ||
168 | @computed get isPersonal() { | 170 | @computed get isPersonal() { |
@@ -201,7 +203,7 @@ export default class UserStore extends Store { | |||
201 | } | 203 | } |
202 | 204 | ||
203 | @action async _signup({ | 205 | @action async _signup({ |
204 | firstname, lastname, email, password, accountType, company, | 206 | firstname, lastname, email, password, accountType, company, plan, currency, |
205 | }) { | 207 | }) { |
206 | const authToken = await this.signupRequest.execute({ | 208 | const authToken = await this.signupRequest.execute({ |
207 | firstname, | 209 | firstname, |
@@ -211,6 +213,8 @@ export default class UserStore extends Store { | |||
211 | accountType, | 213 | accountType, |
212 | company, | 214 | company, |
213 | locale: this.stores.app.locale, | 215 | locale: this.stores.app.locale, |
216 | plan, | ||
217 | currency, | ||
214 | }); | 218 | }); |
215 | 219 | ||
216 | this.hasCompletedSignup = true; | 220 | this.hasCompletedSignup = true; |
diff --git a/src/stores/index.js b/src/stores/index.js index 10dd56665..4eeef7982 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -15,6 +15,7 @@ import { announcementsStore } from '../features/announcements'; | |||
15 | import { serviceLimitStore } from '../features/serviceLimit'; | 15 | import { serviceLimitStore } from '../features/serviceLimit'; |
16 | import { communityRecipesStore } from '../features/communityRecipes'; | 16 | import { communityRecipesStore } from '../features/communityRecipes'; |
17 | import { todosStore } from '../features/todos'; | 17 | import { todosStore } from '../features/todos'; |
18 | import { planSelectionStore } from '../features/planSelection'; | ||
18 | 19 | ||
19 | export default (api, actions, router) => { | 20 | export default (api, actions, router) => { |
20 | const stores = {}; | 21 | const stores = {}; |
@@ -37,6 +38,7 @@ export default (api, actions, router) => { | |||
37 | serviceLimit: serviceLimitStore, | 38 | serviceLimit: serviceLimitStore, |
38 | communityRecipes: communityRecipesStore, | 39 | communityRecipes: communityRecipesStore, |
39 | todos: todosStore, | 40 | todos: todosStore, |
41 | planSelection: planSelectionStore, | ||
40 | }); | 42 | }); |
41 | // Initialize all stores | 43 | // Initialize all stores |
42 | Object.keys(stores).forEach((name) => { | 44 | Object.keys(stores).forEach((name) => { |