diff options
author | 2019-09-07 15:50:23 +0200 | |
---|---|---|
committer | 2019-09-07 15:50:23 +0200 | |
commit | e7a74514c1e7c3833dfdcf5900cb87f9e6e8354e (patch) | |
tree | b8314e4155503b135dcb07e8b4a0e847e25c19cf /src/stores | |
parent | Update CHANGELOG.md (diff) | |
parent | Update CHANGELOG.md (diff) | |
download | ferdium-app-e7a74514c1e7c3833dfdcf5900cb87f9e6e8354e.tar.gz ferdium-app-e7a74514c1e7c3833dfdcf5900cb87f9e6e8354e.tar.zst ferdium-app-e7a74514c1e7c3833dfdcf5900cb87f9e6e8354e.zip |
Merge branch 'master' of https://github.com/meetfranz/franz into franz-5.3.0
Diffstat (limited to 'src/stores')
-rw-r--r-- | src/stores/AppStore.js | 13 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 6 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 42 | ||||
-rw-r--r-- | src/stores/UserStore.js | 68 | ||||
-rw-r--r-- | src/stores/index.js | 6 |
5 files changed, 133 insertions, 2 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 2bfcdf640..61b63d52e 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -95,6 +95,7 @@ export default class AppStore extends Store { | |||
95 | this._offlineCheck.bind(this), | 95 | this._offlineCheck.bind(this), |
96 | this._setLocale.bind(this), | 96 | this._setLocale.bind(this), |
97 | this._muteAppHandler.bind(this), | 97 | this._muteAppHandler.bind(this), |
98 | this._handleFullScreen.bind(this), | ||
98 | ]); | 99 | ]); |
99 | } | 100 | } |
100 | 101 | ||
@@ -347,6 +348,8 @@ export default class AppStore extends Store { | |||
347 | this.locale = this._getDefaultLocale(); | 348 | this.locale = this._getDefaultLocale(); |
348 | } | 349 | } |
349 | 350 | ||
351 | moment.locale(this.locale); | ||
352 | |||
350 | debug(`Set locale to "${this.locale}"`); | 353 | debug(`Set locale to "${this.locale}"`); |
351 | } | 354 | } |
352 | 355 | ||
@@ -367,6 +370,16 @@ export default class AppStore extends Store { | |||
367 | } | 370 | } |
368 | } | 371 | } |
369 | 372 | ||
373 | _handleFullScreen() { | ||
374 | const body = document.querySelector('body'); | ||
375 | |||
376 | if (this.isFullScreen) { | ||
377 | body.classList.add('isFullScreen'); | ||
378 | } else { | ||
379 | body.classList.remove('isFullScreen'); | ||
380 | } | ||
381 | } | ||
382 | |||
370 | // Helpers | 383 | // Helpers |
371 | _appStartsCounter() { | 384 | _appStartsCounter() { |
372 | this.actions.settings.update({ | 385 | this.actions.settings.update({ |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index e7832088b..cf28b6bec 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -16,6 +16,9 @@ import workspaces from '../features/workspaces'; | |||
16 | import shareFranz from '../features/shareFranz'; | 16 | import shareFranz from '../features/shareFranz'; |
17 | import announcements from '../features/announcements'; | 17 | import announcements from '../features/announcements'; |
18 | import settingsWS from '../features/settingsWS'; | 18 | import settingsWS from '../features/settingsWS'; |
19 | import serviceLimit from '../features/serviceLimit'; | ||
20 | import communityRecipes from '../features/communityRecipes'; | ||
21 | import todos from '../features/todos'; | ||
19 | 22 | ||
20 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 23 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
21 | 24 | ||
@@ -75,5 +78,8 @@ export default class FeaturesStore extends Store { | |||
75 | shareFranz(this.stores, this.actions); | 78 | shareFranz(this.stores, this.actions); |
76 | announcements(this.stores, this.actions); | 79 | announcements(this.stores, this.actions); |
77 | settingsWS(this.stores, this.actions); | 80 | settingsWS(this.stores, this.actions); |
81 | serviceLimit(this.stores, this.actions); | ||
82 | communityRecipes(this.stores, this.actions); | ||
83 | todos(this.stores, this.actions); | ||
78 | } | 84 | } |
79 | } | 85 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 6c6b7589f..876851a66 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -12,6 +12,8 @@ import Request from './lib/Request'; | |||
12 | import CachedRequest from './lib/CachedRequest'; | 12 | import CachedRequest from './lib/CachedRequest'; |
13 | import { matchRoute } from '../helpers/routing-helpers'; | 13 | import { matchRoute } from '../helpers/routing-helpers'; |
14 | import { workspaceStore } from '../features/workspaces'; | 14 | import { workspaceStore } from '../features/workspaces'; |
15 | import { serviceLimitStore } from '../features/serviceLimit'; | ||
16 | import { RESTRICTION_TYPES } from '../models/Service'; | ||
15 | 17 | ||
16 | const debug = require('debug')('Franz:ServiceStore'); | 18 | const debug = require('debug')('Franz:ServiceStore'); |
17 | 19 | ||
@@ -74,6 +76,7 @@ export default class ServicesStore extends Store { | |||
74 | this._saveActiveService.bind(this), | 76 | this._saveActiveService.bind(this), |
75 | this._logoutReaction.bind(this), | 77 | this._logoutReaction.bind(this), |
76 | this._handleMuteSettings.bind(this), | 78 | this._handleMuteSettings.bind(this), |
79 | this._restrictServiceAccess.bind(this), | ||
77 | ]); | 80 | ]); |
78 | 81 | ||
79 | // Just bind this | 82 | // Just bind this |
@@ -97,7 +100,10 @@ export default class ServicesStore extends Store { | |||
97 | if (this.stores.user.isLoggedIn) { | 100 | if (this.stores.user.isLoggedIn) { |
98 | const services = this.allServicesRequest.execute().result; | 101 | const services = this.allServicesRequest.execute().result; |
99 | if (services) { | 102 | if (services) { |
100 | return observable(services.slice().slice().sort((a, b) => a.order - b.order)); | 103 | return observable(services.slice().slice().sort((a, b) => a.order - b.order).map((s, index) => { |
104 | s.index = index; | ||
105 | return s; | ||
106 | })); | ||
101 | } | 107 | } |
102 | } | 108 | } |
103 | return []; | 109 | return []; |
@@ -152,6 +158,8 @@ export default class ServicesStore extends Store { | |||
152 | 158 | ||
153 | // Actions | 159 | // Actions |
154 | @action async _createService({ recipeId, serviceData, redirect = true }) { | 160 | @action async _createService({ recipeId, serviceData, redirect = true }) { |
161 | if (serviceLimitStore.userHasReachedServiceLimit) return; | ||
162 | |||
155 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | 163 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); |
156 | 164 | ||
157 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; | 165 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; |
@@ -430,6 +438,9 @@ export default class ServicesStore extends Store { | |||
430 | redirect: false, | 438 | redirect: false, |
431 | }); | 439 | }); |
432 | } | 440 | } |
441 | } else if (channel === 'feature:todos') { | ||
442 | Object.assign(args[0].data, { serviceId }); | ||
443 | this.actions.todos.handleHostMessage(args[0]); | ||
433 | } | 444 | } |
434 | } | 445 | } |
435 | 446 | ||
@@ -666,6 +677,35 @@ export default class ServicesStore extends Store { | |||
666 | return serviceData; | 677 | return serviceData; |
667 | } | 678 | } |
668 | 679 | ||
680 | _restrictServiceAccess() { | ||
681 | const { features } = this.stores.features; | ||
682 | const { userHasReachedServiceLimit, serviceLimit } = this.stores.serviceLimit; | ||
683 | |||
684 | this.all.map((service, index) => { | ||
685 | if (userHasReachedServiceLimit) { | ||
686 | service.isServiceAccessRestricted = index >= serviceLimit; | ||
687 | |||
688 | if (service.isServiceAccessRestricted) { | ||
689 | service.restrictionType = RESTRICTION_TYPES.SERVICE_LIMIT; | ||
690 | |||
691 | debug('Restricting access to server due to service limit'); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | if (service.isUsingCustomUrl) { | ||
696 | service.isServiceAccessRestricted = !features.isCustomUrlIncludedInCurrentPlan; | ||
697 | |||
698 | if (service.isServiceAccessRestricted) { | ||
699 | service.restrictionType = RESTRICTION_TYPES.CUSTOM_URL; | ||
700 | |||
701 | debug('Restricting access to server due to custom url'); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | return service; | ||
706 | }); | ||
707 | } | ||
708 | |||
669 | // Helper | 709 | // Helper |
670 | _initializeServiceRecipeInWebview(serviceId) { | 710 | _initializeServiceRecipeInWebview(serviceId) { |
671 | const service = this.one(serviceId); | 711 | const service = this.one(serviceId); |
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index d813e97b1..e1d9672b6 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -2,11 +2,15 @@ import { observable, computed, action } from 'mobx'; | |||
2 | import moment from 'moment'; | 2 | import moment from 'moment'; |
3 | import jwt from 'jsonwebtoken'; | 3 | import jwt from 'jsonwebtoken'; |
4 | import localStorage from 'mobx-localstorage'; | 4 | import localStorage from 'mobx-localstorage'; |
5 | import ms from 'ms'; | ||
5 | 6 | ||
6 | import { isDevMode } from '../environment'; | 7 | import { isDevMode } from '../environment'; |
7 | import Store from './lib/Store'; | 8 | import Store from './lib/Store'; |
8 | import Request from './lib/Request'; | 9 | import Request from './lib/Request'; |
9 | import CachedRequest from './lib/CachedRequest'; | 10 | import CachedRequest from './lib/CachedRequest'; |
11 | import { sleep } from '../helpers/async-helpers'; | ||
12 | import { getPlan } from '../helpers/plan-helpers'; | ||
13 | import { PLANS } from '../config'; | ||
10 | 14 | ||
11 | const debug = require('debug')('Franz:UserStore'); | 15 | const debug = require('debug')('Franz:UserStore'); |
12 | 16 | ||
@@ -36,6 +40,8 @@ export default class UserStore extends Store { | |||
36 | 40 | ||
37 | @observable passwordRequest = new Request(this.api.user, 'password'); | 41 | @observable passwordRequest = new Request(this.api.user, 'password'); |
38 | 42 | ||
43 | @observable activateTrialRequest = new Request(this.api.user, 'activateTrial'); | ||
44 | |||
39 | @observable inviteRequest = new Request(this.api.user, 'invite'); | 45 | @observable inviteRequest = new Request(this.api.user, 'invite'); |
40 | 46 | ||
41 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); | 47 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); |
@@ -56,7 +62,9 @@ export default class UserStore extends Store { | |||
56 | 62 | ||
57 | @observable accountType; | 63 | @observable accountType; |
58 | 64 | ||
59 | @observable hasCompletedSignup = null; | 65 | @observable hasCompletedSignup = false; |
66 | |||
67 | @observable hasActivatedTrial = false; | ||
60 | 68 | ||
61 | @observable userData = {}; | 69 | @observable userData = {}; |
62 | 70 | ||
@@ -76,6 +84,7 @@ export default class UserStore extends Store { | |||
76 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); | 84 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); |
77 | this.actions.user.logout.listen(this._logout.bind(this)); | 85 | this.actions.user.logout.listen(this._logout.bind(this)); |
78 | this.actions.user.signup.listen(this._signup.bind(this)); | 86 | this.actions.user.signup.listen(this._signup.bind(this)); |
87 | this.actions.user.activateTrial.listen(this._activateTrial.bind(this)); | ||
79 | this.actions.user.invite.listen(this._invite.bind(this)); | 88 | this.actions.user.invite.listen(this._invite.bind(this)); |
80 | this.actions.user.update.listen(this._update.bind(this)); | 89 | this.actions.user.update.listen(this._update.bind(this)); |
81 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); | 90 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); |
@@ -86,6 +95,7 @@ export default class UserStore extends Store { | |||
86 | this.registerReactions([ | 95 | this.registerReactions([ |
87 | // this._requireAuthenticatedUser, | 96 | // this._requireAuthenticatedUser, |
88 | this._getUserData.bind(this), | 97 | this._getUserData.bind(this), |
98 | this._resetTrialActivationState.bind(this), | ||
89 | ]); | 99 | ]); |
90 | } | 100 | } |
91 | 101 | ||
@@ -141,10 +151,34 @@ export default class UserStore extends Store { | |||
141 | return this.getUserInfoRequest.execute().result || {}; | 151 | return this.getUserInfoRequest.execute().result || {}; |
142 | } | 152 | } |
143 | 153 | ||
154 | @computed get team() { | ||
155 | return this.data.team || null; | ||
156 | } | ||
157 | |||
144 | @computed get isPremium() { | 158 | @computed get isPremium() { |
145 | return !!this.data.isPremium; | 159 | return !!this.data.isPremium; |
146 | } | 160 | } |
147 | 161 | ||
162 | @computed get isPremiumOverride() { | ||
163 | return ((!this.team || !this.team.plan) && this.isPremium) || (this.team.state === 'expired' && this.isPremium); | ||
164 | } | ||
165 | |||
166 | @computed get isPersonal() { | ||
167 | if (!this.team || !this.team.plan) return false; | ||
168 | const plan = getPlan(this.team.plan); | ||
169 | |||
170 | return plan === PLANS.PERSONAL; | ||
171 | } | ||
172 | |||
173 | @computed get isPro() { | ||
174 | if (this.isPremiumOverride) return true; | ||
175 | |||
176 | if (!this.team || (!this.team.plan || this.team.state === 'expired')) return false; | ||
177 | const plan = getPlan(this.team.plan); | ||
178 | |||
179 | return plan === PLANS.PRO || plan === PLANS.LEGACY; | ||
180 | } | ||
181 | |||
148 | @computed get legacyServices() { | 182 | @computed get legacyServices() { |
149 | return this.getLegacyServicesRequest.execute() || {}; | 183 | return this.getLegacyServicesRequest.execute() || {}; |
150 | } | 184 | } |
@@ -190,6 +224,21 @@ export default class UserStore extends Store { | |||
190 | this.actionStatus = request.result.status || []; | 224 | this.actionStatus = request.result.status || []; |
191 | } | 225 | } |
192 | 226 | ||
227 | @action async _activateTrial({ planId }) { | ||
228 | debug('activate trial', planId); | ||
229 | |||
230 | this.activateTrialRequest.execute({ | ||
231 | plan: planId, | ||
232 | }); | ||
233 | |||
234 | await this.activateTrialRequest._promise; | ||
235 | |||
236 | this.hasActivatedTrial = true; | ||
237 | |||
238 | this.stores.features.featuresRequest.invalidate({ immediately: true }); | ||
239 | this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); | ||
240 | } | ||
241 | |||
193 | @action async _invite({ invites }) { | 242 | @action async _invite({ invites }) { |
194 | const data = invites.filter(invite => invite.email !== ''); | 243 | const data = invites.filter(invite => invite.email !== ''); |
195 | 244 | ||
@@ -305,6 +354,14 @@ export default class UserStore extends Store { | |||
305 | } | 354 | } |
306 | } | 355 | } |
307 | 356 | ||
357 | async _resetTrialActivationState() { | ||
358 | if (this.hasActivatedTrial) { | ||
359 | await sleep(ms('12s')); | ||
360 | |||
361 | this.hasActivatedTrial = false; | ||
362 | } | ||
363 | } | ||
364 | |||
308 | // Helpers | 365 | // Helpers |
309 | _parseToken(authToken) { | 366 | _parseToken(authToken) { |
310 | try { | 367 | try { |
@@ -334,6 +391,15 @@ export default class UserStore extends Store { | |||
334 | } | 391 | } |
335 | } | 392 | } |
336 | 393 | ||
394 | getAuthURL(url) { | ||
395 | const parsedUrl = new URL(url); | ||
396 | const params = new URLSearchParams(parsedUrl.search.slice(1)); | ||
397 | |||
398 | params.append('authToken', this.authToken); | ||
399 | |||
400 | return `${parsedUrl.origin}${parsedUrl.pathname}?${params.toString()}`; | ||
401 | } | ||
402 | |||
337 | async _migrateUserLocale() { | 403 | async _migrateUserLocale() { |
338 | await this.getUserInfoRequest._promise; | 404 | await this.getUserInfoRequest._promise; |
339 | 405 | ||
diff --git a/src/stores/index.js b/src/stores/index.js index 1912418a2..10dd56665 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -12,6 +12,9 @@ import RequestStore from './RequestStore'; | |||
12 | import GlobalErrorStore from './GlobalErrorStore'; | 12 | import GlobalErrorStore from './GlobalErrorStore'; |
13 | import { workspaceStore } from '../features/workspaces'; | 13 | import { workspaceStore } from '../features/workspaces'; |
14 | import { announcementsStore } from '../features/announcements'; | 14 | import { announcementsStore } from '../features/announcements'; |
15 | import { serviceLimitStore } from '../features/serviceLimit'; | ||
16 | import { communityRecipesStore } from '../features/communityRecipes'; | ||
17 | import { todosStore } from '../features/todos'; | ||
15 | 18 | ||
16 | export default (api, actions, router) => { | 19 | export default (api, actions, router) => { |
17 | const stores = {}; | 20 | const stores = {}; |
@@ -31,6 +34,9 @@ export default (api, actions, router) => { | |||
31 | globalError: new GlobalErrorStore(stores, api, actions), | 34 | globalError: new GlobalErrorStore(stores, api, actions), |
32 | workspaces: workspaceStore, | 35 | workspaces: workspaceStore, |
33 | announcements: announcementsStore, | 36 | announcements: announcementsStore, |
37 | serviceLimit: serviceLimitStore, | ||
38 | communityRecipes: communityRecipesStore, | ||
39 | todos: todosStore, | ||
34 | }); | 40 | }); |
35 | // Initialize all stores | 41 | // Initialize all stores |
36 | Object.keys(stores).forEach((name) => { | 42 | Object.keys(stores).forEach((name) => { |