diff options
author | 2019-09-07 15:50:23 +0200 | |
---|---|---|
committer | 2019-09-07 15:50:23 +0200 | |
commit | e7a74514c1e7c3833dfdcf5900cb87f9e6e8354e (patch) | |
tree | b8314e4155503b135dcb07e8b4a0e847e25c19cf /src/containers | |
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/containers')
-rw-r--r-- | src/containers/auth/PricingScreen.js | 40 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 6 | ||||
-rw-r--r-- | src/containers/settings/AccountScreen.js | 5 | ||||
-rw-r--r-- | src/containers/settings/EditServiceScreen.js | 4 | ||||
-rw-r--r-- | src/containers/settings/EditSettingsScreen.js | 47 | ||||
-rw-r--r-- | src/containers/settings/RecipesScreen.js | 40 | ||||
-rw-r--r-- | src/containers/settings/TeamScreen.js | 2 | ||||
-rw-r--r-- | src/containers/subscription/SubscriptionFormScreen.js | 99 | ||||
-rw-r--r-- | src/containers/subscription/SubscriptionPopupScreen.js | 3 |
9 files changed, 146 insertions, 100 deletions
diff --git a/src/containers/auth/PricingScreen.js b/src/containers/auth/PricingScreen.js index 8d179a170..af1651931 100644 --- a/src/containers/auth/PricingScreen.js +++ b/src/containers/auth/PricingScreen.js | |||
@@ -5,7 +5,6 @@ import { RouterStore } from 'mobx-react-router'; | |||
5 | 5 | ||
6 | import Pricing from '../../components/auth/Pricing'; | 6 | import Pricing from '../../components/auth/Pricing'; |
7 | import UserStore from '../../stores/UserStore'; | 7 | import UserStore from '../../stores/UserStore'; |
8 | import PaymentStore from '../../stores/PaymentStore'; | ||
9 | 8 | ||
10 | import { globalError as globalErrorPropType } from '../../prop-types'; | 9 | import { globalError as globalErrorPropType } from '../../prop-types'; |
11 | 10 | ||
@@ -14,20 +13,40 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend | |||
14 | error: globalErrorPropType.isRequired, | 13 | error: globalErrorPropType.isRequired, |
15 | }; | 14 | }; |
16 | 15 | ||
16 | async submit() { | ||
17 | const { | ||
18 | actions, | ||
19 | stores, | ||
20 | } = this.props; | ||
21 | |||
22 | const { activateTrialRequest } = stores.user; | ||
23 | const { defaultTrialPlan } = stores.features.features; | ||
24 | |||
25 | actions.user.activateTrial({ planId: defaultTrialPlan }); | ||
26 | await activateTrialRequest._promise; | ||
27 | |||
28 | if (!activateTrialRequest.isError) { | ||
29 | stores.router.push('/'); | ||
30 | stores.user.hasCompletedSignup = true; | ||
31 | } | ||
32 | } | ||
33 | |||
17 | render() { | 34 | render() { |
18 | const { actions, stores, error } = this.props; | 35 | const { |
36 | error, | ||
37 | stores, | ||
38 | } = this.props; | ||
19 | 39 | ||
20 | const nextStepRoute = stores.user.legacyServices.length ? stores.user.importRoute : stores.user.inviteRoute; | 40 | const { getUserInfoRequest, activateTrialRequest } = stores.user; |
41 | const { featuresRequest } = stores.features; | ||
21 | 42 | ||
22 | return ( | 43 | return ( |
23 | <Pricing | 44 | <Pricing |
24 | donor={stores.user.data.donor || {}} | 45 | onSubmit={this.submit.bind(this)} |
25 | onSubmit={actions.user.signup} | 46 | isLoadingRequiredData={(getUserInfoRequest.isExecuting || !getUserInfoRequest.wasExecuted) || (featuresRequest.isExecuting || !featuresRequest.wasExecuted)} |
26 | onCloseSubscriptionWindow={() => this.props.stores.router.push(nextStepRoute)} | 47 | isActivatingTrial={activateTrialRequest.isExecuting} |
27 | isLoading={stores.payment.plansRequest.isExecuting} | 48 | trialActivationError={activateTrialRequest.isError} |
28 | isLoadingUser={stores.user.getUserInfoRequest.isExecuting} | ||
29 | error={error} | 49 | error={error} |
30 | skipAction={() => this.props.stores.router.push(nextStepRoute)} | ||
31 | /> | 50 | /> |
32 | ); | 51 | ); |
33 | } | 52 | } |
@@ -36,12 +55,11 @@ export default @inject('stores', 'actions') @observer class PricingScreen extend | |||
36 | PricingScreen.wrappedComponent.propTypes = { | 55 | PricingScreen.wrappedComponent.propTypes = { |
37 | actions: PropTypes.shape({ | 56 | actions: PropTypes.shape({ |
38 | user: PropTypes.shape({ | 57 | user: PropTypes.shape({ |
39 | signup: PropTypes.func.isRequired, | 58 | activateTrial: PropTypes.func.isRequired, |
40 | }).isRequired, | 59 | }).isRequired, |
41 | }).isRequired, | 60 | }).isRequired, |
42 | stores: PropTypes.shape({ | 61 | stores: PropTypes.shape({ |
43 | user: PropTypes.instanceOf(UserStore).isRequired, | 62 | user: PropTypes.instanceOf(UserStore).isRequired, |
44 | payment: PropTypes.instanceOf(PaymentStore).isRequired, | ||
45 | router: PropTypes.instanceOf(RouterStore).isRequired, | 63 | router: PropTypes.instanceOf(RouterStore).isRequired, |
46 | }).isRequired, | 64 | }).isRequired, |
47 | }; | 65 | }; |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 38ed85986..95fbd109f 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -10,6 +10,7 @@ import FeaturesStore from '../../stores/FeaturesStore'; | |||
10 | import UIStore from '../../stores/UIStore'; | 10 | import UIStore from '../../stores/UIStore'; |
11 | import NewsStore from '../../stores/NewsStore'; | 11 | import NewsStore from '../../stores/NewsStore'; |
12 | import SettingsStore from '../../stores/SettingsStore'; | 12 | import SettingsStore from '../../stores/SettingsStore'; |
13 | import UserStore from '../../stores/UserStore'; | ||
13 | import RequestStore from '../../stores/RequestStore'; | 14 | import RequestStore from '../../stores/RequestStore'; |
14 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; | 15 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; |
15 | 16 | ||
@@ -39,6 +40,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
39 | settings, | 40 | settings, |
40 | globalError, | 41 | globalError, |
41 | requests, | 42 | requests, |
43 | user, | ||
42 | } = this.props.stores; | 44 | } = this.props.stores; |
43 | 45 | ||
44 | const { | 46 | const { |
@@ -125,6 +127,8 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
125 | reload={reload} | 127 | reload={reload} |
126 | openSettings={openSettings} | 128 | openSettings={openSettings} |
127 | update={updateService} | 129 | update={updateService} |
130 | userHasCompletedSignup={user.hasCompletedSignup} | ||
131 | hasActivatedTrial={user.hasActivatedTrial} | ||
128 | /> | 132 | /> |
129 | ); | 133 | ); |
130 | 134 | ||
@@ -150,6 +154,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
150 | retryRequiredRequests={retryRequiredRequests} | 154 | retryRequiredRequests={retryRequiredRequests} |
151 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} | 155 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} |
152 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} | 156 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} |
157 | hasActivatedTrial={user.hasActivatedTrial} | ||
153 | > | 158 | > |
154 | {React.Children.count(children) > 0 ? children : null} | 159 | {React.Children.count(children) > 0 ? children : null} |
155 | </AppLayout> | 160 | </AppLayout> |
@@ -167,6 +172,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { | |||
167 | ui: PropTypes.instanceOf(UIStore).isRequired, | 172 | ui: PropTypes.instanceOf(UIStore).isRequired, |
168 | news: PropTypes.instanceOf(NewsStore).isRequired, | 173 | news: PropTypes.instanceOf(NewsStore).isRequired, |
169 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | 174 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
175 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
170 | requests: PropTypes.instanceOf(RequestStore).isRequired, | 176 | requests: PropTypes.instanceOf(RequestStore).isRequired, |
171 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, | 177 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, |
172 | }).isRequired, | 178 | }).isRequired, |
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index fd3317301..41cdeb79a 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js | |||
@@ -30,7 +30,7 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend | |||
30 | 30 | ||
31 | let url; | 31 | let url; |
32 | if (api === 'https://api.franzinfra.com') { | 32 | if (api === 'https://api.franzinfra.com') { |
33 | url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; | 33 | url = stores.user.getAuthURL(`${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`); |
34 | } else { | 34 | } else { |
35 | url = `${api}${route}`; | 35 | url = `${api}${route}`; |
36 | } | 36 | } |
@@ -49,6 +49,8 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend | |||
49 | <ErrorBoundary> | 49 | <ErrorBoundary> |
50 | <AccountDashboard | 50 | <AccountDashboard |
51 | user={user.data} | 51 | user={user.data} |
52 | isPremiumOverrideUser={user.isPremiumOverride} | ||
53 | isProUser={user.isPro} | ||
52 | isLoading={isLoadingUserInfo} | 54 | isLoading={isLoadingUserInfo} |
53 | isLoadingPlans={isLoadingPlans} | 55 | isLoadingPlans={isLoadingPlans} |
54 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | 56 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} |
@@ -58,6 +60,7 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend | |||
58 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} | 60 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} |
59 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} | 61 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} |
60 | openEditAccount={() => this.handleWebsiteLink('/user/profile')} | 62 | openEditAccount={() => this.handleWebsiteLink('/user/profile')} |
63 | upgradeToPro={() => this.handleWebsiteLink('/inapp/user/licenses')} | ||
61 | openBilling={() => this.handleWebsiteLink('/user/billing')} | 64 | openBilling={() => this.handleWebsiteLink('/user/billing')} |
62 | openInvoices={() => this.handleWebsiteLink('/user/invoices')} | 65 | openInvoices={() => this.handleWebsiteLink('/user/invoices')} |
63 | /> | 66 | /> |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index 870ca4ecd..e4ff03bb3 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js | |||
@@ -330,8 +330,8 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex | |||
330 | onSubmit={d => this.onSubmit(d)} | 330 | onSubmit={d => this.onSubmit(d)} |
331 | onDelete={() => this.deleteService()} | 331 | onDelete={() => this.deleteService()} |
332 | isProxyFeatureEnabled={proxyFeature.isEnabled} | 332 | isProxyFeatureEnabled={proxyFeature.isEnabled} |
333 | isProxyPremiumFeature={proxyFeature.isPremium} | 333 | isServiceProxyIncludedInCurrentPlan={proxyFeature.isIncludedInCurrentPlan} |
334 | isSpellcheckerPremiumFeature={spellcheckerFeature.isPremium} | 334 | isSpellcheckerIncludedInCurrentPlan={spellcheckerFeature.isIncludedInCurrentPlan} |
335 | /> | 335 | /> |
336 | </ErrorBoundary> | 336 | </ErrorBoundary> |
337 | ); | 337 | ); |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 38f73c20f..954f64dc6 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -6,6 +6,7 @@ import { defineMessages, intlShape } from 'react-intl'; | |||
6 | import AppStore from '../../stores/AppStore'; | 6 | import AppStore from '../../stores/AppStore'; |
7 | import SettingsStore from '../../stores/SettingsStore'; | 7 | import SettingsStore from '../../stores/SettingsStore'; |
8 | import UserStore from '../../stores/UserStore'; | 8 | import UserStore from '../../stores/UserStore'; |
9 | import TodosStore from '../../features/todos/store'; | ||
9 | import Form from '../../lib/Form'; | 10 | import Form from '../../lib/Form'; |
10 | import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; | 11 | import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; |
11 | import { DEFAULT_APP_SETTINGS } from '../../config'; | 12 | import { DEFAULT_APP_SETTINGS } from '../../config'; |
@@ -19,6 +20,7 @@ import ErrorBoundary from '../../components/util/ErrorBoundary'; | |||
19 | import { API } from '../../environment'; | 20 | import { API } from '../../environment'; |
20 | 21 | ||
21 | import globalMessages from '../../i18n/globalMessages'; | 22 | import globalMessages from '../../i18n/globalMessages'; |
23 | import { DEFAULT_IS_FEATURE_ENABLED_BY_USER } from '../../features/todos'; | ||
22 | 24 | ||
23 | const messages = defineMessages({ | 25 | const messages = defineMessages({ |
24 | autoLaunchOnStart: { | 26 | autoLaunchOnStart: { |
@@ -73,6 +75,10 @@ const messages = defineMessages({ | |||
73 | id: 'settings.app.form.beta', | 75 | id: 'settings.app.form.beta', |
74 | defaultMessage: '!!!Include beta versions', | 76 | defaultMessage: '!!!Include beta versions', |
75 | }, | 77 | }, |
78 | enableTodos: { | ||
79 | id: 'settings.app.form.enableTodos', | ||
80 | defaultMessage: '!!!Enable Franz Todos', | ||
81 | }, | ||
76 | }); | 82 | }); |
77 | 83 | ||
78 | export default @inject('stores', 'actions') @observer class EditSettingsScreen extends Component { | 84 | export default @inject('stores', 'actions') @observer class EditSettingsScreen extends Component { |
@@ -81,7 +87,13 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
81 | }; | 87 | }; |
82 | 88 | ||
83 | onSubmit(settingsData) { | 89 | onSubmit(settingsData) { |
84 | const { app, settings, user } = this.props.actions; | 90 | const { todos } = this.props.stores; |
91 | const { | ||
92 | app, | ||
93 | settings, | ||
94 | user, | ||
95 | todos: todosActions, | ||
96 | } = this.props.actions; | ||
85 | 97 | ||
86 | app.launchOnStartup({ | 98 | app.launchOnStartup({ |
87 | enable: settingsData.autoLaunchOnStart, | 99 | enable: settingsData.autoLaunchOnStart, |
@@ -112,10 +124,16 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
112 | locale: settingsData.locale, | 124 | locale: settingsData.locale, |
113 | }, | 125 | }, |
114 | }); | 126 | }); |
127 | |||
128 | if (todos.isFeatureActive) { | ||
129 | todosActions.toggleTodosFeatureVisibility(); | ||
130 | } | ||
115 | } | 131 | } |
116 | 132 | ||
117 | prepareForm() { | 133 | prepareForm() { |
118 | const { app, settings, user } = this.props.stores; | 134 | const { |
135 | app, settings, user, todos, | ||
136 | } = this.props.stores; | ||
119 | const { intl } = this.context; | 137 | const { intl } = this.context; |
120 | 138 | ||
121 | const locales = getSelectOptions({ | 139 | const locales = getSelectOptions({ |
@@ -171,8 +189,8 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
171 | }, | 189 | }, |
172 | enableSpellchecking: { | 190 | enableSpellchecking: { |
173 | label: intl.formatMessage(messages.enableSpellchecking), | 191 | label: intl.formatMessage(messages.enableSpellchecking), |
174 | value: !this.props.stores.user.data.isPremium && spellcheckerConfig.isPremium ? false : settings.all.app.enableSpellchecking, | 192 | value: !this.props.stores.user.data.isPremium && !spellcheckerConfig.isIncludedInCurrentPlan ? false : settings.all.app.enableSpellchecking, |
175 | default: !this.props.stores.user.data.isPremium && spellcheckerConfig.isPremium ? false : DEFAULT_APP_SETTINGS.enableSpellchecking, | 193 | default: !this.props.stores.user.data.isPremium && !spellcheckerConfig.isIncludedInCurrentPlan ? false : DEFAULT_APP_SETTINGS.enableSpellchecking, |
176 | }, | 194 | }, |
177 | spellcheckerLanguage: { | 195 | spellcheckerLanguage: { |
178 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), | 196 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), |
@@ -204,16 +222,28 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
204 | }, | 222 | }, |
205 | }; | 223 | }; |
206 | 224 | ||
225 | if (todos.isFeatureActive) { | ||
226 | config.fields.enableTodos = { | ||
227 | label: intl.formatMessage(messages.enableTodos), | ||
228 | value: todos.settings.isFeatureEnabledByUser, | ||
229 | default: DEFAULT_IS_FEATURE_ENABLED_BY_USER, | ||
230 | }; | ||
231 | } | ||
232 | |||
207 | return new Form(config); | 233 | return new Form(config); |
208 | } | 234 | } |
209 | 235 | ||
210 | render() { | 236 | render() { |
211 | const { | 237 | const { |
238 | app, | ||
239 | todos, | ||
240 | } = this.props.stores; | ||
241 | const { | ||
212 | updateStatus, | 242 | updateStatus, |
213 | cacheSize, | 243 | cacheSize, |
214 | updateStatusTypes, | 244 | updateStatusTypes, |
215 | isClearingAllCache, | 245 | isClearingAllCache, |
216 | } = this.props.stores.app; | 246 | } = app; |
217 | const { | 247 | const { |
218 | checkForUpdates, | 248 | checkForUpdates, |
219 | installUpdate, | 249 | installUpdate, |
@@ -235,7 +265,8 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e | |||
235 | cacheSize={cacheSize} | 265 | cacheSize={cacheSize} |
236 | isClearingAllCache={isClearingAllCache} | 266 | isClearingAllCache={isClearingAllCache} |
237 | onClearAllCache={clearAllCache} | 267 | onClearAllCache={clearAllCache} |
238 | isSpellcheckerPremiumFeature={spellcheckerConfig.isPremium} | 268 | isSpellcheckerIncludedInCurrentPlan={spellcheckerConfig.isIncludedInCurrentPlan} |
269 | isTodosEnabled={todos.isFeatureActive} | ||
239 | /> | 270 | /> |
240 | </ErrorBoundary> | 271 | </ErrorBoundary> |
241 | ); | 272 | ); |
@@ -247,6 +278,7 @@ EditSettingsScreen.wrappedComponent.propTypes = { | |||
247 | app: PropTypes.instanceOf(AppStore).isRequired, | 278 | app: PropTypes.instanceOf(AppStore).isRequired, |
248 | user: PropTypes.instanceOf(UserStore).isRequired, | 279 | user: PropTypes.instanceOf(UserStore).isRequired, |
249 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | 280 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
281 | todos: PropTypes.instanceOf(TodosStore).isRequired, | ||
250 | }).isRequired, | 282 | }).isRequired, |
251 | actions: PropTypes.shape({ | 283 | actions: PropTypes.shape({ |
252 | app: PropTypes.shape({ | 284 | app: PropTypes.shape({ |
@@ -261,5 +293,8 @@ EditSettingsScreen.wrappedComponent.propTypes = { | |||
261 | user: PropTypes.shape({ | 293 | user: PropTypes.shape({ |
262 | update: PropTypes.func.isRequired, | 294 | update: PropTypes.func.isRequired, |
263 | }).isRequired, | 295 | }).isRequired, |
296 | todos: PropTypes.shape({ | ||
297 | toggleTodosFeatureVisibility: PropTypes.func.isRequired, | ||
298 | }).isRequired, | ||
264 | }).isRequired, | 299 | }).isRequired, |
265 | }; | 300 | }; |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index eda5ae54c..132820b6f 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js | |||
@@ -1,7 +1,9 @@ | |||
1 | import { remote, shell } from 'electron'; | ||
1 | import React, { Component } from 'react'; | 2 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
3 | import { autorun } from 'mobx'; | 4 | import { autorun } from 'mobx'; |
4 | import { inject, observer } from 'mobx-react'; | 5 | import { inject, observer } from 'mobx-react'; |
6 | import path from 'path'; | ||
5 | 7 | ||
6 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | 8 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; |
7 | import RecipeStore from '../../stores/RecipesStore'; | 9 | import RecipeStore from '../../stores/RecipesStore'; |
@@ -10,6 +12,11 @@ import UserStore from '../../stores/UserStore'; | |||
10 | 12 | ||
11 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 13 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
12 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 14 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
15 | import { FRANZ_DEV_DOCS } from '../../config'; | ||
16 | import { gaEvent } from '../../lib/analytics'; | ||
17 | import { communityRecipesStore } from '../../features/communityRecipes'; | ||
18 | |||
19 | const { app } = remote; | ||
13 | 20 | ||
14 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { | 21 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { |
15 | static propTypes = { | 22 | static propTypes = { |
@@ -67,9 +74,16 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
67 | 74 | ||
68 | render() { | 75 | render() { |
69 | const { | 76 | const { |
70 | recipePreviews, recipes, services, user, | 77 | recipePreviews, |
78 | recipes, | ||
79 | services, | ||
80 | user, | ||
71 | } = this.props.stores; | 81 | } = this.props.stores; |
72 | const { showAddServiceInterface } = this.props.actions.service; | 82 | |
83 | const { | ||
84 | app: appActions, | ||
85 | service: serviceActions, | ||
86 | } = this.props.actions; | ||
73 | 87 | ||
74 | const { filter } = this.props.params; | 88 | const { filter } = this.props.params; |
75 | let recipeFilter; | 89 | let recipeFilter; |
@@ -77,7 +91,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
77 | if (filter === 'all') { | 91 | if (filter === 'all') { |
78 | recipeFilter = recipePreviews.all; | 92 | recipeFilter = recipePreviews.all; |
79 | } else if (filter === 'dev') { | 93 | } else if (filter === 'dev') { |
80 | recipeFilter = recipePreviews.dev; | 94 | recipeFilter = communityRecipesStore.communityRecipes; |
81 | } else { | 95 | } else { |
82 | recipeFilter = recipePreviews.featured; | 96 | recipeFilter = recipePreviews.featured; |
83 | } | 97 | } |
@@ -89,6 +103,8 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
89 | || recipes.installRecipeRequest.isExecuting | 103 | || recipes.installRecipeRequest.isExecuting |
90 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 104 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; |
91 | 105 | ||
106 | const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); | ||
107 | |||
92 | return ( | 108 | return ( |
93 | <ErrorBoundary> | 109 | <ErrorBoundary> |
94 | <RecipesDashboard | 110 | <RecipesDashboard |
@@ -97,12 +113,23 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
97 | addedServiceCount={services.all.length} | 113 | addedServiceCount={services.all.length} |
98 | isPremium={user.data.isPremium} | 114 | isPremium={user.data.isPremium} |
99 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} | 115 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} |
100 | showAddServiceInterface={showAddServiceInterface} | 116 | showAddServiceInterface={serviceActions.showAddServiceInterface} |
101 | searchRecipes={e => this.searchRecipes(e)} | 117 | searchRecipes={e => this.searchRecipes(e)} |
102 | resetSearch={() => this.resetSearch()} | 118 | resetSearch={() => this.resetSearch()} |
103 | searchNeedle={this.state.needle} | 119 | searchNeedle={this.state.needle} |
104 | serviceStatus={services.actionStatus} | 120 | serviceStatus={services.actionStatus} |
105 | devRecipesCount={recipePreviews.dev.length} | 121 | recipeFilter={filter} |
122 | recipeDirectory={recipeDirectory} | ||
123 | openRecipeDirectory={() => { | ||
124 | shell.openItem(recipeDirectory); | ||
125 | gaEvent('Recipe', 'open-recipe-folder', 'Open Folder'); | ||
126 | }} | ||
127 | openDevDocs={() => { | ||
128 | appActions.openExternalUrl({ url: FRANZ_DEV_DOCS }); | ||
129 | gaEvent('Recipe', 'open-dev-docs', 'Developer Documentation'); | ||
130 | }} | ||
131 | isCommunityRecipesIncludedInCurrentPlan={communityRecipesStore.isCommunityRecipesIncludedInCurrentPlan} | ||
132 | isUserPremiumUser={user.isPremium} | ||
106 | /> | 133 | /> |
107 | </ErrorBoundary> | 134 | </ErrorBoundary> |
108 | ); | 135 | ); |
@@ -117,6 +144,9 @@ RecipesScreen.wrappedComponent.propTypes = { | |||
117 | user: PropTypes.instanceOf(UserStore).isRequired, | 144 | user: PropTypes.instanceOf(UserStore).isRequired, |
118 | }).isRequired, | 145 | }).isRequired, |
119 | actions: PropTypes.shape({ | 146 | actions: PropTypes.shape({ |
147 | app: PropTypes.shape({ | ||
148 | openExternalUrl: PropTypes.func.isRequired, | ||
149 | }).isRequired, | ||
120 | service: PropTypes.shape({ | 150 | service: PropTypes.shape({ |
121 | showAddServiceInterface: PropTypes.func.isRequired, | 151 | showAddServiceInterface: PropTypes.func.isRequired, |
122 | }).isRequired, | 152 | }).isRequired, |
diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js index c69d5ad08..f600c9947 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.js | |||
@@ -14,7 +14,6 @@ export default @inject('stores', 'actions') @observer class TeamScreen extends C | |||
14 | const { actions, stores } = this.props; | 14 | const { actions, stores } = this.props; |
15 | 15 | ||
16 | const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; | 16 | const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; |
17 | console.log(url); | ||
18 | 17 | ||
19 | actions.app.openExternalUrl({ url }); | 18 | actions.app.openExternalUrl({ url }); |
20 | } | 19 | } |
@@ -31,6 +30,7 @@ export default @inject('stores', 'actions') @observer class TeamScreen extends C | |||
31 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | 30 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} |
32 | retryUserInfoRequest={() => this.reloadData()} | 31 | retryUserInfoRequest={() => this.reloadData()} |
33 | openTeamManagement={() => this.handleWebsiteLink('/user/team')} | 32 | openTeamManagement={() => this.handleWebsiteLink('/user/team')} |
33 | isProUser={user.isPro} | ||
34 | /> | 34 | /> |
35 | </ErrorBoundary> | 35 | </ErrorBoundary> |
36 | ); | 36 | ); |
diff --git a/src/containers/subscription/SubscriptionFormScreen.js b/src/containers/subscription/SubscriptionFormScreen.js index 3d153b8e8..726b10628 100644 --- a/src/containers/subscription/SubscriptionFormScreen.js +++ b/src/containers/subscription/SubscriptionFormScreen.js | |||
@@ -1,4 +1,3 @@ | |||
1 | import { remote } from 'electron'; | ||
2 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
3 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
4 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
@@ -6,96 +5,50 @@ import { inject, observer } from 'mobx-react'; | |||
6 | import PaymentStore from '../../stores/PaymentStore'; | 5 | import PaymentStore from '../../stores/PaymentStore'; |
7 | 6 | ||
8 | import SubscriptionForm from '../../components/subscription/SubscriptionForm'; | 7 | import SubscriptionForm from '../../components/subscription/SubscriptionForm'; |
9 | 8 | import TrialForm from '../../components/subscription/TrialForm'; | |
10 | const { BrowserWindow } = remote; | ||
11 | 9 | ||
12 | export default @inject('stores', 'actions') @observer class SubscriptionFormScreen extends Component { | 10 | export default @inject('stores', 'actions') @observer class SubscriptionFormScreen extends Component { |
13 | static propTypes = { | 11 | async openBrowser() { |
14 | onCloseWindow: PropTypes.func, | ||
15 | content: PropTypes.node, | ||
16 | showSkipOption: PropTypes.bool, | ||
17 | skipAction: PropTypes.func, | ||
18 | skipButtonLabel: PropTypes.string, | ||
19 | hideInfo: PropTypes.bool, | ||
20 | } | ||
21 | |||
22 | static defaultProps = { | ||
23 | onCloseWindow: () => null, | ||
24 | content: '', | ||
25 | showSkipOption: false, | ||
26 | skipAction: () => null, | ||
27 | skipButtonLabel: '', | ||
28 | hideInfo: false, | ||
29 | } | ||
30 | |||
31 | async handlePayment(plan) { | ||
32 | const { | 12 | const { |
33 | actions, | 13 | actions, |
34 | stores, | 14 | stores, |
35 | onCloseWindow, | ||
36 | } = this.props; | 15 | } = this.props; |
37 | 16 | ||
38 | const interval = plan; | 17 | const { |
39 | 18 | user, | |
40 | const { id } = stores.payment.plan[interval]; | 19 | features, |
41 | actions.payment.createHostedPage({ | 20 | } = stores; |
42 | planId: id, | ||
43 | }); | ||
44 | |||
45 | const hostedPage = await stores.payment.createHostedPageRequest; | ||
46 | 21 | ||
47 | if (hostedPage.url) { | 22 | let hostedPageURL = features.features.planSelectionURL; |
48 | if (hostedPage.legacyCheckoutFlow) { | 23 | hostedPageURL = user.getAuthURL(hostedPageURL); |
49 | const paymentWindow = new BrowserWindow({ | ||
50 | parent: remote.getCurrentWindow(), | ||
51 | modal: true, | ||
52 | title: '🔒 Ferdi Supporter License', | ||
53 | width: 600, | ||
54 | height: window.innerHeight - 100, | ||
55 | maxWidth: 600, | ||
56 | minWidth: 600, | ||
57 | webPreferences: { | ||
58 | nodeIntegration: true, | ||
59 | webviewTag: true, | ||
60 | }, | ||
61 | }); | ||
62 | paymentWindow.loadURL(`file://${__dirname}/../../index.html#/payment/${encodeURIComponent(hostedPage.url)}`); | ||
63 | 24 | ||
64 | paymentWindow.on('closed', () => { | 25 | actions.app.openExternalUrl({ url: hostedPageURL }); |
65 | onCloseWindow(); | ||
66 | }); | ||
67 | } else { | ||
68 | actions.app.openExternalUrl({ | ||
69 | url: hostedPage.url, | ||
70 | }); | ||
71 | } | ||
72 | } | ||
73 | } | 26 | } |
74 | 27 | ||
75 | render() { | 28 | render() { |
76 | const { | 29 | const { |
77 | content, | ||
78 | actions, | 30 | actions, |
79 | stores, | 31 | stores, |
80 | showSkipOption, | ||
81 | skipAction, | ||
82 | skipButtonLabel, | ||
83 | hideInfo, | ||
84 | } = this.props; | 32 | } = this.props; |
33 | |||
34 | const { data: user } = stores.user; | ||
35 | |||
36 | if (user.hadSubscription) { | ||
37 | return ( | ||
38 | <SubscriptionForm | ||
39 | plan={stores.payment.plan} | ||
40 | selectPlan={() => this.openBrowser()} | ||
41 | isActivatingTrial={stores.user.activateTrialRequest.isExecuting || stores.user.getUserInfoRequest.isExecuting} | ||
42 | /> | ||
43 | ); | ||
44 | } | ||
45 | |||
85 | return ( | 46 | return ( |
86 | <SubscriptionForm | 47 | <TrialForm |
87 | plan={stores.payment.plan} | 48 | plan={stores.payment.plan} |
88 | isLoading={stores.payment.plansRequest.isExecuting} | 49 | activateTrial={() => actions.user.activateTrial({ planId: stores.features.features.defaultTrialPlan })} |
89 | retryPlanRequest={() => stores.payment.plansRequest.reload()} | 50 | showAllOptions={() => this.openBrowser()} |
90 | isCreatingHostedPage={stores.payment.createHostedPageRequest.isExecuting} | 51 | isActivatingTrial={stores.user.activateTrialRequest.isExecuting || stores.user.getUserInfoRequest.isExecuting} |
91 | handlePayment={price => this.handlePayment(price)} | ||
92 | content={content} | ||
93 | error={stores.payment.plansRequest.isError} | ||
94 | showSkipOption={showSkipOption} | ||
95 | skipAction={skipAction} | ||
96 | skipButtonLabel={skipButtonLabel} | ||
97 | hideInfo={hideInfo} | ||
98 | openExternalUrl={actions.app.openExternalUrl} | ||
99 | /> | 52 | /> |
100 | ); | 53 | ); |
101 | } | 54 | } |
diff --git a/src/containers/subscription/SubscriptionPopupScreen.js b/src/containers/subscription/SubscriptionPopupScreen.js index f76d6c5a6..0de5a87c4 100644 --- a/src/containers/subscription/SubscriptionPopupScreen.js +++ b/src/containers/subscription/SubscriptionPopupScreen.js | |||
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; | |||
3 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
4 | 4 | ||
5 | import SubscriptionPopup from '../../components/subscription/SubscriptionPopup'; | 5 | import SubscriptionPopup from '../../components/subscription/SubscriptionPopup'; |
6 | import { isDevMode } from '../../environment'; | ||
6 | 7 | ||
7 | 8 | ||
8 | export default @inject('stores', 'actions') @observer class SubscriptionPopupScreen extends Component { | 9 | export default @inject('stores', 'actions') @observer class SubscriptionPopupScreen extends Component { |
@@ -13,7 +14,7 @@ export default @inject('stores', 'actions') @observer class SubscriptionPopupScr | |||
13 | completeCheck(event) { | 14 | completeCheck(event) { |
14 | const { url } = event; | 15 | const { url } = event; |
15 | 16 | ||
16 | if ((url.includes('recurly') && url.includes('confirmation')) || (url.includes('meetfranz') && url.includes('success'))) { | 17 | if ((url.includes('recurly') && url.includes('confirmation')) || ((url.includes('meetfranz') || isDevMode) && url.includes('success'))) { |
17 | this.setState({ | 18 | this.setState({ |
18 | complete: true, | 19 | complete: true, |
19 | }); | 20 | }); |