aboutsummaryrefslogtreecommitdiffstats
path: root/src/stores
diff options
context:
space:
mode:
authorLibravatar vantezzen <hello@vantezzen.io>2019-10-24 15:15:42 +0200
committerLibravatar vantezzen <hello@vantezzen.io>2019-10-24 15:15:42 +0200
commit54f8b191a94bd78a85b046bbf21dd2245d3a6f3e (patch)
treeada5876f0e8a697ba4693bba07f5e0f31fea1fc9 /src/stores
parentUpdate submodules (diff)
parentbump version to 5.4.0 (diff)
downloadferdium-app-54f8b191a94bd78a85b046bbf21dd2245d3a6f3e.tar.gz
ferdium-app-54f8b191a94bd78a85b046bbf21dd2245d3a6f3e.tar.zst
ferdium-app-54f8b191a94bd78a85b046bbf21dd2245d3a6f3e.zip
Merge https://github.com/meetfranz/franz into franz-5.4.0-release
Diffstat (limited to 'src/stores')
-rw-r--r--src/stores/AppStore.js57
-rw-r--r--src/stores/FeaturesStore.js5
-rw-r--r--src/stores/PaymentStore.js38
-rw-r--r--src/stores/ServicesStore.js8
-rw-r--r--src/stores/UserStore.js8
-rw-r--r--src/stores/index.js2
6 files changed, 113 insertions, 5 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index 40d98cf42..6ce79f2e2 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -26,7 +26,9 @@ import { sleep } from '../helpers/async-helpers';
26 26
27const debug = require('debug')('Ferdi:AppStore'); 27const debug = require('debug')('Ferdi:AppStore');
28 28
29const { app, systemPreferences, screen } = remote; 29const {
30 app, systemPreferences, screen, powerMonitor,
31} = remote;
30 32
31const mainWindow = remote.getCurrentWindow(); 33const mainWindow = remote.getCurrentWindow();
32 34
@@ -35,6 +37,8 @@ const autoLauncher = new AutoLaunch({
35 name: 'Ferdi', 37 name: 'Ferdi',
36}); 38});
37 39
40const CATALINA_NOTIFICATION_HACK_KEY = '_temp_askedForCatalinaNotificationPermissions';
41
38export default class AppStore extends Store { 42export default class AppStore extends Store {
39 updateStatusTypes = { 43 updateStatusTypes = {
40 CHECKING: 'CHECKING', 44 CHECKING: 'CHECKING',
@@ -55,6 +59,8 @@ export default class AppStore extends Store {
55 @observable isOnline = navigator.onLine; 59 @observable isOnline = navigator.onLine;
56 60
57 @observable authRequestFailed = false; 61 @observable authRequestFailed = false;
62
63 @observable timeSuspensionStart;
58 64
59 @observable timeOfflineStart; 65 @observable timeOfflineStart;
60 66
@@ -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,40 @@ 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 statsEvent('resumed-app');
211 }
212 });
213
214 // macOS catalina notifications hack
215 // notifications got stuck after upgrade but forcing a notification
216 // via `new Notification` triggered the permission request
217 if (isMac && !localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) {
218 // eslint-disable-next-line no-new
219 new window.Notification('Welcome to Franz 5', {
220 body: 'Have a wonderful day & happy messaging.',
221 });
222
223 localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, true);
224 }
225
226 statsEvent('app-start');
178 } 227 }
179 228
180 @computed get cacheSize() { 229 @computed get cacheSize() {
@@ -383,6 +432,12 @@ export default class AppStore extends Store {
383 } 432 }
384 } 433 }
385 434
435 _handleLogout() {
436 if (!this.stores.user.isLoggedIn) {
437 clearInterval(this.fetchDataInterval);
438 }
439 }
440
386 // Helpers 441 // Helpers
387 _appStartsCounter() { 442 _appStartsCounter() {
388 this.actions.settings.update({ 443 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';
21import communityRecipes from '../features/communityRecipes'; 21import communityRecipes from '../features/communityRecipes';
22import todos from '../features/todos'; 22import todos from '../features/todos';
23import accentColor from '../features/accentColor'; 23import accentColor from '../features/accentColor';
24import planSelection from '../features/planSelection';
25import trialStatusBar from '../features/trialStatusBar';
24 26
25import { DEFAULT_FEATURES_CONFIG } from '../config'; 27import { 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 @@
1import { action, observable, computed } from 'mobx'; 1import { action, observable, computed } from 'mobx';
2import { remote } from 'electron';
2 3
3import Store from './lib/Store'; 4import Store from './lib/Store';
4import CachedRequest from './lib/CachedRequest'; 5import CachedRequest from './lib/CachedRequest';
5import Request from './lib/Request'; 6import Request from './lib/Request';
6 7
8const { BrowserWindow } = remote;
9
7export default class PaymentStore extends Store { 10export 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 @@
1import { shell } from 'electron'; 1import { shell, remote } from 'electron';
2import { 2import {
3 action, 3 action,
4 reaction, 4 reaction,
@@ -23,6 +23,8 @@ import { KEEP_WS_LOADED_USID } from '../config';
23 23
24const debug = require('debug')('Ferdi:ServiceStore'); 24const debug = require('debug')('Ferdi:ServiceStore');
25 25
26const { app } = remote;
27
26export default class ServicesStore extends Store { 28export 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';
15import { serviceLimitStore } from '../features/serviceLimit'; 15import { serviceLimitStore } from '../features/serviceLimit';
16import { communityRecipesStore } from '../features/communityRecipes'; 16import { communityRecipesStore } from '../features/communityRecipes';
17import { todosStore } from '../features/todos'; 17import { todosStore } from '../features/todos';
18import { planSelectionStore } from '../features/planSelection';
18 19
19export default (api, actions, router) => { 20export 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) => {