diff options
Diffstat (limited to 'src/stores')
-rw-r--r-- | src/stores/AppStore.js | 2 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 4 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 39 | ||||
-rw-r--r-- | src/stores/UserStore.js | 47 | ||||
-rw-r--r-- | src/stores/index.js | 4 |
5 files changed, 93 insertions, 3 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 2ac306a2a..6054e6721 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -357,6 +357,8 @@ export default class AppStore extends Store { | |||
357 | this.locale = this._getDefaultLocale(); | 357 | this.locale = this._getDefaultLocale(); |
358 | } | 358 | } |
359 | 359 | ||
360 | moment.locale(this.locale); | ||
361 | |||
360 | debug(`Set locale to "${this.locale}"`); | 362 | debug(`Set locale to "${this.locale}"`); |
361 | } | 363 | } |
362 | 364 | ||
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 35a050c67..cf28b6bec 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -16,6 +16,8 @@ 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'; | ||
19 | import todos from '../features/todos'; | 21 | import todos from '../features/todos'; |
20 | 22 | ||
21 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 23 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
@@ -76,6 +78,8 @@ export default class FeaturesStore extends Store { | |||
76 | shareFranz(this.stores, this.actions); | 78 | shareFranz(this.stores, this.actions); |
77 | announcements(this.stores, this.actions); | 79 | announcements(this.stores, this.actions); |
78 | settingsWS(this.stores, this.actions); | 80 | settingsWS(this.stores, this.actions); |
81 | serviceLimit(this.stores, this.actions); | ||
82 | communityRecipes(this.stores, this.actions); | ||
79 | todos(this.stores, this.actions); | 83 | todos(this.stores, this.actions); |
80 | } | 84 | } |
81 | } | 85 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index b13425249..2fc543192 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -13,6 +13,8 @@ import CachedRequest from './lib/CachedRequest'; | |||
13 | import { matchRoute } from '../helpers/routing-helpers'; | 13 | import { matchRoute } from '../helpers/routing-helpers'; |
14 | import { gaEvent, statsEvent } from '../lib/analytics'; | 14 | import { gaEvent, statsEvent } from '../lib/analytics'; |
15 | import { workspaceStore } from '../features/workspaces'; | 15 | import { workspaceStore } from '../features/workspaces'; |
16 | import { serviceLimitStore } from '../features/serviceLimit'; | ||
17 | import { RESTRICTION_TYPES } from '../models/Service'; | ||
16 | 18 | ||
17 | const debug = require('debug')('Franz:ServiceStore'); | 19 | const debug = require('debug')('Franz:ServiceStore'); |
18 | 20 | ||
@@ -75,6 +77,7 @@ export default class ServicesStore extends Store { | |||
75 | this._saveActiveService.bind(this), | 77 | this._saveActiveService.bind(this), |
76 | this._logoutReaction.bind(this), | 78 | this._logoutReaction.bind(this), |
77 | this._handleMuteSettings.bind(this), | 79 | this._handleMuteSettings.bind(this), |
80 | this._restrictServiceAccess.bind(this), | ||
78 | ]); | 81 | ]); |
79 | 82 | ||
80 | // Just bind this | 83 | // Just bind this |
@@ -98,7 +101,10 @@ export default class ServicesStore extends Store { | |||
98 | if (this.stores.user.isLoggedIn) { | 101 | if (this.stores.user.isLoggedIn) { |
99 | const services = this.allServicesRequest.execute().result; | 102 | const services = this.allServicesRequest.execute().result; |
100 | if (services) { | 103 | if (services) { |
101 | return observable(services.slice().slice().sort((a, b) => a.order - b.order)); | 104 | return observable(services.slice().slice().sort((a, b) => a.order - b.order).map((s, index) => { |
105 | s.index = index; | ||
106 | return s; | ||
107 | })); | ||
102 | } | 108 | } |
103 | } | 109 | } |
104 | return []; | 110 | return []; |
@@ -153,6 +159,8 @@ export default class ServicesStore extends Store { | |||
153 | 159 | ||
154 | // Actions | 160 | // Actions |
155 | @action async _createService({ recipeId, serviceData, redirect = true }) { | 161 | @action async _createService({ recipeId, serviceData, redirect = true }) { |
162 | if (serviceLimitStore.userHasReachedServiceLimit) return; | ||
163 | |||
156 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | 164 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); |
157 | 165 | ||
158 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; | 166 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; |
@@ -681,6 +689,35 @@ export default class ServicesStore extends Store { | |||
681 | return serviceData; | 689 | return serviceData; |
682 | } | 690 | } |
683 | 691 | ||
692 | _restrictServiceAccess() { | ||
693 | const { features } = this.stores.features; | ||
694 | const { userHasReachedServiceLimit, serviceLimit } = this.stores.serviceLimit; | ||
695 | |||
696 | this.all.map((service, index) => { | ||
697 | if (userHasReachedServiceLimit) { | ||
698 | service.isServiceAccessRestricted = index >= serviceLimit; | ||
699 | |||
700 | if (service.isServiceAccessRestricted) { | ||
701 | service.restrictionType = RESTRICTION_TYPES.SERVICE_LIMIT; | ||
702 | |||
703 | debug('Restricting access to server due to service limit'); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | if (service.isUsingCustomUrl) { | ||
708 | service.isServiceAccessRestricted = !features.isCustomUrlIncludedInCurrentPlan; | ||
709 | |||
710 | if (service.isServiceAccessRestricted) { | ||
711 | service.restrictionType = RESTRICTION_TYPES.CUSTOM_URL; | ||
712 | |||
713 | debug('Restricting access to server due to custom url'); | ||
714 | } | ||
715 | } | ||
716 | |||
717 | return service; | ||
718 | }); | ||
719 | } | ||
720 | |||
684 | // Helper | 721 | // Helper |
685 | _initializeServiceRecipeInWebview(serviceId) { | 722 | _initializeServiceRecipeInWebview(serviceId) { |
686 | const service = this.one(serviceId); | 723 | const service = this.one(serviceId); |
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index b5423af3b..e23106462 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -2,12 +2,14 @@ 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, WEBSITE } 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'; |
10 | import { gaEvent } from '../lib/analytics'; | 11 | import { gaEvent } from '../lib/analytics'; |
12 | import { sleep } from '../helpers/async-helpers'; | ||
11 | 13 | ||
12 | const debug = require('debug')('Franz:UserStore'); | 14 | const debug = require('debug')('Franz:UserStore'); |
13 | 15 | ||
@@ -37,6 +39,8 @@ export default class UserStore extends Store { | |||
37 | 39 | ||
38 | @observable passwordRequest = new Request(this.api.user, 'password'); | 40 | @observable passwordRequest = new Request(this.api.user, 'password'); |
39 | 41 | ||
42 | @observable activateTrialRequest = new Request(this.api.user, 'activateTrial'); | ||
43 | |||
40 | @observable inviteRequest = new Request(this.api.user, 'invite'); | 44 | @observable inviteRequest = new Request(this.api.user, 'invite'); |
41 | 45 | ||
42 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); | 46 | @observable getUserInfoRequest = new CachedRequest(this.api.user, 'getInfo'); |
@@ -57,7 +61,9 @@ export default class UserStore extends Store { | |||
57 | 61 | ||
58 | @observable accountType; | 62 | @observable accountType; |
59 | 63 | ||
60 | @observable hasCompletedSignup = null; | 64 | @observable hasCompletedSignup = false; |
65 | |||
66 | @observable hasActivatedTrial = false; | ||
61 | 67 | ||
62 | @observable userData = {}; | 68 | @observable userData = {}; |
63 | 69 | ||
@@ -77,6 +83,7 @@ export default class UserStore extends Store { | |||
77 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); | 83 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); |
78 | this.actions.user.logout.listen(this._logout.bind(this)); | 84 | this.actions.user.logout.listen(this._logout.bind(this)); |
79 | this.actions.user.signup.listen(this._signup.bind(this)); | 85 | this.actions.user.signup.listen(this._signup.bind(this)); |
86 | this.actions.user.activateTrial.listen(this._activateTrial.bind(this)); | ||
80 | this.actions.user.invite.listen(this._invite.bind(this)); | 87 | this.actions.user.invite.listen(this._invite.bind(this)); |
81 | this.actions.user.update.listen(this._update.bind(this)); | 88 | this.actions.user.update.listen(this._update.bind(this)); |
82 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); | 89 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); |
@@ -87,6 +94,7 @@ export default class UserStore extends Store { | |||
87 | this.registerReactions([ | 94 | this.registerReactions([ |
88 | this._requireAuthenticatedUser, | 95 | this._requireAuthenticatedUser, |
89 | this._getUserData.bind(this), | 96 | this._getUserData.bind(this), |
97 | this._resetTrialActivationState.bind(this), | ||
90 | ]); | 98 | ]); |
91 | } | 99 | } |
92 | 100 | ||
@@ -199,6 +207,24 @@ export default class UserStore extends Store { | |||
199 | gaEvent('User', 'retrievePassword'); | 207 | gaEvent('User', 'retrievePassword'); |
200 | } | 208 | } |
201 | 209 | ||
210 | @action async _activateTrial({ planId }) { | ||
211 | debug('activate trial', planId); | ||
212 | |||
213 | this.activateTrialRequest.execute({ | ||
214 | plan: planId, | ||
215 | }); | ||
216 | |||
217 | await this.activateTrialRequest._promise; | ||
218 | |||
219 | this.hasActivatedTrial = true; | ||
220 | |||
221 | this.stores.features.featuresRequest.invalidate({ immediately: true }); | ||
222 | this.stores.user.getUserInfoRequest.invalidate({ immediately: true }); | ||
223 | |||
224 | |||
225 | gaEvent('User', 'activateTrial'); | ||
226 | } | ||
227 | |||
202 | @action async _invite({ invites }) { | 228 | @action async _invite({ invites }) { |
203 | const data = invites.filter(invite => invite.email !== ''); | 229 | const data = invites.filter(invite => invite.email !== ''); |
204 | 230 | ||
@@ -318,6 +344,14 @@ export default class UserStore extends Store { | |||
318 | } | 344 | } |
319 | } | 345 | } |
320 | 346 | ||
347 | async _resetTrialActivationState() { | ||
348 | if (this.hasActivatedTrial) { | ||
349 | await sleep(ms('12s')); | ||
350 | |||
351 | this.hasActivatedTrial = false; | ||
352 | } | ||
353 | } | ||
354 | |||
321 | // Helpers | 355 | // Helpers |
322 | _parseToken(authToken) { | 356 | _parseToken(authToken) { |
323 | try { | 357 | try { |
@@ -347,6 +381,15 @@ export default class UserStore extends Store { | |||
347 | } | 381 | } |
348 | } | 382 | } |
349 | 383 | ||
384 | getAuthURL(url) { | ||
385 | const parsedUrl = new URL(url); | ||
386 | const params = new URLSearchParams(parsedUrl.search.slice(1)); | ||
387 | |||
388 | params.append('authToken', this.authToken); | ||
389 | |||
390 | return `${parsedUrl.origin}${parsedUrl.pathname}?${params.toString()}`; | ||
391 | } | ||
392 | |||
350 | async _migrateUserLocale() { | 393 | async _migrateUserLocale() { |
351 | await this.getUserInfoRequest._promise; | 394 | await this.getUserInfoRequest._promise; |
352 | 395 | ||
diff --git a/src/stores/index.js b/src/stores/index.js index e9ef523f8..10dd56665 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -12,6 +12,8 @@ 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'; | ||
15 | import { todosStore } from '../features/todos'; | 17 | import { todosStore } from '../features/todos'; |
16 | 18 | ||
17 | export default (api, actions, router) => { | 19 | export default (api, actions, router) => { |
@@ -32,6 +34,8 @@ export default (api, actions, router) => { | |||
32 | globalError: new GlobalErrorStore(stores, api, actions), | 34 | globalError: new GlobalErrorStore(stores, api, actions), |
33 | workspaces: workspaceStore, | 35 | workspaces: workspaceStore, |
34 | announcements: announcementsStore, | 36 | announcements: announcementsStore, |
37 | serviceLimit: serviceLimitStore, | ||
38 | communityRecipes: communityRecipesStore, | ||
35 | todos: todosStore, | 39 | todos: todosStore, |
36 | }); | 40 | }); |
37 | // Initialize all stores | 41 | // Initialize all stores |