diff options
25 files changed, 839 insertions, 283 deletions
diff --git a/package-lock.json b/package-lock.json index 70f3b2484..ab505e904 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -2976,6 +2976,11 @@ | |||
2976 | "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", | 2976 | "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", |
2977 | "dev": true | 2977 | "dev": true |
2978 | }, | 2978 | }, |
2979 | "async-limiter": { | ||
2980 | "version": "1.0.0", | ||
2981 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", | ||
2982 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" | ||
2983 | }, | ||
2979 | "async-settle": { | 2984 | "async-settle": { |
2980 | "version": "1.0.0", | 2985 | "version": "1.0.0", |
2981 | "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", | 2986 | "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", |
@@ -6525,6 +6530,16 @@ | |||
6525 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", | 6530 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", |
6526 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", | 6531 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", |
6527 | "dev": true | 6532 | "dev": true |
6533 | }, | ||
6534 | "ws": { | ||
6535 | "version": "1.1.5", | ||
6536 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", | ||
6537 | "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", | ||
6538 | "dev": true, | ||
6539 | "requires": { | ||
6540 | "options": ">=0.0.5", | ||
6541 | "ultron": "1.0.x" | ||
6542 | } | ||
6528 | } | 6543 | } |
6529 | } | 6544 | } |
6530 | }, | 6545 | }, |
@@ -6562,6 +6577,16 @@ | |||
6562 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", | 6577 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", |
6563 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", | 6578 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", |
6564 | "dev": true | 6579 | "dev": true |
6580 | }, | ||
6581 | "ws": { | ||
6582 | "version": "1.1.5", | ||
6583 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", | ||
6584 | "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", | ||
6585 | "dev": true, | ||
6586 | "requires": { | ||
6587 | "options": ">=0.0.5", | ||
6588 | "ultron": "1.0.x" | ||
6589 | } | ||
6565 | } | 6590 | } |
6566 | } | 6591 | } |
6567 | }, | 6592 | }, |
@@ -19305,13 +19330,11 @@ | |||
19305 | } | 19330 | } |
19306 | }, | 19331 | }, |
19307 | "ws": { | 19332 | "ws": { |
19308 | "version": "1.1.5", | 19333 | "version": "6.2.1", |
19309 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", | 19334 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", |
19310 | "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", | 19335 | "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", |
19311 | "dev": true, | ||
19312 | "requires": { | 19336 | "requires": { |
19313 | "options": ">=0.0.5", | 19337 | "async-limiter": "~1.0.0" |
19314 | "ultron": "1.0.x" | ||
19315 | } | 19338 | } |
19316 | }, | 19339 | }, |
19317 | "wtf-8": { | 19340 | "wtf-8": { |
diff --git a/package.json b/package.json index c43e0b3a9..948e4b6cc 100644 --- a/package.json +++ b/package.json | |||
@@ -83,7 +83,8 @@ | |||
83 | "semver": "^5.4.1", | 83 | "semver": "^5.4.1", |
84 | "smoothscroll-polyfill": "^0.3.4", | 84 | "smoothscroll-polyfill": "^0.3.4", |
85 | "tar": "^4.0.2", | 85 | "tar": "^4.0.2", |
86 | "uuid": "^3.0.1" | 86 | "uuid": "^3.0.1", |
87 | "ws": "6.2.1" | ||
87 | }, | 88 | }, |
88 | "devDependencies": { | 89 | "devDependencies": { |
89 | "@adlk/misty": "^0.1.1", | 90 | "@adlk/misty": "^0.1.1", |
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 ab27e92bf..a9ce202ff 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..3f6964b6b 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -3,12 +3,11 @@ 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'; | 6 | import { ProBadge } from '@meetfranz/ui'; |
7 | 7 | ||
8 | import Loader from '../../ui/Loader'; | 8 | import Loader from '../../ui/Loader'; |
9 | import Button from '../../ui/Button'; | 9 | import Button from '../../ui/Button'; |
10 | import Infobox from '../../ui/Infobox'; | 10 | import Infobox from '../../ui/Infobox'; |
11 | import Link from '../../ui/Link'; | ||
12 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; | 11 | import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; |
13 | 12 | ||
14 | const messages = defineMessages({ | 13 | const messages = defineMessages({ |
@@ -24,10 +23,6 @@ const messages = defineMessages({ | |||
24 | id: 'settings.account.headlineUpgrade', | 23 | id: 'settings.account.headlineUpgrade', |
25 | defaultMessage: '!!!Upgrade your Account', | 24 | defaultMessage: '!!!Upgrade your Account', |
26 | }, | 25 | }, |
27 | headlineInvoices: { | ||
28 | id: 'settings.account.headlineInvoices', | ||
29 | defaultMessage: '!!Invoices', | ||
30 | }, | ||
31 | headlineDangerZone: { | 26 | headlineDangerZone: { |
32 | id: 'settings.account.headlineDangerZone', | 27 | id: 'settings.account.headlineDangerZone', |
33 | defaultMessage: '!!Danger Zone', | 28 | defaultMessage: '!!Danger Zone', |
@@ -48,6 +43,10 @@ const messages = defineMessages({ | |||
48 | id: 'settings.account.account.editButton', | 43 | id: 'settings.account.account.editButton', |
49 | defaultMessage: '!!!Edit Account', | 44 | defaultMessage: '!!!Edit Account', |
50 | }, | 45 | }, |
46 | invoicesButton: { | ||
47 | id: 'settings.account.headlineInvoices', | ||
48 | defaultMessage: '!!Invoices', | ||
49 | }, | ||
51 | invoiceDownload: { | 50 | invoiceDownload: { |
52 | id: 'settings.account.invoiceDownload', | 51 | id: 'settings.account.invoiceDownload', |
53 | defaultMessage: '!!!Download', | 52 | defaultMessage: '!!!Download', |
@@ -77,19 +76,17 @@ const messages = defineMessages({ | |||
77 | export default @observer class AccountDashboard extends Component { | 76 | export default @observer class AccountDashboard extends Component { |
78 | static propTypes = { | 77 | static propTypes = { |
79 | user: MobxPropTypes.observableObject.isRequired, | 78 | user: MobxPropTypes.observableObject.isRequired, |
80 | orders: MobxPropTypes.arrayOrObservableArray.isRequired, | ||
81 | isLoading: PropTypes.bool.isRequired, | 79 | isLoading: PropTypes.bool.isRequired, |
82 | isLoadingOrdersInfo: PropTypes.bool.isRequired, | ||
83 | isLoadingPlans: PropTypes.bool.isRequired, | 80 | isLoadingPlans: PropTypes.bool.isRequired, |
84 | isCreatingPaymentDashboardUrl: PropTypes.bool.isRequired, | ||
85 | userInfoRequestFailed: PropTypes.bool.isRequired, | 81 | userInfoRequestFailed: PropTypes.bool.isRequired, |
86 | retryUserInfoRequest: PropTypes.func.isRequired, | 82 | retryUserInfoRequest: PropTypes.func.isRequired, |
87 | openDashboard: PropTypes.func.isRequired, | ||
88 | openExternalUrl: PropTypes.func.isRequired, | ||
89 | onCloseSubscriptionWindow: PropTypes.func.isRequired, | 83 | onCloseSubscriptionWindow: PropTypes.func.isRequired, |
90 | deleteAccount: PropTypes.func.isRequired, | 84 | deleteAccount: PropTypes.func.isRequired, |
91 | isLoadingDeleteAccount: PropTypes.bool.isRequired, | 85 | isLoadingDeleteAccount: PropTypes.bool.isRequired, |
92 | isDeleteAccountSuccessful: PropTypes.bool.isRequired, | 86 | isDeleteAccountSuccessful: PropTypes.bool.isRequired, |
87 | openEditAccount: PropTypes.func.isRequired, | ||
88 | openBilling: PropTypes.func.isRequired, | ||
89 | openInvoices: PropTypes.func.isRequired, | ||
93 | }; | 90 | }; |
94 | 91 | ||
95 | static contextTypes = { | 92 | static contextTypes = { |
@@ -99,12 +96,7 @@ export default @observer class AccountDashboard extends Component { | |||
99 | render() { | 96 | render() { |
100 | const { | 97 | const { |
101 | user, | 98 | user, |
102 | orders, | ||
103 | isLoading, | 99 | isLoading, |
104 | isCreatingPaymentDashboardUrl, | ||
105 | openDashboard, | ||
106 | openExternalUrl, | ||
107 | isLoadingOrdersInfo, | ||
108 | isLoadingPlans, | 100 | isLoadingPlans, |
109 | userInfoRequestFailed, | 101 | userInfoRequestFailed, |
110 | retryUserInfoRequest, | 102 | retryUserInfoRequest, |
@@ -112,6 +104,9 @@ export default @observer class AccountDashboard extends Component { | |||
112 | deleteAccount, | 104 | deleteAccount, |
113 | isLoadingDeleteAccount, | 105 | isLoadingDeleteAccount, |
114 | isDeleteAccountSuccessful, | 106 | isDeleteAccountSuccessful, |
107 | openEditAccount, | ||
108 | openBilling, | ||
109 | openInvoices, | ||
115 | } = this.props; | 110 | } = this.props; |
116 | const { intl } = this.context; | 111 | const { intl } = this.context; |
117 | 112 | ||
@@ -149,80 +144,53 @@ export default @observer class AccountDashboard extends Component { | |||
149 | src="./assets/images/logo.svg" | 144 | src="./assets/images/logo.svg" |
150 | alt="" | 145 | alt="" |
151 | /> | 146 | /> |
152 | {user.isPremium && ( | ||
153 | <span | ||
154 | className="account__avatar-premium emoji" | ||
155 | data-tip="Premium Supporter Account" | ||
156 | > | ||
157 | <img src="./assets/images/emoji/star.png" alt="" /> | ||
158 | </span> | ||
159 | )} | ||
160 | </div> | 147 | </div> |
161 | <div className="account__info"> | 148 | <div className="account__info"> |
162 | <h2> | 149 | <h2> |
163 | {`${user.firstname} ${user.lastname}`} | 150 | <span className="username">{`${user.firstname} ${user.lastname}`}</span> |
151 | {user.isPremium && ( | ||
152 | <> | ||
153 | {' '} | ||
154 | <ProBadge /> | ||
155 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | ||
156 | </> | ||
157 | )} | ||
164 | </h2> | 158 | </h2> |
165 | {user.organization && `${user.organization}, `} | 159 | {user.organization && `${user.organization}, `} |
166 | {user.email} | 160 | {user.email} |
167 | <br /> | ||
168 | {user.isPremium && ( | 161 | {user.isPremium && ( |
169 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | 162 | <div className="manage-user-links"> |
163 | <Button | ||
164 | label={intl.formatMessage(messages.accountEditButton)} | ||
165 | className="franz-form__button--inverted" | ||
166 | onClick={openEditAccount} | ||
167 | /> | ||
168 | {user.isSubscriptionOwner && ( | ||
169 | <> | ||
170 | <Button | ||
171 | label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} | ||
172 | className="franz-form__button--inverted" | ||
173 | onClick={openBilling} | ||
174 | /> | ||
175 | <Button | ||
176 | label={intl.formatMessage(messages.invoicesButton)} | ||
177 | className="franz-form__button--inverted" | ||
178 | onClick={openInvoices} | ||
179 | /> | ||
180 | </> | ||
181 | )} | ||
182 | </div> | ||
170 | )} | 183 | )} |
171 | </div> | 184 | </div> |
172 | <Link to="/settings/user/edit" className="button"> | 185 | {!user.isPremium && ( |
173 | {intl.formatMessage(messages.accountEditButton)} | 186 | <Button |
174 | </Link> | 187 | label={intl.formatMessage(messages.accountEditButton)} |
175 | {user.emailValidated} | 188 | className="franz-form__button--inverted" |
176 | </div> | 189 | onClick={openEditAccount} |
177 | </div> | 190 | /> |
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 | )} | 191 | )} |
224 | </div> | 192 | </div> |
225 | ) | 193 | </div> |
226 | )} | 194 | )} |
227 | 195 | ||
228 | {!user.isPremium && ( | 196 | {!user.isPremium && ( |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 993b0a44a..df4b3b3b2 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -7,6 +7,7 @@ import { ProBadge } from '@meetfranz/ui'; | |||
7 | import Link from '../../ui/Link'; | 7 | import Link from '../../ui/Link'; |
8 | import { workspaceStore } from '../../../features/workspaces'; | 8 | import { workspaceStore } from '../../../features/workspaces'; |
9 | import UIStore from '../../../stores/UIStore'; | 9 | import UIStore from '../../../stores/UIStore'; |
10 | import UserStore from '../../../stores/UserStore'; | ||
10 | 11 | ||
11 | const messages = defineMessages({ | 12 | const messages = defineMessages({ |
12 | availableServices: { | 13 | availableServices: { |
@@ -25,6 +26,10 @@ const messages = defineMessages({ | |||
25 | id: 'settings.navigation.account', | 26 | id: 'settings.navigation.account', |
26 | defaultMessage: '!!!Account', | 27 | defaultMessage: '!!!Account', |
27 | }, | 28 | }, |
29 | team: { | ||
30 | id: 'settings.navigation.team', | ||
31 | defaultMessage: '!!!Manage Team', | ||
32 | }, | ||
28 | settings: { | 33 | settings: { |
29 | id: 'settings.navigation.settings', | 34 | id: 'settings.navigation.settings', |
30 | defaultMessage: '!!!Settings', | 35 | defaultMessage: '!!!Settings', |
@@ -43,6 +48,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
43 | static propTypes = { | 48 | static propTypes = { |
44 | stores: PropTypes.shape({ | 49 | stores: PropTypes.shape({ |
45 | ui: PropTypes.instanceOf(UIStore).isRequired, | 50 | ui: PropTypes.instanceOf(UIStore).isRequired, |
51 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
46 | }).isRequired, | 52 | }).isRequired, |
47 | serviceCount: PropTypes.number.isRequired, | 53 | serviceCount: PropTypes.number.isRequired, |
48 | workspaceCount: PropTypes.number.isRequired, | 54 | workspaceCount: PropTypes.number.isRequired, |
@@ -55,6 +61,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
55 | render() { | 61 | render() { |
56 | const { serviceCount, workspaceCount, stores } = this.props; | 62 | const { serviceCount, workspaceCount, stores } = this.props; |
57 | const { isDarkThemeActive } = stores.ui; | 63 | const { isDarkThemeActive } = stores.ui; |
64 | const { router, user } = stores; | ||
58 | const { intl } = this.context; | 65 | const { intl } = this.context; |
59 | 66 | ||
60 | return ( | 67 | return ( |
@@ -98,6 +105,16 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
98 | {intl.formatMessage(messages.account)} | 105 | {intl.formatMessage(messages.account)} |
99 | </Link> | 106 | </Link> |
100 | <Link | 107 | <Link |
108 | to="/settings/team" | ||
109 | className="settings-navigation__link" | ||
110 | activeClassName="is-active" | ||
111 | > | ||
112 | {intl.formatMessage(messages.team)} | ||
113 | {!user.data.isPremium && ( | ||
114 | <ProBadge inverted={!isDarkThemeActive && router.location.pathname === '/settings/team'} /> | ||
115 | )} | ||
116 | </Link> | ||
117 | <Link | ||
101 | to="/settings/app" | 118 | to="/settings/app" |
102 | className="settings-navigation__link" | 119 | className="settings-navigation__link" |
103 | activeClassName="is-active" | 120 | 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..82c517fcb --- /dev/null +++ b/src/components/settings/team/TeamDashboard.js | |||
@@ -0,0 +1,152 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } 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 on meetfranz.com', | ||
33 | }, | ||
34 | upgradeButton: { | ||
35 | id: 'settings.team.upgradeAction', | ||
36 | defaultMessage: '!!!Upgrade your Account', | ||
37 | }, | ||
38 | }); | ||
39 | |||
40 | const styles = { | ||
41 | cta: { | ||
42 | margin: [40, 'auto'], | ||
43 | }, | ||
44 | container: { | ||
45 | display: 'flex', | ||
46 | flexDirection: 'column', | ||
47 | height: 'auto', | ||
48 | |||
49 | '@media(min-width: 800px)': { | ||
50 | flexDirection: 'row', | ||
51 | }, | ||
52 | }, | ||
53 | content: { | ||
54 | height: 'auto', | ||
55 | order: 1, | ||
56 | |||
57 | '@media(min-width: 800px)': { | ||
58 | order: 0, | ||
59 | }, | ||
60 | }, | ||
61 | image: { | ||
62 | display: 'block', | ||
63 | height: 150, | ||
64 | order: 0, | ||
65 | margin: [0, 'auto', 40, 'auto'], | ||
66 | |||
67 | '@media(min-width: 800px)': { | ||
68 | marginLeft: 40, | ||
69 | order: 1, | ||
70 | }, | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | |||
75 | export default @injectSheet(styles) @observer class TeamDashboard extends Component { | ||
76 | static propTypes = { | ||
77 | isLoading: PropTypes.bool.isRequired, | ||
78 | userInfoRequestFailed: PropTypes.bool.isRequired, | ||
79 | retryUserInfoRequest: PropTypes.func.isRequired, | ||
80 | openTeamManagement: PropTypes.func.isRequired, | ||
81 | classes: PropTypes.object.isRequired, | ||
82 | }; | ||
83 | |||
84 | static contextTypes = { | ||
85 | intl: intlShape, | ||
86 | }; | ||
87 | |||
88 | render() { | ||
89 | const { | ||
90 | isLoading, | ||
91 | userInfoRequestFailed, | ||
92 | retryUserInfoRequest, | ||
93 | openTeamManagement, | ||
94 | classes, | ||
95 | } = this.props; | ||
96 | const { intl } = this.context; | ||
97 | |||
98 | return ( | ||
99 | <div className="settings__main"> | ||
100 | <div className="settings__header"> | ||
101 | <span className="settings__header-item"> | ||
102 | {intl.formatMessage(messages.headline)} | ||
103 | </span> | ||
104 | </div> | ||
105 | <div className="settings__body"> | ||
106 | {isLoading && ( | ||
107 | <Loader /> | ||
108 | )} | ||
109 | |||
110 | {!isLoading && userInfoRequestFailed && ( | ||
111 | <Infobox | ||
112 | icon="alert" | ||
113 | type="danger" | ||
114 | ctaLabel={intl.formatMessage(messages.tryReloadUserInfoRequest)} | ||
115 | ctaLoading={isLoading} | ||
116 | ctaOnClick={retryUserInfoRequest} | ||
117 | > | ||
118 | {intl.formatMessage(messages.userInfoRequestFailed)} | ||
119 | </Infobox> | ||
120 | )} | ||
121 | |||
122 | {!userInfoRequestFailed && ( | ||
123 | <> | ||
124 | {!isLoading && ( | ||
125 | <> | ||
126 | <PremiumFeatureContainer> | ||
127 | <> | ||
128 | <h1>{intl.formatMessage(messages.contentHeadline)}</h1> | ||
129 | <div className={classes.container}> | ||
130 | <div className={classes.content}> | ||
131 | <p>{intl.formatMessage(messages.intro)}</p> | ||
132 | <p>{intl.formatMessage(messages.copy)}</p> | ||
133 | </div> | ||
134 | <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Franz for Teams" /> | ||
135 | </div> | ||
136 | <Button | ||
137 | label={intl.formatMessage(messages.manageButton)} | ||
138 | onClick={openTeamManagement} | ||
139 | className={classes.cta} | ||
140 | /> | ||
141 | </> | ||
142 | </PremiumFeatureContainer> | ||
143 | </> | ||
144 | )} | ||
145 | </> | ||
146 | )} | ||
147 | </div> | ||
148 | <ReactTooltip place="right" type="dark" effect="solid" /> | ||
149 | </div> | ||
150 | ); | ||
151 | } | ||
152 | } | ||
diff --git a/src/config.js b/src/config.js index 3b5ce7dda..5bc318545 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -9,10 +9,21 @@ const app = process.type === 'renderer' ? electron.remote.app : electron.app; | |||
9 | const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences; | 9 | const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences; |
10 | 10 | ||
11 | export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks | 11 | export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks |
12 | |||
12 | export const LOCAL_API = 'http://localhost:3000'; | 13 | export const LOCAL_API = 'http://localhost:3000'; |
13 | export const DEV_API = 'https://dev.franzinfra.com'; | 14 | export const DEV_API = 'https://dev.franzinfra.com'; |
14 | export const LIVE_API = 'https://api.franzinfra.com'; | 15 | export const LIVE_API = 'https://api.franzinfra.com'; |
16 | |||
17 | export const LOCAL_WS_API = 'ws://localhost:3000'; | ||
18 | export const DEV_WS_API = 'wss://dev.franzinfra.com'; | ||
19 | export const LIVE_WS_API = 'wss://api.franzinfra.com'; | ||
20 | |||
21 | export const LOCAL_API_WEBSITE = 'http://localhost:3333'; | ||
22 | export const DEV_API_WEBSITE = 'https://meetfranz.com'; | ||
23 | export const LIVE_API_WEBSITE = 'https://meetfranz.com'; | ||
24 | |||
15 | export const STATS_API = 'https://stats.franzinfra.com'; | 25 | export const STATS_API = 'https://stats.franzinfra.com'; |
26 | |||
16 | export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; | 27 | export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; |
17 | 28 | ||
18 | export const DEFAULT_APP_SETTINGS = { | 29 | 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..c69d5ad08 --- /dev/null +++ b/src/containers/settings/TeamScreen.js | |||
@@ -0,0 +1,57 @@ | |||
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 | isLoading={isLoadingUserInfo} | ||
31 | userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} | ||
32 | retryUserInfoRequest={() => this.reloadData()} | ||
33 | openTeamManagement={() => this.handleWebsiteLink('/user/team')} | ||
34 | /> | ||
35 | </ErrorBoundary> | ||
36 | ); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | TeamScreen.wrappedComponent.propTypes = { | ||
41 | stores: PropTypes.shape({ | ||
42 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
43 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
44 | }).isRequired, | ||
45 | actions: PropTypes.shape({ | ||
46 | payment: PropTypes.shape({ | ||
47 | createDashboardUrl: PropTypes.func.isRequired, | ||
48 | }).isRequired, | ||
49 | app: PropTypes.shape({ | ||
50 | openExternalUrl: PropTypes.func.isRequired, | ||
51 | }).isRequired, | ||
52 | user: PropTypes.shape({ | ||
53 | update: PropTypes.func.isRequired, | ||
54 | delete: PropTypes.func.isRequired, | ||
55 | }).isRequired, | ||
56 | }).isRequired, | ||
57 | }; | ||
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..4049ae814 --- /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 initSettingsWebSocket(stores, actions) { | ||
10 | const { features } = stores; | ||
11 | |||
12 | // Toggle SettingsWebSocket 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..0f1feebb9 --- /dev/null +++ b/src/features/settingsWS/store.js | |||
@@ -0,0 +1,120 @@ | |||
1 | import { observable } 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 | this.registerReactions([ | ||
24 | this._initialize.bind(this), | ||
25 | this._reconnect.bind(this), | ||
26 | this._close.bind(this), | ||
27 | ]); | ||
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 | // Reactions | ||
91 | |||
92 | _initialize() { | ||
93 | if (this.stores.user.data.id) { | ||
94 | this.connect(); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | _reconnect() { | ||
99 | if (!this.connected) { | ||
100 | debug('Trying to reconnect in 30s'); | ||
101 | this.reconnectTimeout = setInterval(() => { | ||
102 | debug('Trying to reconnect'); | ||
103 | this.connect(); | ||
104 | }, ms('30s')); | ||
105 | } else { | ||
106 | debug('Clearing reconnect interval'); | ||
107 | clearInterval(this.reconnectTimeout); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | _close() { | ||
112 | if (!this.stores.user.isLoggedIn && this.ws) { | ||
113 | debug('Terminating connection'); | ||
114 | this.ws.terminate(); | ||
115 | this.ws = null; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | export default SettingsWSStore; | ||
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 910dac727..9c9dee340 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, |
@@ -2257,6 +2270,89 @@ | |||
2257 | { | 2270 | { |
2258 | "descriptors": [ | 2271 | "descriptors": [ |
2259 | { | 2272 | { |
2273 | "defaultMessage": "!!!Team", | ||
2274 | "end": { | ||
2275 | "column": 3, | ||
2276 | "line": 17 | ||
2277 | }, | ||
2278 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2279 | "id": "settings.team.headline", | ||
2280 | "start": { | ||
2281 | "column": 12, | ||
2282 | "line": 14 | ||
2283 | } | ||
2284 | }, | ||
2285 | { | ||
2286 | "defaultMessage": "!!!Franz for Teams", | ||
2287 | "end": { | ||
2288 | "column": 3, | ||
2289 | "line": 21 | ||
2290 | }, | ||
2291 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2292 | "id": "settings.team.contentHeadline", | ||
2293 | "start": { | ||
2294 | "column": 19, | ||
2295 | "line": 18 | ||
2296 | } | ||
2297 | }, | ||
2298 | { | ||
2299 | "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.", | ||
2300 | "end": { | ||
2301 | "column": 3, | ||
2302 | "line": 25 | ||
2303 | }, | ||
2304 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2305 | "id": "settings.team.intro", | ||
2306 | "start": { | ||
2307 | "column": 9, | ||
2308 | "line": 22 | ||
2309 | } | ||
2310 | }, | ||
2311 | { | ||
2312 | "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!", | ||
2313 | "end": { | ||
2314 | "column": 3, | ||
2315 | "line": 29 | ||
2316 | }, | ||
2317 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2318 | "id": "settings.team.copy", | ||
2319 | "start": { | ||
2320 | "column": 8, | ||
2321 | "line": 26 | ||
2322 | } | ||
2323 | }, | ||
2324 | { | ||
2325 | "defaultMessage": "!!!Manage your Team", | ||
2326 | "end": { | ||
2327 | "column": 3, | ||
2328 | "line": 33 | ||
2329 | }, | ||
2330 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2331 | "id": "settings.team.manageAction", | ||
2332 | "start": { | ||
2333 | "column": 16, | ||
2334 | "line": 30 | ||
2335 | } | ||
2336 | }, | ||
2337 | { | ||
2338 | "defaultMessage": "!!!Upgrade your Account", | ||
2339 | "end": { | ||
2340 | "column": 3, | ||
2341 | "line": 37 | ||
2342 | }, | ||
2343 | "file": "src/components/settings/team/TeamDashboard.js", | ||
2344 | "id": "settings.team.upgradeAction", | ||
2345 | "start": { | ||
2346 | "column": 17, | ||
2347 | "line": 34 | ||
2348 | } | ||
2349 | } | ||
2350 | ], | ||
2351 | "path": "src/components/settings/team/TeamDashboard.json" | ||
2352 | }, | ||
2353 | { | ||
2354 | "descriptors": [ | ||
2355 | { | ||
2260 | "defaultMessage": "!!!Account", | 2356 | "defaultMessage": "!!!Account", |
2261 | "end": { | 2357 | "end": { |
2262 | "column": 3, | 2358 | "column": 3, |
@@ -4504,4 +4600,4 @@ | |||
4504 | ], | 4600 | ], |
4505 | "path": "src/lib/Menu.json" | 4601 | "path": "src/lib/Menu.json" |
4506 | } | 4602 | } |
4507 | ] \ No newline at end of file | 4603 | ] |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 1090584c2..1d8fb8d18 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -177,6 +177,7 @@ | |||
177 | "settings.navigation.inviteFriends": "Invite Friends", | 177 | "settings.navigation.inviteFriends": "Invite Friends", |
178 | "settings.navigation.logout": "Logout", | 178 | "settings.navigation.logout": "Logout", |
179 | "settings.navigation.settings": "Settings", | 179 | "settings.navigation.settings": "Settings", |
180 | "settings.navigation.team": "Manage Team", | ||
180 | "settings.navigation.yourServices": "Your services", | 181 | "settings.navigation.yourServices": "Your services", |
181 | "settings.navigation.yourWorkspaces": "Your workspaces", | 182 | "settings.navigation.yourWorkspaces": "Your workspaces", |
182 | "settings.recipes.all": "All services", | 183 | "settings.recipes.all": "All services", |
@@ -236,6 +237,12 @@ | |||
236 | "settings.services.tooltip.isMuted": "All sounds are muted", | 237 | "settings.services.tooltip.isMuted": "All sounds are muted", |
237 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", | 238 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", |
238 | "settings.services.updatedInfo": "Your changes have been saved", | 239 | "settings.services.updatedInfo": "Your changes have been saved", |
240 | "settings.team.contentHeadline": "Franz for Teams", | ||
241 | "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!", | ||
242 | "settings.team.headline": "Team", | ||
243 | "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.", | ||
244 | "settings.team.manageAction": "Manage your Team on meetfranz.com", | ||
245 | "settings.team.upgradeAction": "Upgrade your Account", | ||
239 | "settings.user.form.accountType.company": "Company", | 246 | "settings.user.form.accountType.company": "Company", |
240 | "settings.user.form.accountType.individual": "Individual", | 247 | "settings.user.form.accountType.individual": "Individual", |
241 | "settings.user.form.accountType.label": "Account type", | 248 | "settings.user.form.accountType.label": "Account type", |
diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json index 603950395..4969db910 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": 14, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 18, | 11 | "line": 17, |
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": 18, |
21 | "column": 24 | 21 | "column": 24 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 22, | 24 | "line": 21, |
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": 22, |
34 | "column": 19 | 34 | "column": 19 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 26, | 37 | "line": 25, |
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": 26, |
60 | "column": 22 | 47 | "column": 22 |
61 | }, | 48 | }, |
62 | "end": { | 49 | "end": { |
63 | "line": 34, | 50 | "line": 29, |
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": 30, |
73 | "column": 33 | 60 | "column": 33 |
74 | }, | 61 | }, |
75 | "end": { | 62 | "end": { |
76 | "line": 38, | 63 | "line": 33, |
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": 34, |
86 | "column": 20 | 73 | "column": 20 |
87 | }, | 74 | }, |
88 | "end": { | 75 | "end": { |
89 | "line": 42, | 76 | "line": 37, |
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": 38, |
99 | "column": 22 | 86 | "column": 22 |
100 | }, | 87 | }, |
101 | "end": { | 88 | "end": { |
102 | "line": 46, | 89 | "line": 41, |
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": 42, |
112 | "column": 21 | 99 | "column": 21 |
113 | }, | 100 | }, |
114 | "end": { | 101 | "end": { |
115 | "line": 50, | 102 | "line": 45, |
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": 46, | ||
112 | "column": 18 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 49, | ||
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": 50, |
125 | "column": 19 | 125 | "column": 19 |
126 | }, | 126 | }, |
127 | "end": { | 127 | "end": { |
128 | "line": 54, | 128 | "line": 53, |
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": 54, |
138 | "column": 25 | 138 | "column": 25 |
139 | }, | 139 | }, |
140 | "end": { | 140 | "end": { |
141 | "line": 58, | 141 | "line": 57, |
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": 58, |
151 | "column": 28 | 151 | "column": 28 |
152 | }, | 152 | }, |
153 | "end": { | 153 | "end": { |
154 | "line": 62, | 154 | "line": 61, |
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": 62, |
164 | "column": 17 | 164 | "column": 17 |
165 | }, | 165 | }, |
166 | "end": { | 166 | "end": { |
167 | "line": 66, | 167 | "line": 65, |
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": 66, |
177 | "column": 14 | 177 | "column": 14 |
178 | }, | 178 | }, |
179 | "end": { | 179 | "end": { |
180 | "line": 70, | 180 | "line": 69, |
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": 70, |
190 | "column": 19 | 190 | "column": 19 |
191 | }, | 191 | }, |
192 | "end": { | 192 | "end": { |
193 | "line": 74, | 193 | "line": 73, |
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..6bccc25ff --- /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 on meetfranz.com", | ||
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 dcda021c1..e7832088b 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -15,6 +15,7 @@ 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 announcements from '../features/announcements'; | 17 | import announcements from '../features/announcements'; |
18 | import settingsWS from '../features/settingsWS'; | ||
18 | 19 | ||
19 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 20 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
20 | 21 | ||
@@ -73,5 +74,6 @@ export default class FeaturesStore extends Store { | |||
73 | workspaces(this.stores, this.actions); | 74 | workspaces(this.stores, this.actions); |
74 | shareFranz(this.stores, this.actions); | 75 | shareFranz(this.stores, this.actions); |
75 | announcements(this.stores, this.actions); | 76 | announcements(this.stores, this.actions); |
77 | settingsWS(this.stores, this.actions); | ||
76 | } | 78 | } |
77 | } | 79 | } |
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..1baff8b54 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -61,11 +61,6 @@ | |||
61 | 61 | ||
62 | .account { | 62 | .account { |
63 | .account__box { background: $dark-theme-gray-darker; } | 63 | .account__box { background: $dark-theme-gray-darker; } |
64 | |||
65 | .invoices { | ||
66 | td { border-bottom: 1px solid $dark-theme-gray-darker; } | ||
67 | .invoices__action button { color: $theme-brand-primary; } | ||
68 | } | ||
69 | } | 64 | } |
70 | 65 | ||
71 | .premium-info { | 66 | .premium-info { |
@@ -329,15 +324,6 @@ | |||
329 | .account__avatar { | 324 | .account__avatar { |
330 | margin-right: 20px; | 325 | margin-right: 20px; |
331 | position: relative; | 326 | position: relative; |
332 | |||
333 | .emoji img { width: 30px; } | ||
334 | } | ||
335 | |||
336 | .account__avatar-premium { | ||
337 | font-size: 26px; | ||
338 | position: absolute; | ||
339 | right: 2px; | ||
340 | top: 2px; | ||
341 | } | 327 | } |
342 | 328 | ||
343 | .account__info { | 329 | .account__info { |
@@ -345,6 +331,7 @@ | |||
345 | 331 | ||
346 | h2 { margin-bottom: 5px; } | 332 | h2 { margin-bottom: 5px; } |
347 | .badge { margin-top: 5px; } | 333 | .badge { margin-top: 5px; } |
334 | .username { margin-right: 10 } | ||
348 | } | 335 | } |
349 | 336 | ||
350 | .account__subscription { | 337 | .account__subscription { |
@@ -354,6 +341,22 @@ | |||
354 | .badge { margin-left: 10px; } | 341 | .badge { margin-left: 10px; } |
355 | } | 342 | } |
356 | 343 | ||
344 | .badge--premium { | ||
345 | margin-left: 1px; | ||
346 | position: relative; | ||
347 | top: -3px; | ||
348 | padding-top: 4px; | ||
349 | color: #FFF; | ||
350 | border-radius: 3px; | ||
351 | } | ||
352 | |||
353 | |||
354 | .manage-user-links { | ||
355 | margin-top: 20px; | ||
356 | display: flex; | ||
357 | justify-content: space-between; | ||
358 | } | ||
359 | |||
357 | .account__subscription-button { margin-left: auto; } | 360 | .account__subscription-button { margin-left: auto; } |
358 | .franz-form__button { white-space: nowrap; } | 361 | .franz-form__button { white-space: nowrap; } |
359 | div { height: auto; } | 362 | div { height: auto; } |