diff options
Diffstat (limited to 'src')
23 files changed, 745 insertions, 257 deletions
diff --git a/src/api/PaymentApi.js b/src/api/PaymentApi.js index 3f6bb442e..7325151e9 100644 --- a/src/api/PaymentApi.js +++ b/src/api/PaymentApi.js | |||
@@ -11,12 +11,4 @@ export default class PaymentApi { | |||
11 | getHostedPage(planId) { | 11 | getHostedPage(planId) { |
12 | return this.server.getHostedPage(planId); | 12 | return this.server.getHostedPage(planId); |
13 | } | 13 | } |
14 | |||
15 | getDashboardUrl() { | ||
16 | return this.server.getPaymentDashboardUrl(); | ||
17 | } | ||
18 | |||
19 | getOrders() { | ||
20 | return this.server.getSubscriptionOrders(); | ||
21 | } | ||
22 | } | 14 | } |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index bafeef005..f6bc9c283 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -418,23 +418,6 @@ export default class ServerApi { | |||
418 | return data; | 418 | return data; |
419 | } | 419 | } |
420 | 420 | ||
421 | async getPaymentDashboardUrl() { | ||
422 | const request = await sendAuthRequest(`${API_URL}/me/billing`); | ||
423 | if (!request.ok) throw request; | ||
424 | const data = await request.json(); | ||
425 | debug('ServerApi::getPaymentDashboardUrl resolves', data); | ||
426 | return data; | ||
427 | } | ||
428 | |||
429 | async getSubscriptionOrders() { | ||
430 | const request = await sendAuthRequest(`${API_URL}/me/subscription`); | ||
431 | if (!request.ok) throw request; | ||
432 | const data = await request.json(); | ||
433 | const orders = this._mapOrderModels(data); | ||
434 | debug('ServerApi::getSubscriptionOrders resolves', orders); | ||
435 | return orders; | ||
436 | } | ||
437 | |||
438 | // News | 421 | // News |
439 | async getLatestNews() { | 422 | async getLatestNews() { |
440 | const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; | 423 | const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; |
diff --git a/src/app.js b/src/app.js index fb9f1c6ab..f6092bf60 100644 --- a/src/app.js +++ b/src/app.js | |||
@@ -27,6 +27,7 @@ import RecipesScreen from './containers/settings/RecipesScreen'; | |||
27 | import ServicesScreen from './containers/settings/ServicesScreen'; | 27 | import ServicesScreen from './containers/settings/ServicesScreen'; |
28 | import EditServiceScreen from './containers/settings/EditServiceScreen'; | 28 | import EditServiceScreen from './containers/settings/EditServiceScreen'; |
29 | import AccountScreen from './containers/settings/AccountScreen'; | 29 | import AccountScreen from './containers/settings/AccountScreen'; |
30 | import TeamScreen from './containers/settings/TeamScreen'; | ||
30 | import EditUserScreen from './containers/settings/EditUserScreen'; | 31 | import EditUserScreen from './containers/settings/EditUserScreen'; |
31 | import EditSettingsScreen from './containers/settings/EditSettingsScreen'; | 32 | import EditSettingsScreen from './containers/settings/EditSettingsScreen'; |
32 | import InviteSettingsScreen from './containers/settings/InviteScreen'; | 33 | import InviteSettingsScreen from './containers/settings/InviteScreen'; |
@@ -82,6 +83,7 @@ window.addEventListener('load', () => { | |||
82 | <Route path={WORKSPACES_ROUTES.EDIT} component={EditWorkspaceScreen} /> | 83 | <Route path={WORKSPACES_ROUTES.EDIT} component={EditWorkspaceScreen} /> |
83 | <Route path="/settings/user" component={AccountScreen} /> | 84 | <Route path="/settings/user" component={AccountScreen} /> |
84 | <Route path="/settings/user/edit" component={EditUserScreen} /> | 85 | <Route path="/settings/user/edit" component={EditUserScreen} /> |
86 | <Route path="/settings/team" component={TeamScreen} /> | ||
85 | <Route path="/settings/app" component={EditSettingsScreen} /> | 87 | <Route path="/settings/app" component={EditSettingsScreen} /> |
86 | <Route path="/settings/invite" component={InviteSettingsScreen} /> | 88 | <Route path="/settings/invite" component={InviteSettingsScreen} /> |
87 | </Route> | 89 | </Route> |
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 181b95c8c..ea335815c 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -3,12 +3,10 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import ReactTooltip from 'react-tooltip'; | 5 | import ReactTooltip from 'react-tooltip'; |
6 | import moment from 'moment'; | ||
7 | 6 | ||
8 | import Loader from '../../ui/Loader'; | 7 | import Loader from '../../ui/Loader'; |
9 | import Button from '../../ui/Button'; | 8 | import Button from '../../ui/Button'; |
10 | import Infobox from '../../ui/Infobox'; | 9 | import Infobox from '../../ui/Infobox'; |
11 | import Link from '../../ui/Link'; | ||
12 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; | 10 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; |
13 | 11 | ||
14 | const messages = defineMessages({ | 12 | const messages = defineMessages({ |
@@ -24,10 +22,6 @@ const messages = defineMessages({ | |||
24 | id: 'settings.account.headlineUpgrade', | 22 | id: 'settings.account.headlineUpgrade', |
25 | defaultMessage: '!!!Upgrade your Account', | 23 | defaultMessage: '!!!Upgrade your Account', |
26 | }, | 24 | }, |
27 | headlineInvoices: { | ||
28 | id: 'settings.account.headlineInvoices', | ||
29 | defaultMessage: '!!Invoices', | ||
30 | }, | ||
31 | headlineDangerZone: { | 25 | headlineDangerZone: { |
32 | id: 'settings.account.headlineDangerZone', | 26 | id: 'settings.account.headlineDangerZone', |
33 | defaultMessage: '!!Danger Zone', | 27 | defaultMessage: '!!Danger Zone', |
@@ -48,6 +42,10 @@ const messages = defineMessages({ | |||
48 | id: 'settings.account.account.editButton', | 42 | id: 'settings.account.account.editButton', |
49 | defaultMessage: '!!!Edit Account', | 43 | defaultMessage: '!!!Edit Account', |
50 | }, | 44 | }, |
45 | invoicesButton: { | ||
46 | id: 'settings.account.headlineInvoices', | ||
47 | defaultMessage: '!!Invoices', | ||
48 | }, | ||
51 | invoiceDownload: { | 49 | invoiceDownload: { |
52 | id: 'settings.account.invoiceDownload', | 50 | id: 'settings.account.invoiceDownload', |
53 | defaultMessage: '!!!Download', | 51 | defaultMessage: '!!!Download', |
@@ -77,19 +75,17 @@ const messages = defineMessages({ | |||
77 | export default @observer class AccountDashboard extends Component { | 75 | export default @observer class AccountDashboard extends Component { |
78 | static propTypes = { | 76 | static propTypes = { |
79 | user: MobxPropTypes.observableObject.isRequired, | 77 | user: MobxPropTypes.observableObject.isRequired, |
80 | orders: MobxPropTypes.arrayOrObservableArray.isRequired, | ||
81 | isLoading: PropTypes.bool.isRequired, | 78 | isLoading: PropTypes.bool.isRequired, |
82 | isLoadingOrdersInfo: PropTypes.bool.isRequired, | ||
83 | isLoadingPlans: PropTypes.bool.isRequired, | 79 | isLoadingPlans: PropTypes.bool.isRequired, |
84 | isCreatingPaymentDashboardUrl: PropTypes.bool.isRequired, | ||
85 | userInfoRequestFailed: PropTypes.bool.isRequired, | 80 | userInfoRequestFailed: PropTypes.bool.isRequired, |
86 | retryUserInfoRequest: PropTypes.func.isRequired, | 81 | retryUserInfoRequest: PropTypes.func.isRequired, |
87 | openDashboard: PropTypes.func.isRequired, | ||
88 | openExternalUrl: PropTypes.func.isRequired, | ||
89 | onCloseSubscriptionWindow: PropTypes.func.isRequired, | 82 | onCloseSubscriptionWindow: PropTypes.func.isRequired, |
90 | deleteAccount: PropTypes.func.isRequired, | 83 | deleteAccount: PropTypes.func.isRequired, |
91 | isLoadingDeleteAccount: PropTypes.bool.isRequired, | 84 | isLoadingDeleteAccount: PropTypes.bool.isRequired, |
92 | isDeleteAccountSuccessful: PropTypes.bool.isRequired, | 85 | isDeleteAccountSuccessful: PropTypes.bool.isRequired, |
86 | openEditAccount: PropTypes.func.isRequired, | ||
87 | openBilling: PropTypes.func.isRequired, | ||
88 | openInvoices: PropTypes.func.isRequired, | ||
93 | }; | 89 | }; |
94 | 90 | ||
95 | static contextTypes = { | 91 | static contextTypes = { |
@@ -99,12 +95,7 @@ export default @observer class AccountDashboard extends Component { | |||
99 | render() { | 95 | render() { |
100 | const { | 96 | const { |
101 | user, | 97 | user, |
102 | orders, | ||
103 | isLoading, | 98 | isLoading, |
104 | isCreatingPaymentDashboardUrl, | ||
105 | openDashboard, | ||
106 | openExternalUrl, | ||
107 | isLoadingOrdersInfo, | ||
108 | isLoadingPlans, | 99 | isLoadingPlans, |
109 | userInfoRequestFailed, | 100 | userInfoRequestFailed, |
110 | retryUserInfoRequest, | 101 | retryUserInfoRequest, |
@@ -112,6 +103,9 @@ export default @observer class AccountDashboard extends Component { | |||
112 | deleteAccount, | 103 | deleteAccount, |
113 | isLoadingDeleteAccount, | 104 | isLoadingDeleteAccount, |
114 | isDeleteAccountSuccessful, | 105 | isDeleteAccountSuccessful, |
106 | openEditAccount, | ||
107 | openBilling, | ||
108 | openInvoices, | ||
115 | } = this.props; | 109 | } = this.props; |
116 | const { intl } = this.context; | 110 | const { intl } = this.context; |
117 | 111 | ||
@@ -161,68 +155,48 @@ export default @observer class AccountDashboard extends Component { | |||
161 | <div className="account__info"> | 155 | <div className="account__info"> |
162 | <h2> | 156 | <h2> |
163 | {`${user.firstname} ${user.lastname}`} | 157 | {`${user.firstname} ${user.lastname}`} |
158 | {user.isPremium && ( | ||
159 | <> | ||
160 | {' '} | ||
161 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | ||
162 | </> | ||
163 | )} | ||
164 | </h2> | 164 | </h2> |
165 | {user.organization && `${user.organization}, `} | 165 | {user.organization && `${user.organization}, `} |
166 | {user.email} | 166 | {user.email} |
167 | <br /> | ||
168 | {user.isPremium && ( | 167 | {user.isPremium && ( |
169 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | 168 | <div className="manage-user-links"> |
169 | <Button | ||
170 | label={intl.formatMessage(messages.accountEditButton)} | ||
171 | className="franz-form__button--inverted" | ||
172 | onClick={openEditAccount} | ||
173 | /> | ||
174 | {user.isSubscriptionOwner && ( | ||
175 | <> | ||
176 | <Button | ||
177 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} | ||
178 | className="franz-form__button--inverted" | ||
179 | onClick={openBilling} | ||
180 | /> | ||
181 | <Button | ||
182 | label={intl.formatMessage(messages.invoicesButton)} | ||
183 | className="franz-form__button--inverted" | ||
184 | onClick={openInvoices} | ||
185 | /> | ||
186 | </> | ||
187 | )} | ||
188 | </div> | ||
170 | )} | 189 | )} |
171 | </div> | 190 | </div> |
172 | <Link to="/settings/user/edit" className="button"> | 191 | {!user.isPremium && ( |
173 | {intl.formatMessage(messages.accountEditButton)} | 192 | <Button |
174 | </Link> | 193 | label={intl.formatMessage(messages.accountEditButton)} |
175 | {user.emailValidated} | 194 | className="franz-form__button--inverted" |
176 | </div> | 195 | onClick={openEditAccount} |
177 | </div> | 196 | /> |
178 | )} | ||
179 | |||
180 | {user.isSubscriptionOwner && ( | ||
181 | isLoadingOrdersInfo ? ( | ||
182 | <Loader /> | ||
183 | ) : ( | ||
184 | <div className="account franz-form"> | ||
185 | {orders.length > 0 && ( | ||
186 | <Fragment> | ||
187 | <div className="account__box"> | ||
188 | <h2>{intl.formatMessage(messages.headlineSubscription)}</h2> | ||
189 | <div className="account__subscription"> | ||
190 | {orders[0].name} | ||
191 | <span className="badge">{orders[0].price}</span> | ||
192 | <Button | ||
193 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} | ||
194 | className="account__subscription-button franz-form__button--inverted" | ||
195 | loaded={!isCreatingPaymentDashboardUrl} | ||
196 | onClick={() => openDashboard()} | ||
197 | /> | ||
198 | </div> | ||
199 | </div> | ||
200 | <div className="account__box"> | ||
201 | <h2>{intl.formatMessage(messages.headlineInvoices)}</h2> | ||
202 | <table className="invoices"> | ||
203 | <tbody> | ||
204 | {orders.map(order => ( | ||
205 | <tr key={order.id}> | ||
206 | <td className="invoices__date"> | ||
207 | {moment(order.date).format('DD.MM.YYYY')} | ||
208 | </td> | ||
209 | <td className="invoices__action"> | ||
210 | <button | ||
211 | type="button" | ||
212 | onClick={() => openExternalUrl(order.invoiceUrl)} | ||
213 | > | ||
214 | {intl.formatMessage(messages.invoiceDownload)} | ||
215 | </button> | ||
216 | </td> | ||
217 | </tr> | ||
218 | ))} | ||
219 | </tbody> | ||
220 | </table> | ||
221 | </div> | ||
222 | </Fragment> | ||
223 | )} | 197 | )} |
224 | </div> | 198 | </div> |
225 | ) | 199 | </div> |
226 | )} | 200 | )} |
227 | 201 | ||
228 | {!user.isPremium && ( | 202 | {!user.isPremium && ( |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 993b0a44a..cab6f23d7 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -25,6 +25,10 @@ const messages = defineMessages({ | |||
25 | id: 'settings.navigation.account', | 25 | id: 'settings.navigation.account', |
26 | defaultMessage: '!!!Account', | 26 | defaultMessage: '!!!Account', |
27 | }, | 27 | }, |
28 | team: { | ||
29 | id: 'settings.navigation.team', | ||
30 | defaultMessage: '!!!Manage Team', | ||
31 | }, | ||
28 | settings: { | 32 | settings: { |
29 | id: 'settings.navigation.settings', | 33 | id: 'settings.navigation.settings', |
30 | defaultMessage: '!!!Settings', | 34 | defaultMessage: '!!!Settings', |
@@ -98,6 +102,13 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
98 | {intl.formatMessage(messages.account)} | 102 | {intl.formatMessage(messages.account)} |
99 | </Link> | 103 | </Link> |
100 | <Link | 104 | <Link |
105 | to="/settings/team" | ||
106 | className="settings-navigation__link" | ||
107 | activeClassName="is-active" | ||
108 | > | ||
109 | {intl.formatMessage(messages.team)} | ||
110 | </Link> | ||
111 | <Link | ||
101 | to="/settings/app" | 112 | to="/settings/app" |
102 | className="settings-navigation__link" | 113 | className="settings-navigation__link" |
103 | activeClassName="is-active" | 114 | activeClassName="is-active" |
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js new file mode 100644 index 000000000..e222bb14c --- /dev/null +++ b/src/components/settings/team/TeamDashboard.js | |||
@@ -0,0 +1,123 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import ReactTooltip from 'react-tooltip'; | ||
6 | import injectSheet from 'react-jss'; | ||
7 | |||
8 | import Loader from '../../ui/Loader'; | ||
9 | import Button from '../../ui/Button'; | ||
10 | import Infobox from '../../ui/Infobox'; | ||
11 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | ||
12 | |||
13 | const messages = defineMessages({ | ||
14 | headline: { | ||
15 | id: 'settings.team.headline', | ||
16 | defaultMessage: '!!!Team', | ||
17 | }, | ||
18 | contentHeadline: { | ||
19 | id: 'settings.team.contentHeadline', | ||
20 | defaultMessage: '!!!Franz for Teams', | ||
21 | }, | ||
22 | intro: { | ||
23 | id: 'settings.team.intro', | ||
24 | defaultMessage: '!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.', | ||
25 | }, | ||
26 | copy: { | ||
27 | id: 'settings.team.copy', | ||
28 | defaultMessage: '!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!', | ||
29 | }, | ||
30 | manageButton: { | ||
31 | id: 'settings.team.manageAction', | ||
32 | defaultMessage: '!!!Manage your Team', | ||
33 | }, | ||
34 | upgradeButton: { | ||
35 | id: 'settings.team.upgradeAction', | ||
36 | defaultMessage: '!!!Upgrade your Account', | ||
37 | }, | ||
38 | }); | ||
39 | |||
40 | const styles = { | ||
41 | cta: { | ||
42 | marginTop: 40, | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | |||
47 | export default @injectSheet(styles) @observer class TeamDashboard extends Component { | ||
48 | static propTypes = { | ||
49 | user: MobxPropTypes.observableObject.isRequired, | ||
50 | isLoading: PropTypes.bool.isRequired, | ||
51 | userInfoRequestFailed: PropTypes.bool.isRequired, | ||
52 | retryUserInfoRequest: PropTypes.func.isRequired, | ||
53 | openTeamManagement: PropTypes.func.isRequired, | ||
54 | classes: PropTypes.object.isRequired, | ||
55 | }; | ||
56 | |||
57 | static contextTypes = { | ||
58 | intl: intlShape, | ||
59 | }; | ||
60 | |||
61 | render() { | ||
62 | const { | ||
63 | user, | ||
64 | isLoading, | ||
65 | userInfoRequestFailed, | ||
66 | retryUserInfoRequest, | ||
67 | openTeamManagement, | ||
68 | classes, | ||
69 | } = this.props; | ||
70 | const { intl } = this.context; | ||
71 | |||
72 | return ( | ||
73 | <div className="settings__main"> | ||
74 | <div className="settings__header"> | ||
75 | <span className="settings__header-item"> | ||
76 | {intl.formatMessage(messages.headline)} | ||
77 | </span> | ||
78 | </div> | ||
79 | <div className="settings__body"> | ||
80 | {isLoading && ( | ||
81 | <Loader /> | ||
82 | )} | ||
83 | |||
84 | {!isLoading && userInfoRequestFailed && ( | ||
85 | <Infobox | ||
86 | icon="alert" | ||
87 | type="danger" | ||
88 | ctaLabel={intl.formatMessage(messages.tryReloadUserInfoRequest)} | ||
89 | ctaLoading={isLoading} | ||
90 | ctaOnClick={retryUserInfoRequest} | ||
91 | > | ||
92 | {intl.formatMessage(messages.userInfoRequestFailed)} | ||
93 | </Infobox> | ||
94 | )} | ||
95 | |||
96 | {!userInfoRequestFailed && ( | ||
97 | <> | ||
98 | {!isLoading && ( | ||
99 | <> | ||
100 | <PremiumFeatureContainer> | ||
101 | <> | ||
102 | <h1>{intl.formatMessage(messages.contentHeadline)}</h1> | ||
103 | <p>{intl.formatMessage(messages.intro)}</p> | ||
104 | <p>{intl.formatMessage(messages.copy)}</p> | ||
105 | {user.isSubscriptionOwner && ( | ||
106 | <Button | ||
107 | label={intl.formatMessage(messages.manageButton)} | ||
108 | onClick={openTeamManagement} | ||
109 | className={classes.cta} | ||
110 | /> | ||
111 | )} | ||
112 | </> | ||
113 | </PremiumFeatureContainer> | ||
114 | </> | ||
115 | )} | ||
116 | </> | ||
117 | )} | ||
118 | </div> | ||
119 | <ReactTooltip place="right" type="dark" effect="solid" /> | ||
120 | </div> | ||
121 | ); | ||
122 | } | ||
123 | } | ||
diff --git a/src/config.js b/src/config.js index 242675762..0a47aa7d7 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -12,6 +12,15 @@ export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks | |||
12 | export const LOCAL_API = 'http://localhost:3000'; | 12 | export const LOCAL_API = 'http://localhost:3000'; |
13 | export const DEV_API = 'https://dev.franzinfra.com'; | 13 | export const DEV_API = 'https://dev.franzinfra.com'; |
14 | export const LIVE_API = 'https://api.franzinfra.com'; | 14 | export const LIVE_API = 'https://api.franzinfra.com'; |
15 | |||
16 | export const LOCAL_WS_API = 'ws://localhost:3000'; | ||
17 | export const DEV_WS_API = 'wss://dev.franzinfra.com'; | ||
18 | export const LIVE_WS_API = 'wss://api.franzinfra.com'; | ||
19 | |||
20 | export const LOCAL_API_WEBSITE = 'http://localhost:3333'; | ||
21 | export const DEV_API_WEBSITE = 'https://meetfranz.com'; | ||
22 | export const LIVE_API_WEBSITE = 'https://meetfranz.com'; | ||
23 | |||
15 | export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; | 24 | export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; |
16 | 25 | ||
17 | export const DEFAULT_APP_SETTINGS = { | 26 | export const DEFAULT_APP_SETTINGS = { |
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index ce1b9c333..b3f967353 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.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'; |
@@ -9,84 +8,52 @@ import AppStore from '../../stores/AppStore'; | |||
9 | 8 | ||
10 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; | 9 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; |
11 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 10 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
12 | 11 | import { WEBSITE } from '../../environment'; | |
13 | const { BrowserWindow } = remote; | ||
14 | 12 | ||
15 | export default @inject('stores', 'actions') @observer class AccountScreen extends Component { | 13 | export default @inject('stores', 'actions') @observer class AccountScreen extends Component { |
16 | componentWillMount() { | ||
17 | const { | ||
18 | user, | ||
19 | } = this.props.stores; | ||
20 | |||
21 | user.getUserInfoRequest.invalidate({ immediately: true }); | ||
22 | } | ||
23 | |||
24 | onCloseWindow() { | 14 | onCloseWindow() { |
25 | const { user, payment } = this.props.stores; | 15 | const { user } = this.props.stores; |
26 | user.getUserInfoRequest.invalidate({ immediately: true }); | 16 | user.getUserInfoRequest.invalidate({ immediately: true }); |
27 | payment.ordersDataRequest.invalidate({ immediately: true }); | ||
28 | } | 17 | } |
29 | 18 | ||
30 | reloadData() { | 19 | reloadData() { |
31 | const { user, payment } = this.props.stores; | 20 | const { user, payment } = this.props.stores; |
32 | 21 | ||
33 | user.getUserInfoRequest.reload(); | 22 | user.getUserInfoRequest.reload(); |
34 | payment.ordersDataRequest.reload(); | ||
35 | payment.plansRequest.reload(); | 23 | payment.plansRequest.reload(); |
36 | } | 24 | } |
37 | 25 | ||
38 | async handlePaymentDashboard() { | 26 | handleWebsiteLink(route) { |
39 | const { actions, stores } = this.props; | 27 | const { actions, stores } = this.props; |
40 | 28 | ||
41 | actions.payment.createDashboardUrl(); | 29 | const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; |
42 | 30 | console.log(url); | |
43 | const dashboard = await stores.payment.createDashboardUrlRequest; | ||
44 | |||
45 | if (dashboard.url) { | ||
46 | const paymentWindow = new BrowserWindow({ | ||
47 | title: '🔒 Franz Subscription Dashboard', | ||
48 | parent: remote.getCurrentWindow(), | ||
49 | modal: false, | ||
50 | width: 900, | ||
51 | minWidth: 600, | ||
52 | webPreferences: { | ||
53 | nodeIntegration: false, | ||
54 | }, | ||
55 | }); | ||
56 | paymentWindow.loadURL(dashboard.url); | ||
57 | 31 | ||
58 | paymentWindow.on('closed', () => { | 32 | actions.app.openExternalUrl({ url }); |
59 | this.onCloseWindow(); | ||
60 | }); | ||
61 | } | ||
62 | } | 33 | } |
63 | 34 | ||
64 | render() { | 35 | render() { |
65 | const { user, payment } = this.props.stores; | 36 | const { user, payment } = this.props.stores; |
66 | const { openExternalUrl } = this.props.actions.app; | ||
67 | const { user: userActions } = this.props.actions; | 37 | const { user: userActions } = this.props.actions; |
68 | 38 | ||
69 | const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; | 39 | const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; |
70 | const isLoadingOrdersInfo = payment.ordersDataRequest.isExecuting; | ||
71 | const isLoadingPlans = payment.plansRequest.isExecuting; | 40 | const isLoadingPlans = payment.plansRequest.isExecuting; |
72 | 41 | ||
73 | return ( | 42 | return ( |
74 | <ErrorBoundary> | 43 | <ErrorBoundary> |
75 | <AccountDashboard | 44 | <AccountDashboard |
76 | user={user.data} | 45 | user={user.data} |
77 | orders={payment.orders} | ||
78 | isLoading={isLoadingUserInfo} | 46 | isLoading={isLoadingUserInfo} |
79 | isLoadingOrdersInfo={isLoadingOrdersInfo} | ||
80 | isLoadingPlans={isLoadingPlans} | 47 | isLoadingPlans={isLoadingPlans} |
81 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | 48 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} |
82 | retryUserInfoRequest={() => this.reloadData()} | 49 | retryUserInfoRequest={() => this.reloadData()} |
83 | isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting} | ||
84 | openDashboard={price => this.handlePaymentDashboard(price)} | ||
85 | openExternalUrl={url => openExternalUrl({ url })} | ||
86 | onCloseSubscriptionWindow={() => this.onCloseWindow()} | 50 | onCloseSubscriptionWindow={() => this.onCloseWindow()} |
87 | deleteAccount={userActions.delete} | 51 | deleteAccount={userActions.delete} |
88 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} | 52 | isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} |
89 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} | 53 | isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} |
54 | openEditAccount={() => this.handleWebsiteLink('/user/profile')} | ||
55 | openBilling={() => this.handleWebsiteLink('/user/billing')} | ||
56 | openInvoices={() => this.handleWebsiteLink('/user/invoices')} | ||
90 | /> | 57 | /> |
91 | </ErrorBoundary> | 58 | </ErrorBoundary> |
92 | ); | 59 | ); |
diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js new file mode 100644 index 000000000..30b0895e3 --- /dev/null +++ b/src/containers/settings/TeamScreen.js | |||
@@ -0,0 +1,58 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | ||
4 | |||
5 | import UserStore from '../../stores/UserStore'; | ||
6 | import AppStore from '../../stores/AppStore'; | ||
7 | |||
8 | import TeamDashboard from '../../components/settings/team/TeamDashboard'; | ||
9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | ||
10 | import { WEBSITE } from '../../environment'; | ||
11 | |||
12 | export default @inject('stores', 'actions') @observer class TeamScreen extends Component { | ||
13 | handleWebsiteLink(route) { | ||
14 | const { actions, stores } = this.props; | ||
15 | |||
16 | const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; | ||
17 | console.log(url); | ||
18 | |||
19 | actions.app.openExternalUrl({ url }); | ||
20 | } | ||
21 | |||
22 | render() { | ||
23 | const { user } = this.props.stores; | ||
24 | |||
25 | const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; | ||
26 | |||
27 | return ( | ||
28 | <ErrorBoundary> | ||
29 | <TeamDashboard | ||
30 | user={user.data} | ||
31 | isLoading={isLoadingUserInfo} | ||
32 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | ||
33 | retryUserInfoRequest={() => this.reloadData()} | ||
34 | openTeamManagement={() => this.handleWebsiteLink('/user/team')} | ||
35 | /> | ||
36 | </ErrorBoundary> | ||
37 | ); | ||
38 | } | ||
39 | } | ||
40 | |||
41 | TeamScreen.wrappedComponent.propTypes = { | ||
42 | stores: PropTypes.shape({ | ||
43 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
44 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
45 | }).isRequired, | ||
46 | actions: PropTypes.shape({ | ||
47 | payment: PropTypes.shape({ | ||
48 | createDashboardUrl: PropTypes.func.isRequired, | ||
49 | }).isRequired, | ||
50 | app: PropTypes.shape({ | ||
51 | openExternalUrl: PropTypes.func.isRequired, | ||
52 | }).isRequired, | ||
53 | user: PropTypes.shape({ | ||
54 | update: PropTypes.func.isRequired, | ||
55 | delete: PropTypes.func.isRequired, | ||
56 | }).isRequired, | ||
57 | }).isRequired, | ||
58 | }; | ||
diff --git a/src/environment.js b/src/environment.js index d67fd6adb..ae7a67e4d 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -1,6 +1,16 @@ | |||
1 | import isDev from 'electron-is-dev'; | 1 | import isDev from 'electron-is-dev'; |
2 | 2 | ||
3 | import { LIVE_API, DEV_API, LOCAL_API } from './config'; | 3 | import { |
4 | LIVE_API, | ||
5 | DEV_API, | ||
6 | LOCAL_API, | ||
7 | LOCAL_API_WEBSITE, | ||
8 | DEV_API_WEBSITE, | ||
9 | LIVE_API_WEBSITE, | ||
10 | LIVE_WS_API, | ||
11 | LOCAL_WS_API, | ||
12 | DEV_WS_API, | ||
13 | } from './config'; | ||
4 | 14 | ||
5 | export const isDevMode = isDev; | 15 | export const isDevMode = isDev; |
6 | export const useLiveAPI = process.env.LIVE_API; | 16 | export const useLiveAPI = process.env.LIVE_API; |
@@ -19,13 +29,23 @@ export const ctrlKey = isMac ? '⌘' : 'Ctrl'; | |||
19 | export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; | 29 | export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; |
20 | 30 | ||
21 | let api; | 31 | let api; |
32 | let wsApi; | ||
33 | let web; | ||
22 | if (!isDevMode || (isDevMode && useLiveAPI)) { | 34 | if (!isDevMode || (isDevMode && useLiveAPI)) { |
23 | api = LIVE_API; | 35 | api = LIVE_API; |
36 | wsApi = LIVE_WS_API; | ||
37 | web = LIVE_API_WEBSITE; | ||
24 | } else if (isDevMode && useLocalAPI) { | 38 | } else if (isDevMode && useLocalAPI) { |
25 | api = LOCAL_API; | 39 | api = LOCAL_API; |
40 | wsApi = LOCAL_WS_API; | ||
41 | web = LOCAL_API_WEBSITE; | ||
26 | } else { | 42 | } else { |
27 | api = DEV_API; | 43 | api = DEV_API; |
44 | wsApi = DEV_WS_API; | ||
45 | web = DEV_API_WEBSITE; | ||
28 | } | 46 | } |
29 | 47 | ||
30 | export const API = api; | 48 | export const API = api; |
31 | export const API_VERSION = 'v1'; | 49 | export const API_VERSION = 'v1'; |
50 | export const WS_API = wsApi; | ||
51 | export const WEBSITE = web; | ||
diff --git a/src/features/settingsWS/actions.js b/src/features/settingsWS/actions.js new file mode 100755 index 000000000..631670c8a --- /dev/null +++ b/src/features/settingsWS/actions.js | |||
@@ -0,0 +1,10 @@ | |||
1 | import PropTypes from 'prop-types'; | ||
2 | import { createActionsFromDefinitions } from '../../actions/lib/actions'; | ||
3 | |||
4 | export const settingsWSActions = createActionsFromDefinitions({ | ||
5 | greet: { | ||
6 | name: PropTypes.string.isRequired, | ||
7 | }, | ||
8 | }, PropTypes.checkPropTypes); | ||
9 | |||
10 | export default settingsWSActions; | ||
diff --git a/src/features/settingsWS/index.js b/src/features/settingsWS/index.js new file mode 100755 index 000000000..1e268f184 --- /dev/null +++ b/src/features/settingsWS/index.js | |||
@@ -0,0 +1,35 @@ | |||
1 | import { reaction, runInAction } from 'mobx'; | ||
2 | import { SettingsWSStore } from './store'; | ||
3 | import state, { resetState } from './state'; | ||
4 | |||
5 | const debug = require('debug')('Franz:feature:settingsWS'); | ||
6 | |||
7 | let store = null; | ||
8 | |||
9 | export default function initAnnouncements(stores, actions) { | ||
10 | const { features } = stores; | ||
11 | |||
12 | // Toggle workspace feature | ||
13 | reaction( | ||
14 | () => ( | ||
15 | features.features.isSettingsWSEnabled | ||
16 | ), | ||
17 | (isEnabled) => { | ||
18 | if (isEnabled) { | ||
19 | debug('Initializing `settingsWS` feature'); | ||
20 | store = new SettingsWSStore(stores, null, actions, state); | ||
21 | store.initialize(); | ||
22 | runInAction(() => { state.isFeatureActive = true; }); | ||
23 | } else if (store) { | ||
24 | debug('Disabling `settingsWS` feature'); | ||
25 | runInAction(() => { state.isFeatureActive = false; }); | ||
26 | store.teardown(); | ||
27 | store = null; | ||
28 | resetState(); // Reset state to default | ||
29 | } | ||
30 | }, | ||
31 | { | ||
32 | fireImmediately: true, | ||
33 | }, | ||
34 | ); | ||
35 | } | ||
diff --git a/src/features/settingsWS/state.js b/src/features/settingsWS/state.js new file mode 100755 index 000000000..7b16b2b6e --- /dev/null +++ b/src/features/settingsWS/state.js | |||
@@ -0,0 +1,13 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | |||
3 | const defaultState = { | ||
4 | isFeatureActive: false, | ||
5 | }; | ||
6 | |||
7 | export const settingsWSState = observable(defaultState); | ||
8 | |||
9 | export function resetState() { | ||
10 | Object.assign(settingsWSState, defaultState); | ||
11 | } | ||
12 | |||
13 | export default settingsWSState; | ||
diff --git a/src/features/settingsWS/store.js b/src/features/settingsWS/store.js new file mode 100755 index 000000000..3cc74d8ef --- /dev/null +++ b/src/features/settingsWS/store.js | |||
@@ -0,0 +1,104 @@ | |||
1 | import { observable, reaction } from 'mobx'; | ||
2 | import WebSocket from 'ws'; | ||
3 | import ms from 'ms'; | ||
4 | |||
5 | import Store from '../../stores/lib/Store'; | ||
6 | import { WS_API } from '../../environment'; | ||
7 | |||
8 | const debug = require('debug')('Franz:feature:settingsWS:store'); | ||
9 | |||
10 | export class SettingsWSStore extends Store { | ||
11 | ws = null; | ||
12 | |||
13 | @observable connected = false; | ||
14 | |||
15 | pingTimeout = null; | ||
16 | |||
17 | reconnectTimeout = null; | ||
18 | |||
19 | constructor(stores, api, actions, state) { | ||
20 | super(stores, api, actions); | ||
21 | this.state = state; | ||
22 | } | ||
23 | |||
24 | setup() { | ||
25 | this.connect(); | ||
26 | |||
27 | reaction(() => !this.connected, this.reconnect.bind(this)); | ||
28 | } | ||
29 | |||
30 | connect() { | ||
31 | try { | ||
32 | const wsURL = `${WS_API}/ws/${this.stores.user.data.id}`; | ||
33 | debug('Setting up WebSocket to', wsURL); | ||
34 | |||
35 | this.ws = new WebSocket(wsURL); | ||
36 | |||
37 | this.ws.on('open', () => { | ||
38 | debug('Opened WebSocket'); | ||
39 | this.send({ | ||
40 | action: 'authorize', | ||
41 | token: this.stores.user.authToken, | ||
42 | }); | ||
43 | |||
44 | this.connected = true; | ||
45 | |||
46 | this.heartbeat(); | ||
47 | }); | ||
48 | |||
49 | this.ws.on('message', (data) => { | ||
50 | const resp = JSON.parse(data); | ||
51 | debug('Received message', resp); | ||
52 | |||
53 | if (resp.id) { | ||
54 | this.stores.user.getUserInfoRequest.patch((result) => { | ||
55 | if (!result) return; | ||
56 | |||
57 | debug('Patching user object with new values'); | ||
58 | Object.assign(result, resp); | ||
59 | }); | ||
60 | } | ||
61 | }); | ||
62 | |||
63 | this.ws.on('ping', this.heartbeat.bind(this)); | ||
64 | } catch (err) { | ||
65 | console.err(err); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | heartbeat() { | ||
70 | debug('Heartbeat'); | ||
71 | clearTimeout(this.pingTimeout); | ||
72 | |||
73 | this.pingTimeout = setTimeout(() => { | ||
74 | debug('Terminating connection reconnecting in 35'); | ||
75 | this.ws.terminate(); | ||
76 | |||
77 | this.connected = false; | ||
78 | }, ms('35s')); | ||
79 | } | ||
80 | |||
81 | send(data) { | ||
82 | if (this.ws) { | ||
83 | this.ws.send(JSON.stringify(data)); | ||
84 | debug('Sending data', data); | ||
85 | } else { | ||
86 | debug('WebSocket is not initialized'); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | reconnect() { | ||
91 | if (!this.connected) { | ||
92 | debug('Trying to reconnect in 30s'); | ||
93 | this.reconnectTimeout = setInterval(() => { | ||
94 | debug('Trying to reconnect'); | ||
95 | this.connect(); | ||
96 | }, ms('30s')); | ||
97 | } else { | ||
98 | debug('Clearing reconnect interval'); | ||
99 | clearInterval(this.reconnectTimeout); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | export default SettingsWSStore; | ||
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 65799b614..8fe5e8852 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json | |||
@@ -1102,195 +1102,195 @@ | |||
1102 | "defaultMessage": "!!!Account", | 1102 | "defaultMessage": "!!!Account", |
1103 | "end": { | 1103 | "end": { |
1104 | "column": 3, | 1104 | "column": 3, |
1105 | "line": 18 | 1105 | "line": 16 |
1106 | }, | 1106 | }, |
1107 | "file": "src/components/settings/account/AccountDashboard.js", | 1107 | "file": "src/components/settings/account/AccountDashboard.js", |
1108 | "id": "settings.account.headline", | 1108 | "id": "settings.account.headline", |
1109 | "start": { | 1109 | "start": { |
1110 | "column": 12, | 1110 | "column": 12, |
1111 | "line": 15 | 1111 | "line": 13 |
1112 | } | 1112 | } |
1113 | }, | 1113 | }, |
1114 | { | 1114 | { |
1115 | "defaultMessage": "!!!Your Subscription", | 1115 | "defaultMessage": "!!!Your Subscription", |
1116 | "end": { | 1116 | "end": { |
1117 | "column": 3, | 1117 | "column": 3, |
1118 | "line": 22 | 1118 | "line": 20 |
1119 | }, | 1119 | }, |
1120 | "file": "src/components/settings/account/AccountDashboard.js", | 1120 | "file": "src/components/settings/account/AccountDashboard.js", |
1121 | "id": "settings.account.headlineSubscription", | 1121 | "id": "settings.account.headlineSubscription", |
1122 | "start": { | 1122 | "start": { |
1123 | "column": 24, | 1123 | "column": 24, |
1124 | "line": 19 | 1124 | "line": 17 |
1125 | } | 1125 | } |
1126 | }, | 1126 | }, |
1127 | { | 1127 | { |
1128 | "defaultMessage": "!!!Upgrade your Account", | 1128 | "defaultMessage": "!!!Upgrade your Account", |
1129 | "end": { | 1129 | "end": { |
1130 | "column": 3, | 1130 | "column": 3, |
1131 | "line": 26 | 1131 | "line": 24 |
1132 | }, | 1132 | }, |
1133 | "file": "src/components/settings/account/AccountDashboard.js", | 1133 | "file": "src/components/settings/account/AccountDashboard.js", |
1134 | "id": "settings.account.headlineUpgrade", | 1134 | "id": "settings.account.headlineUpgrade", |
1135 | "start": { | 1135 | "start": { |
1136 | "column": 19, | 1136 | "column": 19, |
1137 | "line": 23 | 1137 | "line": 21 |
1138 | } | ||
1139 | }, | ||
1140 | { | ||
1141 | "defaultMessage": "!!Invoices", | ||
1142 | "end": { | ||
1143 | "column": 3, | ||
1144 | "line": 30 | ||
1145 | }, | ||
1146 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1147 | "id": "settings.account.headlineInvoices", | ||
1148 | "start": { | ||
1149 | "column": 20, | ||
1150 | "line": 27 | ||
1151 | } | 1138 | } |
1152 | }, | 1139 | }, |
1153 | { | 1140 | { |
1154 | "defaultMessage": "!!Danger Zone", | 1141 | "defaultMessage": "!!Danger Zone", |
1155 | "end": { | 1142 | "end": { |
1156 | "column": 3, | 1143 | "column": 3, |
1157 | "line": 34 | 1144 | "line": 28 |
1158 | }, | 1145 | }, |
1159 | "file": "src/components/settings/account/AccountDashboard.js", | 1146 | "file": "src/components/settings/account/AccountDashboard.js", |
1160 | "id": "settings.account.headlineDangerZone", | 1147 | "id": "settings.account.headlineDangerZone", |
1161 | "start": { | 1148 | "start": { |
1162 | "column": 22, | 1149 | "column": 22, |
1163 | "line": 31 | 1150 | "line": 25 |
1164 | } | 1151 | } |
1165 | }, | 1152 | }, |
1166 | { | 1153 | { |
1167 | "defaultMessage": "!!!Manage your subscription", | 1154 | "defaultMessage": "!!!Manage your subscription", |
1168 | "end": { | 1155 | "end": { |
1169 | "column": 3, | 1156 | "column": 3, |
1170 | "line": 38 | 1157 | "line": 32 |
1171 | }, | 1158 | }, |
1172 | "file": "src/components/settings/account/AccountDashboard.js", | 1159 | "file": "src/components/settings/account/AccountDashboard.js", |
1173 | "id": "settings.account.manageSubscription.label", | 1160 | "id": "settings.account.manageSubscription.label", |
1174 | "start": { | 1161 | "start": { |
1175 | "column": 33, | 1162 | "column": 33, |
1176 | "line": 35 | 1163 | "line": 29 |
1177 | } | 1164 | } |
1178 | }, | 1165 | }, |
1179 | { | 1166 | { |
1180 | "defaultMessage": "!!!Basic Account", | 1167 | "defaultMessage": "!!!Basic Account", |
1181 | "end": { | 1168 | "end": { |
1182 | "column": 3, | 1169 | "column": 3, |
1183 | "line": 42 | 1170 | "line": 36 |
1184 | }, | 1171 | }, |
1185 | "file": "src/components/settings/account/AccountDashboard.js", | 1172 | "file": "src/components/settings/account/AccountDashboard.js", |
1186 | "id": "settings.account.accountType.basic", | 1173 | "id": "settings.account.accountType.basic", |
1187 | "start": { | 1174 | "start": { |
1188 | "column": 20, | 1175 | "column": 20, |
1189 | "line": 39 | 1176 | "line": 33 |
1190 | } | 1177 | } |
1191 | }, | 1178 | }, |
1192 | { | 1179 | { |
1193 | "defaultMessage": "!!!Premium Supporter Account", | 1180 | "defaultMessage": "!!!Premium Supporter Account", |
1194 | "end": { | 1181 | "end": { |
1195 | "column": 3, | 1182 | "column": 3, |
1196 | "line": 46 | 1183 | "line": 40 |
1197 | }, | 1184 | }, |
1198 | "file": "src/components/settings/account/AccountDashboard.js", | 1185 | "file": "src/components/settings/account/AccountDashboard.js", |
1199 | "id": "settings.account.accountType.premium", | 1186 | "id": "settings.account.accountType.premium", |
1200 | "start": { | 1187 | "start": { |
1201 | "column": 22, | 1188 | "column": 22, |
1202 | "line": 43 | 1189 | "line": 37 |
1203 | } | 1190 | } |
1204 | }, | 1191 | }, |
1205 | { | 1192 | { |
1206 | "defaultMessage": "!!!Edit Account", | 1193 | "defaultMessage": "!!!Edit Account", |
1207 | "end": { | 1194 | "end": { |
1208 | "column": 3, | 1195 | "column": 3, |
1209 | "line": 50 | 1196 | "line": 44 |
1210 | }, | 1197 | }, |
1211 | "file": "src/components/settings/account/AccountDashboard.js", | 1198 | "file": "src/components/settings/account/AccountDashboard.js", |
1212 | "id": "settings.account.account.editButton", | 1199 | "id": "settings.account.account.editButton", |
1213 | "start": { | 1200 | "start": { |
1214 | "column": 21, | 1201 | "column": 21, |
1215 | "line": 47 | 1202 | "line": 41 |
1203 | } | ||
1204 | }, | ||
1205 | { | ||
1206 | "defaultMessage": "!!Invoices", | ||
1207 | "end": { | ||
1208 | "column": 3, | ||
1209 | "line": 48 | ||
1210 | }, | ||
1211 | "file": "src/components/settings/account/AccountDashboard.js", | ||
1212 | "id": "settings.account.headlineInvoices", | ||
1213 | "start": { | ||
1214 | "column": 18, | ||
1215 | "line": 45 | ||
1216 | } | 1216 | } |
1217 | }, | 1217 | }, |
1218 | { | 1218 | { |
1219 | "defaultMessage": "!!!Download", | 1219 | "defaultMessage": "!!!Download", |
1220 | "end": { | 1220 | "end": { |
1221 | "column": 3, | 1221 | "column": 3, |
1222 | "line": 54 | 1222 | "line": 52 |
1223 | }, | 1223 | }, |
1224 | "file": "src/components/settings/account/AccountDashboard.js", | 1224 | "file": "src/components/settings/account/AccountDashboard.js", |
1225 | "id": "settings.account.invoiceDownload", | 1225 | "id": "settings.account.invoiceDownload", |
1226 | "start": { | 1226 | "start": { |
1227 | "column": 19, | 1227 | "column": 19, |
1228 | "line": 51 | 1228 | "line": 49 |
1229 | } | 1229 | } |
1230 | }, | 1230 | }, |
1231 | { | 1231 | { |
1232 | "defaultMessage": "!!!Could not load user information", | 1232 | "defaultMessage": "!!!Could not load user information", |
1233 | "end": { | 1233 | "end": { |
1234 | "column": 3, | 1234 | "column": 3, |
1235 | "line": 58 | 1235 | "line": 56 |
1236 | }, | 1236 | }, |
1237 | "file": "src/components/settings/account/AccountDashboard.js", | 1237 | "file": "src/components/settings/account/AccountDashboard.js", |
1238 | "id": "settings.account.userInfoRequestFailed", | 1238 | "id": "settings.account.userInfoRequestFailed", |
1239 | "start": { | 1239 | "start": { |
1240 | "column": 25, | 1240 | "column": 25, |
1241 | "line": 55 | 1241 | "line": 53 |
1242 | } | 1242 | } |
1243 | }, | 1243 | }, |
1244 | { | 1244 | { |
1245 | "defaultMessage": "!!!Try again", | 1245 | "defaultMessage": "!!!Try again", |
1246 | "end": { | 1246 | "end": { |
1247 | "column": 3, | 1247 | "column": 3, |
1248 | "line": 62 | 1248 | "line": 60 |
1249 | }, | 1249 | }, |
1250 | "file": "src/components/settings/account/AccountDashboard.js", | 1250 | "file": "src/components/settings/account/AccountDashboard.js", |
1251 | "id": "settings.account.tryReloadUserInfoRequest", | 1251 | "id": "settings.account.tryReloadUserInfoRequest", |
1252 | "start": { | 1252 | "start": { |
1253 | "column": 28, | 1253 | "column": 28, |
1254 | "line": 59 | 1254 | "line": 57 |
1255 | } | 1255 | } |
1256 | }, | 1256 | }, |
1257 | { | 1257 | { |
1258 | "defaultMessage": "!!!Delete account", | 1258 | "defaultMessage": "!!!Delete account", |
1259 | "end": { | 1259 | "end": { |
1260 | "column": 3, | 1260 | "column": 3, |
1261 | "line": 66 | 1261 | "line": 64 |
1262 | }, | 1262 | }, |
1263 | "file": "src/components/settings/account/AccountDashboard.js", | 1263 | "file": "src/components/settings/account/AccountDashboard.js", |
1264 | "id": "settings.account.deleteAccount", | 1264 | "id": "settings.account.deleteAccount", |
1265 | "start": { | 1265 | "start": { |
1266 | "column": 17, | 1266 | "column": 17, |
1267 | "line": 63 | 1267 | "line": 61 |
1268 | } | 1268 | } |
1269 | }, | 1269 | }, |
1270 | { | 1270 | { |
1271 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", | 1271 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", |
1272 | "end": { | 1272 | "end": { |
1273 | "column": 3, | 1273 | "column": 3, |
1274 | "line": 70 | 1274 | "line": 68 |
1275 | }, | 1275 | }, |
1276 | "file": "src/components/settings/account/AccountDashboard.js", | 1276 | "file": "src/components/settings/account/AccountDashboard.js", |
1277 | "id": "settings.account.deleteInfo", | 1277 | "id": "settings.account.deleteInfo", |
1278 | "start": { | 1278 | "start": { |
1279 | "column": 14, | 1279 | "column": 14, |
1280 | "line": 67 | 1280 | "line": 65 |
1281 | } | 1281 | } |
1282 | }, | 1282 | }, |
1283 | { | 1283 | { |
1284 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", | 1284 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", |
1285 | "end": { | 1285 | "end": { |
1286 | "column": 3, | 1286 | "column": 3, |
1287 | "line": 74 | 1287 | "line": 72 |
1288 | }, | 1288 | }, |
1289 | "file": "src/components/settings/account/AccountDashboard.js", | 1289 | "file": "src/components/settings/account/AccountDashboard.js", |
1290 | "id": "settings.account.deleteEmailSent", | 1290 | "id": "settings.account.deleteEmailSent", |
1291 | "start": { | 1291 | "start": { |
1292 | "column": 19, | 1292 | "column": 19, |
1293 | "line": 71 | 1293 | "line": 69 |
1294 | } | 1294 | } |
1295 | } | 1295 | } |
1296 | ], | 1296 | ], |
@@ -1351,12 +1351,25 @@ | |||
1351 | } | 1351 | } |
1352 | }, | 1352 | }, |
1353 | { | 1353 | { |
1354 | "defaultMessage": "!!!Settings", | 1354 | "defaultMessage": "!!!Manage Team", |
1355 | "end": { | 1355 | "end": { |
1356 | "column": 3, | 1356 | "column": 3, |
1357 | "line": 31 | 1357 | "line": 31 |
1358 | }, | 1358 | }, |
1359 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1359 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1360 | "id": "settings.navigation.team", | ||
1361 | "start": { | ||
1362 | "column": 8, | ||
1363 | "line": 21 | ||
1364 | } | ||
1365 | }, | ||
1366 | { | ||
1367 | "defaultMessage": "!!!Settings", | ||
1368 | "end": { | ||
1369 | "column": 3, | ||
1370 | "line": 28 | ||
1371 | }, | ||
1372 | "file": "src/components/settings/navigation/SettingsNavigation.js", | ||
1360 | "id": "settings.navigation.settings", | 1373 | "id": "settings.navigation.settings", |
1361 | "start": { | 1374 | "start": { |
1362 | "column": 12, | 1375 | "column": 12, |
@@ -2244,6 +2257,89 @@ | |||
2244 | { | 2257 | { |
2245 | "descriptors": [ | 2258 | "descriptors": [ |
2246 | { | 2259 | { |
2260 | "defaultMessage": "!!!Team", | ||
2261 | "end": { | ||
2262 | "column": 3, | ||
2263 | "line": 17 | ||
2264 | }, | ||
2265 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2266 | "id": "settings.team.headline", | ||
2267 | "start": { | ||
2268 | "column": 12, | ||
2269 | "line": 14 | ||
2270 | } | ||
2271 | }, | ||
2272 | { | ||
2273 | "defaultMessage": "!!!Franz for Teams", | ||
2274 | "end": { | ||
2275 | "column": 3, | ||
2276 | "line": 21 | ||
2277 | }, | ||
2278 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2279 | "id": "settings.team.contentHeadline", | ||
2280 | "start": { | ||
2281 | "column": 19, | ||
2282 | "line": 18 | ||
2283 | } | ||
2284 | }, | ||
2285 | { | ||
2286 | "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", | ||
2287 | "end": { | ||
2288 | "column": 3, | ||
2289 | "line": 25 | ||
2290 | }, | ||
2291 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2292 | "id": "settings.team.intro", | ||
2293 | "start": { | ||
2294 | "column": 9, | ||
2295 | "line": 22 | ||
2296 | } | ||
2297 | }, | ||
2298 | { | ||
2299 | "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", | ||
2300 | "end": { | ||
2301 | "column": 3, | ||
2302 | "line": 29 | ||
2303 | }, | ||
2304 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2305 | "id": "settings.team.copy", | ||
2306 | "start": { | ||
2307 | "column": 8, | ||
2308 | "line": 26 | ||
2309 | } | ||
2310 | }, | ||
2311 | { | ||
2312 | "defaultMessage": "!!!Manage your Team", | ||
2313 | "end": { | ||
2314 | "column": 3, | ||
2315 | "line": 33 | ||
2316 | }, | ||
2317 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2318 | "id": "settings.team.manageAction", | ||
2319 | "start": { | ||
2320 | "column": 16, | ||
2321 | "line": 30 | ||
2322 | } | ||
2323 | }, | ||
2324 | { | ||
2325 | "defaultMessage": "!!!Upgrade your Account", | ||
2326 | "end": { | ||
2327 | "column": 3, | ||
2328 | "line": 37 | ||
2329 | }, | ||
2330 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2331 | "id": "settings.team.upgradeAction", | ||
2332 | "start": { | ||
2333 | "column": 17, | ||
2334 | "line": 34 | ||
2335 | } | ||
2336 | } | ||
2337 | ], | ||
2338 | "path": "src/components/settings/team/TeamDashboard.json" | ||
2339 | }, | ||
2340 | { | ||
2341 | "descriptors": [ | ||
2342 | { | ||
2247 | "defaultMessage": "!!!Account", | 2343 | "defaultMessage": "!!!Account", |
2248 | "end": { | 2344 | "end": { |
2249 | "column": 3, | 2345 | "column": 3, |
@@ -4421,4 +4517,4 @@ | |||
4421 | ], | 4517 | ], |
4422 | "path": "src/lib/Menu.json" | 4518 | "path": "src/lib/Menu.json" |
4423 | } | 4519 | } |
4424 | ] \ No newline at end of file | 4520 | ] |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 84a71117a..bcdfb8220 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -174,6 +174,7 @@ | |||
174 | "settings.navigation.inviteFriends": "Invite Friends", | 174 | "settings.navigation.inviteFriends": "Invite Friends", |
175 | "settings.navigation.logout": "Logout", | 175 | "settings.navigation.logout": "Logout", |
176 | "settings.navigation.settings": "Settings", | 176 | "settings.navigation.settings": "Settings", |
177 | "settings.navigation.team": "Manage Team", | ||
177 | "settings.navigation.yourServices": "Your services", | 178 | "settings.navigation.yourServices": "Your services", |
178 | "settings.navigation.yourWorkspaces": "Your workspaces", | 179 | "settings.navigation.yourWorkspaces": "Your workspaces", |
179 | "settings.recipes.all": "All services", | 180 | "settings.recipes.all": "All services", |
@@ -233,6 +234,12 @@ | |||
233 | "settings.services.tooltip.isMuted": "All sounds are muted", | 234 | "settings.services.tooltip.isMuted": "All sounds are muted", |
234 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", | 235 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", |
235 | "settings.services.updatedInfo": "Your changes have been saved", | 236 | "settings.services.updatedInfo": "Your changes have been saved", |
237 | "settings.team.contentHeadline": "Franz for Teams", | ||
238 | "settings.team.copy": "Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", | ||
239 | "settings.team.headline": "Team", | ||
240 | "settings.team.intro": "You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", | ||
241 | "settings.team.manageAction": "Manage your Team on meetfranz.com", | ||
242 | "settings.team.upgradeAction": "Upgrade your Account", | ||
236 | "settings.user.form.accountType.company": "Company", | 243 | "settings.user.form.accountType.company": "Company", |
237 | "settings.user.form.accountType.individual": "Individual", | 244 | "settings.user.form.accountType.individual": "Individual", |
238 | "settings.user.form.accountType.label": "Account type", | 245 | "settings.user.form.accountType.label": "Account type", |
@@ -317,4 +324,4 @@ | |||
317 | "workspaceDrawer.workspaceFeatureInfo": "<p>Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", | 324 | "workspaceDrawer.workspaceFeatureInfo": "<p>Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", |
318 | "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", | 325 | "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", |
319 | "workspaces.switchingIndicator.switchingTo": "Switching to" | 326 | "workspaces.switchingIndicator.switchingTo": "Switching to" |
320 | } \ No newline at end of file | 327 | } |
diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json index 603950395..22eaf0381 100644 --- a/src/i18n/messages/src/components/settings/account/AccountDashboard.json +++ b/src/i18n/messages/src/components/settings/account/AccountDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Account", | 4 | "defaultMessage": "!!!Account", |
5 | "file": "src/components/settings/account/AccountDashboard.js", | 5 | "file": "src/components/settings/account/AccountDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 15, | 7 | "line": 13, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 18, | 11 | "line": 16, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Your Subscription", | 17 | "defaultMessage": "!!!Your Subscription", |
18 | "file": "src/components/settings/account/AccountDashboard.js", | 18 | "file": "src/components/settings/account/AccountDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 19, | 20 | "line": 17, |
21 | "column": 24 | 21 | "column": 24 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 22, | 24 | "line": 20, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,24 +30,11 @@ | |||
30 | "defaultMessage": "!!!Upgrade your Account", | 30 | "defaultMessage": "!!!Upgrade your Account", |
31 | "file": "src/components/settings/account/AccountDashboard.js", | 31 | "file": "src/components/settings/account/AccountDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 23, | 33 | "line": 21, |
34 | "column": 19 | 34 | "column": 19 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 26, | 37 | "line": 24, |
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "settings.account.headlineInvoices", | ||
43 | "defaultMessage": "!!Invoices", | ||
44 | "file": "src/components/settings/account/AccountDashboard.js", | ||
45 | "start": { | ||
46 | "line": 27, | ||
47 | "column": 20 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 30, | ||
51 | "column": 3 | 38 | "column": 3 |
52 | } | 39 | } |
53 | }, | 40 | }, |
@@ -56,11 +43,11 @@ | |||
56 | "defaultMessage": "!!Danger Zone", | 43 | "defaultMessage": "!!Danger Zone", |
57 | "file": "src/components/settings/account/AccountDashboard.js", | 44 | "file": "src/components/settings/account/AccountDashboard.js", |
58 | "start": { | 45 | "start": { |
59 | "line": 31, | 46 | "line": 25, |
60 | "column": 22 | 47 | "column": 22 |
61 | }, | 48 | }, |
62 | "end": { | 49 | "end": { |
63 | "line": 34, | 50 | "line": 28, |
64 | "column": 3 | 51 | "column": 3 |
65 | } | 52 | } |
66 | }, | 53 | }, |
@@ -69,11 +56,11 @@ | |||
69 | "defaultMessage": "!!!Manage your subscription", | 56 | "defaultMessage": "!!!Manage your subscription", |
70 | "file": "src/components/settings/account/AccountDashboard.js", | 57 | "file": "src/components/settings/account/AccountDashboard.js", |
71 | "start": { | 58 | "start": { |
72 | "line": 35, | 59 | "line": 29, |
73 | "column": 33 | 60 | "column": 33 |
74 | }, | 61 | }, |
75 | "end": { | 62 | "end": { |
76 | "line": 38, | 63 | "line": 32, |
77 | "column": 3 | 64 | "column": 3 |
78 | } | 65 | } |
79 | }, | 66 | }, |
@@ -82,11 +69,11 @@ | |||
82 | "defaultMessage": "!!!Basic Account", | 69 | "defaultMessage": "!!!Basic Account", |
83 | "file": "src/components/settings/account/AccountDashboard.js", | 70 | "file": "src/components/settings/account/AccountDashboard.js", |
84 | "start": { | 71 | "start": { |
85 | "line": 39, | 72 | "line": 33, |
86 | "column": 20 | 73 | "column": 20 |
87 | }, | 74 | }, |
88 | "end": { | 75 | "end": { |
89 | "line": 42, | 76 | "line": 36, |
90 | "column": 3 | 77 | "column": 3 |
91 | } | 78 | } |
92 | }, | 79 | }, |
@@ -95,11 +82,11 @@ | |||
95 | "defaultMessage": "!!!Premium Supporter Account", | 82 | "defaultMessage": "!!!Premium Supporter Account", |
96 | "file": "src/components/settings/account/AccountDashboard.js", | 83 | "file": "src/components/settings/account/AccountDashboard.js", |
97 | "start": { | 84 | "start": { |
98 | "line": 43, | 85 | "line": 37, |
99 | "column": 22 | 86 | "column": 22 |
100 | }, | 87 | }, |
101 | "end": { | 88 | "end": { |
102 | "line": 46, | 89 | "line": 40, |
103 | "column": 3 | 90 | "column": 3 |
104 | } | 91 | } |
105 | }, | 92 | }, |
@@ -108,11 +95,24 @@ | |||
108 | "defaultMessage": "!!!Edit Account", | 95 | "defaultMessage": "!!!Edit Account", |
109 | "file": "src/components/settings/account/AccountDashboard.js", | 96 | "file": "src/components/settings/account/AccountDashboard.js", |
110 | "start": { | 97 | "start": { |
111 | "line": 47, | 98 | "line": 41, |
112 | "column": 21 | 99 | "column": 21 |
113 | }, | 100 | }, |
114 | "end": { | 101 | "end": { |
115 | "line": 50, | 102 | "line": 44, |
103 | "column": 3 | ||
104 | } | ||
105 | }, | ||
106 | { | ||
107 | "id": "settings.account.headlineInvoices", | ||
108 | "defaultMessage": "!!Invoices", | ||
109 | "file": "src/components/settings/account/AccountDashboard.js", | ||
110 | "start": { | ||
111 | "line": 45, | ||
112 | "column": 18 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 48, | ||
116 | "column": 3 | 116 | "column": 3 |
117 | } | 117 | } |
118 | }, | 118 | }, |
@@ -121,11 +121,11 @@ | |||
121 | "defaultMessage": "!!!Download", | 121 | "defaultMessage": "!!!Download", |
122 | "file": "src/components/settings/account/AccountDashboard.js", | 122 | "file": "src/components/settings/account/AccountDashboard.js", |
123 | "start": { | 123 | "start": { |
124 | "line": 51, | 124 | "line": 49, |
125 | "column": 19 | 125 | "column": 19 |
126 | }, | 126 | }, |
127 | "end": { | 127 | "end": { |
128 | "line": 54, | 128 | "line": 52, |
129 | "column": 3 | 129 | "column": 3 |
130 | } | 130 | } |
131 | }, | 131 | }, |
@@ -134,11 +134,11 @@ | |||
134 | "defaultMessage": "!!!Could not load user information", | 134 | "defaultMessage": "!!!Could not load user information", |
135 | "file": "src/components/settings/account/AccountDashboard.js", | 135 | "file": "src/components/settings/account/AccountDashboard.js", |
136 | "start": { | 136 | "start": { |
137 | "line": 55, | 137 | "line": 53, |
138 | "column": 25 | 138 | "column": 25 |
139 | }, | 139 | }, |
140 | "end": { | 140 | "end": { |
141 | "line": 58, | 141 | "line": 56, |
142 | "column": 3 | 142 | "column": 3 |
143 | } | 143 | } |
144 | }, | 144 | }, |
@@ -147,11 +147,11 @@ | |||
147 | "defaultMessage": "!!!Try again", | 147 | "defaultMessage": "!!!Try again", |
148 | "file": "src/components/settings/account/AccountDashboard.js", | 148 | "file": "src/components/settings/account/AccountDashboard.js", |
149 | "start": { | 149 | "start": { |
150 | "line": 59, | 150 | "line": 57, |
151 | "column": 28 | 151 | "column": 28 |
152 | }, | 152 | }, |
153 | "end": { | 153 | "end": { |
154 | "line": 62, | 154 | "line": 60, |
155 | "column": 3 | 155 | "column": 3 |
156 | } | 156 | } |
157 | }, | 157 | }, |
@@ -160,11 +160,11 @@ | |||
160 | "defaultMessage": "!!!Delete account", | 160 | "defaultMessage": "!!!Delete account", |
161 | "file": "src/components/settings/account/AccountDashboard.js", | 161 | "file": "src/components/settings/account/AccountDashboard.js", |
162 | "start": { | 162 | "start": { |
163 | "line": 63, | 163 | "line": 61, |
164 | "column": 17 | 164 | "column": 17 |
165 | }, | 165 | }, |
166 | "end": { | 166 | "end": { |
167 | "line": 66, | 167 | "line": 64, |
168 | "column": 3 | 168 | "column": 3 |
169 | } | 169 | } |
170 | }, | 170 | }, |
@@ -173,11 +173,11 @@ | |||
173 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", | 173 | "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", |
174 | "file": "src/components/settings/account/AccountDashboard.js", | 174 | "file": "src/components/settings/account/AccountDashboard.js", |
175 | "start": { | 175 | "start": { |
176 | "line": 67, | 176 | "line": 65, |
177 | "column": 14 | 177 | "column": 14 |
178 | }, | 178 | }, |
179 | "end": { | 179 | "end": { |
180 | "line": 70, | 180 | "line": 68, |
181 | "column": 3 | 181 | "column": 3 |
182 | } | 182 | } |
183 | }, | 183 | }, |
@@ -186,11 +186,11 @@ | |||
186 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", | 186 | "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", |
187 | "file": "src/components/settings/account/AccountDashboard.js", | 187 | "file": "src/components/settings/account/AccountDashboard.js", |
188 | "start": { | 188 | "start": { |
189 | "line": 71, | 189 | "line": 69, |
190 | "column": 19 | 190 | "column": 19 |
191 | }, | 191 | }, |
192 | "end": { | 192 | "end": { |
193 | "line": 74, | 193 | "line": 72, |
194 | "column": 3 | 194 | "column": 3 |
195 | } | 195 | } |
196 | } | 196 | } |
diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 77b0ed8a4..70a989211 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Available services", | 4 | "defaultMessage": "!!!Available services", |
5 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 5 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 12, | 7 | "line": 13, |
8 | "column": 21 | 8 | "column": 21 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 15, | 11 | "line": 16, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Your services", | 17 | "defaultMessage": "!!!Your services", |
18 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 18 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 16, | 20 | "line": 17, |
21 | "column": 16 | 21 | "column": 16 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 19, | 24 | "line": 20, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Your workspaces", | 30 | "defaultMessage": "!!!Your workspaces", |
31 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 31 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 20, | 33 | "line": 21, |
34 | "column": 18 | 34 | "column": 18 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 23, | 37 | "line": 24, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,24 @@ | |||
43 | "defaultMessage": "!!!Account", | 43 | "defaultMessage": "!!!Account", |
44 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 44 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 24, | 46 | "line": 25, |
47 | "column": 11 | 47 | "column": 11 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 27, | 50 | "line": 28, |
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "settings.navigation.team", | ||
56 | "defaultMessage": "!!!Manage Team", | ||
57 | "file": "src/components/settings/navigation/SettingsNavigation.js", | ||
58 | "start": { | ||
59 | "line": 29, | ||
60 | "column": 8 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 32, | ||
51 | "column": 3 | 64 | "column": 3 |
52 | } | 65 | } |
53 | }, | 66 | }, |
@@ -56,11 +69,11 @@ | |||
56 | "defaultMessage": "!!!Settings", | 69 | "defaultMessage": "!!!Settings", |
57 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 70 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
58 | "start": { | 71 | "start": { |
59 | "line": 28, | 72 | "line": 33, |
60 | "column": 12 | 73 | "column": 12 |
61 | }, | 74 | }, |
62 | "end": { | 75 | "end": { |
63 | "line": 31, | 76 | "line": 36, |
64 | "column": 3 | 77 | "column": 3 |
65 | } | 78 | } |
66 | }, | 79 | }, |
@@ -69,11 +82,11 @@ | |||
69 | "defaultMessage": "!!!Invite Friends", | 82 | "defaultMessage": "!!!Invite Friends", |
70 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 83 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
71 | "start": { | 84 | "start": { |
72 | "line": 32, | 85 | "line": 37, |
73 | "column": 17 | 86 | "column": 17 |
74 | }, | 87 | }, |
75 | "end": { | 88 | "end": { |
76 | "line": 35, | 89 | "line": 40, |
77 | "column": 3 | 90 | "column": 3 |
78 | } | 91 | } |
79 | }, | 92 | }, |
@@ -82,11 +95,11 @@ | |||
82 | "defaultMessage": "!!!Logout", | 95 | "defaultMessage": "!!!Logout", |
83 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 96 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
84 | "start": { | 97 | "start": { |
85 | "line": 36, | 98 | "line": 41, |
86 | "column": 10 | 99 | "column": 10 |
87 | }, | 100 | }, |
88 | "end": { | 101 | "end": { |
89 | "line": 39, | 102 | "line": 44, |
90 | "column": 3 | 103 | "column": 3 |
91 | } | 104 | } |
92 | } | 105 | } |
diff --git a/src/i18n/messages/src/components/settings/team/TeamDashboard.json b/src/i18n/messages/src/components/settings/team/TeamDashboard.json new file mode 100644 index 000000000..91b6754ea --- /dev/null +++ b/src/i18n/messages/src/components/settings/team/TeamDashboard.json | |||
@@ -0,0 +1,80 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "settings.team.headline", | ||
4 | "defaultMessage": "!!!Team", | ||
5 | "file": "src/components/settings/team/TeamDashboard.js", | ||
6 | "start": { | ||
7 | "line": 14, | ||
8 | "column": 12 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 17, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "settings.team.contentHeadline", | ||
17 | "defaultMessage": "!!!Franz for Teams", | ||
18 | "file": "src/components/settings/team/TeamDashboard.js", | ||
19 | "start": { | ||
20 | "line": 18, | ||
21 | "column": 19 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 21, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "settings.team.intro", | ||
30 | "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", | ||
31 | "file": "src/components/settings/team/TeamDashboard.js", | ||
32 | "start": { | ||
33 | "line": 22, | ||
34 | "column": 9 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 25, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "settings.team.copy", | ||
43 | "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", | ||
44 | "file": "src/components/settings/team/TeamDashboard.js", | ||
45 | "start": { | ||
46 | "line": 26, | ||
47 | "column": 8 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 29, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "settings.team.manageAction", | ||
56 | "defaultMessage": "!!!Manage your Team", | ||
57 | "file": "src/components/settings/team/TeamDashboard.js", | ||
58 | "start": { | ||
59 | "line": 30, | ||
60 | "column": 16 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 33, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "settings.team.upgradeAction", | ||
69 | "defaultMessage": "!!!Upgrade your Account", | ||
70 | "file": "src/components/settings/team/TeamDashboard.js", | ||
71 | "start": { | ||
72 | "line": 34, | ||
73 | "column": 17 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 37, | ||
77 | "column": 3 | ||
78 | } | ||
79 | } | ||
80 | ] \ No newline at end of file | ||
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 8fe576813..6200c9a16 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -14,6 +14,7 @@ import serviceProxy from '../features/serviceProxy'; | |||
14 | import basicAuth from '../features/basicAuth'; | 14 | import basicAuth from '../features/basicAuth'; |
15 | import workspaces from '../features/workspaces'; | 15 | import workspaces from '../features/workspaces'; |
16 | import shareFranz from '../features/shareFranz'; | 16 | import shareFranz from '../features/shareFranz'; |
17 | import settingsWS from '../features/settingsWS'; | ||
17 | 18 | ||
18 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 19 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
19 | 20 | ||
@@ -71,5 +72,6 @@ export default class FeaturesStore extends Store { | |||
71 | basicAuth(this.stores, this.actions); | 72 | basicAuth(this.stores, this.actions); |
72 | workspaces(this.stores, this.actions); | 73 | workspaces(this.stores, this.actions); |
73 | shareFranz(this.stores, this.actions); | 74 | shareFranz(this.stores, this.actions); |
75 | settingsWS(this.stores, this.actions); | ||
74 | } | 76 | } |
75 | } | 77 | } |
diff --git a/src/stores/PaymentStore.js b/src/stores/PaymentStore.js index 4cabee194..d4de476c8 100644 --- a/src/stores/PaymentStore.js +++ b/src/stores/PaymentStore.js | |||
@@ -10,15 +10,10 @@ export default class PaymentStore extends Store { | |||
10 | 10 | ||
11 | @observable createHostedPageRequest = new Request(this.api.payment, 'getHostedPage'); | 11 | @observable createHostedPageRequest = new Request(this.api.payment, 'getHostedPage'); |
12 | 12 | ||
13 | @observable createDashboardUrlRequest = new Request(this.api.payment, 'getDashboardUrl'); | ||
14 | |||
15 | @observable ordersDataRequest = new CachedRequest(this.api.payment, 'getOrders'); | ||
16 | |||
17 | constructor(...args) { | 13 | constructor(...args) { |
18 | super(...args); | 14 | super(...args); |
19 | 15 | ||
20 | this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); | 16 | this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); |
21 | this.actions.payment.createDashboardUrl.listen(this._createDashboardUrl.bind(this)); | ||
22 | } | 17 | } |
23 | 18 | ||
24 | @computed get plan() { | 19 | @computed get plan() { |
@@ -28,10 +23,6 @@ export default class PaymentStore extends Store { | |||
28 | return this.plansRequest.execute().result || {}; | 23 | return this.plansRequest.execute().result || {}; |
29 | } | 24 | } |
30 | 25 | ||
31 | @computed get orders() { | ||
32 | return this.ordersDataRequest.execute().result || []; | ||
33 | } | ||
34 | |||
35 | @action _createHostedPage({ planId }) { | 26 | @action _createHostedPage({ planId }) { |
36 | const request = this.createHostedPageRequest.execute(planId); | 27 | const request = this.createHostedPageRequest.execute(planId); |
37 | 28 | ||
@@ -39,12 +30,4 @@ export default class PaymentStore extends Store { | |||
39 | 30 | ||
40 | return request; | 31 | return request; |
41 | } | 32 | } |
42 | |||
43 | @action _createDashboardUrl() { | ||
44 | const request = this.createDashboardUrlRequest.execute(); | ||
45 | |||
46 | gaEvent('Payment', 'createDashboardUrl'); | ||
47 | |||
48 | return request; | ||
49 | } | ||
50 | } | 33 | } |
diff --git a/src/styles/badge.scss b/src/styles/badge.scss index f9fac039a..be3a1055d 100644 --- a/src/styles/badge.scss +++ b/src/styles/badge.scss | |||
@@ -19,6 +19,7 @@ | |||
19 | display: inline-block; | 19 | display: inline-block; |
20 | font-size: 14px; | 20 | font-size: 14px; |
21 | padding: 5px 10px; | 21 | padding: 5px 10px; |
22 | letter-spacing: 0; | ||
22 | 23 | ||
23 | &.badge--primary, | 24 | &.badge--primary, |
24 | &.badge--premium { | 25 | &.badge--premium { |
diff --git a/src/styles/settings.scss b/src/styles/settings.scss index dd6f56d2b..efa0ab942 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -62,9 +62,14 @@ | |||
62 | .account { | 62 | .account { |
63 | .account__box { background: $dark-theme-gray-darker; } | 63 | .account__box { background: $dark-theme-gray-darker; } |
64 | 64 | ||
65 | .invoices { | 65 | .badge--premium { |
66 | td { border-bottom: 1px solid $dark-theme-gray-darker; } | 66 | margin-left: 10px; |
67 | .invoices__action button { color: $theme-brand-primary; } | 67 | } |
68 | |||
69 | .manage-user-links { | ||
70 | margin-top: 20px; | ||
71 | display: flex; | ||
72 | justify-content: space-between; | ||
68 | } | 73 | } |
69 | } | 74 | } |
70 | 75 | ||