summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-04-08 15:18:58 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-04-08 15:18:58 +0200
commitea71fced95a6923926c92ada523840ebdbd0ef64 (patch)
treeed5542a00b12a870fd6c426cad65b6daa797ebd6 /src
parentremove console log (diff)
downloadferdium-app-ea71fced95a6923926c92ada523840ebdbd0ef64.tar.gz
ferdium-app-ea71fced95a6923926c92ada523840ebdbd0ef64.tar.zst
ferdium-app-ea71fced95a6923926c92ada523840ebdbd0ef64.zip
Replace invoices & subscription info with links to website
Diffstat (limited to 'src')
-rw-r--r--src/api/PaymentApi.js8
-rw-r--r--src/api/server/ServerApi.js17
-rw-r--r--src/components/settings/account/AccountDashboard.js107
-rw-r--r--src/config.js5
-rw-r--r--src/containers/settings/AccountScreen.js69
-rw-r--r--src/environment.js14
-rw-r--r--src/stores/PaymentStore.js17
-rw-r--r--src/styles/badge.scss1
-rw-r--r--src/styles/settings.scss13
9 files changed, 103 insertions, 148 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/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 181b95c8c..ca8b9e1bd 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -3,12 +3,10 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import ReactTooltip from 'react-tooltip'; 5import ReactTooltip from 'react-tooltip';
6import moment from 'moment';
7 6
8import Loader from '../../ui/Loader'; 7import Loader from '../../ui/Loader';
9import Button from '../../ui/Button'; 8import Button from '../../ui/Button';
10import Infobox from '../../ui/Infobox'; 9import Infobox from '../../ui/Infobox';
11import Link from '../../ui/Link';
12import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; 10import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen';
13 11
14const messages = defineMessages({ 12const 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({
77export default @observer class AccountDashboard extends Component { 75export 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,39 @@ 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 /> 167 <div className="manage-user-links">
168 {user.isPremium && ( 168 <Button
169 <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> 169 label={intl.formatMessage(messages.accountEditButton)}
170 )} 170 className="franz-form__button--inverted"
171 </div> 171 onClick={openEditAccount}
172 <Link to="/settings/user/edit" className="button"> 172 />
173 {intl.formatMessage(messages.accountEditButton)} 173 {user.isSubscriptionOwner && (
174 </Link> 174 <>
175 {user.emailValidated}
176 </div>
177 </div>
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 175 <Button
193 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)} 176 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
194 className="account__subscription-button franz-form__button--inverted" 177 className="franz-form__button--inverted"
195 loaded={!isCreatingPaymentDashboardUrl} 178 onClick={openBilling}
196 onClick={() => openDashboard()}
197 /> 179 />
198 </div> 180 <Button
199 </div> 181 label={intl.formatMessage(messages.invoicesButton)}
200 <div className="account__box"> 182 className="franz-form__button--inverted"
201 <h2>{intl.formatMessage(messages.headlineInvoices)}</h2> 183 onClick={openInvoices}
202 <table className="invoices"> 184 />
203 <tbody> 185 </>
204 {orders.map(order => ( 186 )}
205 <tr key={order.id}> 187 </div>
206 <td className="invoices__date"> 188 </div>
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 )}
224 </div> 189 </div>
225 ) 190 </div>
226 )} 191 )}
227 192
228 {!user.isPremium && ( 193 {!user.isPremium && (
diff --git a/src/config.js b/src/config.js
index 479572edb..4423e61e9 100644
--- a/src/config.js
+++ b/src/config.js
@@ -12,6 +12,11 @@ export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks
12export const LOCAL_API = 'http://localhost:3000'; 12export const LOCAL_API = 'http://localhost:3000';
13export const DEV_API = 'https://dev.franzinfra.com'; 13export const DEV_API = 'https://dev.franzinfra.com';
14export const LIVE_API = 'https://api.franzinfra.com'; 14export const LIVE_API = 'https://api.franzinfra.com';
15
16export const LOCAL_API_WEBSITE = 'http://localhost:3333';
17export const DEV_API_WEBSITE = 'https://meetfranz.com';
18export const LIVE_API_WEBSITE = 'https://meetfranz.com';
19
15export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; 20export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12';
16 21
17export const DEFAULT_APP_SETTINGS = { 22export const DEFAULT_APP_SETTINGS = {
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js
index ce1b9c333..0c837fab9 100644
--- a/src/containers/settings/AccountScreen.js
+++ b/src/containers/settings/AccountScreen.js
@@ -9,6 +9,7 @@ import AppStore from '../../stores/AppStore';
9 9
10import AccountDashboard from '../../components/settings/account/AccountDashboard'; 10import AccountDashboard from '../../components/settings/account/AccountDashboard';
11import ErrorBoundary from '../../components/util/ErrorBoundary'; 11import ErrorBoundary from '../../components/util/ErrorBoundary';
12import { WEBSITE } from '../../environment';
12 13
13const { BrowserWindow } = remote; 14const { BrowserWindow } = remote;
14 15
@@ -24,69 +25,77 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend
24 onCloseWindow() { 25 onCloseWindow() {
25 const { user, payment } = this.props.stores; 26 const { user, payment } = this.props.stores;
26 user.getUserInfoRequest.invalidate({ immediately: true }); 27 user.getUserInfoRequest.invalidate({ immediately: true });
27 payment.ordersDataRequest.invalidate({ immediately: true });
28 } 28 }
29 29
30 reloadData() { 30 reloadData() {
31 const { user, payment } = this.props.stores; 31 const { user, payment } = this.props.stores;
32 32
33 user.getUserInfoRequest.reload(); 33 user.getUserInfoRequest.reload();
34 payment.ordersDataRequest.reload();
35 payment.plansRequest.reload(); 34 payment.plansRequest.reload();
36 } 35 }
37 36
38 async handlePaymentDashboard() { 37 async handlePaymentDashboard() {
39 const { actions, stores } = this.props; 38 const { actions, stores } = this.props;
40 39
41 actions.payment.createDashboardUrl(); 40 // actions.payment.createDashboardUrl();
42 41
43 const dashboard = await stores.payment.createDashboardUrlRequest; 42 // const dashboard = await stores.payment.createDashboardUrlRequest;
44 43
45 if (dashboard.url) { 44 // if (dashboard.url) {
46 const paymentWindow = new BrowserWindow({ 45 // const paymentWindow = new BrowserWindow({
47 title: '🔒 Franz Subscription Dashboard', 46 // title: '🔒 Franz Subscription Dashboard',
48 parent: remote.getCurrentWindow(), 47 // parent: remote.getCurrentWindow(),
49 modal: false, 48 // modal: false,
50 width: 900, 49 // width: 900,
51 minWidth: 600, 50 // minWidth: 600,
52 webPreferences: { 51 // webPreferences: {
53 nodeIntegration: false, 52 // nodeIntegration: false,
54 }, 53 // },
55 }); 54 // });
56 paymentWindow.loadURL(dashboard.url); 55 // paymentWindow.loadURL(dashboard.url);
57 56
58 paymentWindow.on('closed', () => { 57 // paymentWindow.on('closed', () => {
59 this.onCloseWindow(); 58 // this.onCloseWindow();
60 }); 59 // });
61 } 60 // }
61
62 const url = `${WEBSITE}/user/billing?token=${stores.user.authToken}&utm_source=app&utm_medium=edit_profile`;
63
64 actions.app.openExternalUrl({ url });
65 }
66
67 handleWebsiteLink(route) {
68 const { actions, stores } = this.props;
69
70 const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`;
71 console.log(url);
72
73 actions.app.openExternalUrl({ url });
62 } 74 }
63 75
64 render() { 76 render() {
65 const { user, payment } = this.props.stores; 77 const { user, payment } = this.props.stores;
66 const { openExternalUrl } = this.props.actions.app;
67 const { user: userActions } = this.props.actions; 78 const { user: userActions } = this.props.actions;
68 79
69 const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; 80 const isLoadingUserInfo = user.getUserInfoRequest.isExecuting;
70 const isLoadingOrdersInfo = payment.ordersDataRequest.isExecuting;
71 const isLoadingPlans = payment.plansRequest.isExecuting; 81 const isLoadingPlans = payment.plansRequest.isExecuting;
72 82
73 return ( 83 return (
74 <ErrorBoundary> 84 <ErrorBoundary>
75 <AccountDashboard 85 <AccountDashboard
76 user={user.data} 86 user={user.data}
77 orders={payment.orders} 87 orders={payment.orders} // das muss raus
78 isLoading={isLoadingUserInfo} 88 isLoading={isLoadingUserInfo}
79 isLoadingOrdersInfo={isLoadingOrdersInfo}
80 isLoadingPlans={isLoadingPlans} 89 isLoadingPlans={isLoadingPlans}
81 userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} 90 userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError}
82 retryUserInfoRequest={() => this.reloadData()} 91 retryUserInfoRequest={() => this.reloadData()}
83 isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting}
84 openDashboard={price => this.handlePaymentDashboard(price)}
85 openExternalUrl={url => openExternalUrl({ url })}
86 onCloseSubscriptionWindow={() => this.onCloseWindow()} 92 onCloseSubscriptionWindow={() => this.onCloseWindow()}
87 deleteAccount={userActions.delete} 93 deleteAccount={userActions.delete}
88 isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} 94 isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting}
89 isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} 95 isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError}
96 openEditAccount={() => this.handleWebsiteLink('/user/profile')}
97 openBilling={() => this.handleWebsiteLink('/user/billing')}
98 openInvoices={() => this.handleWebsiteLink('/user/invoices')}
90 /> 99 />
91 </ErrorBoundary> 100 </ErrorBoundary>
92 ); 101 );
diff --git a/src/environment.js b/src/environment.js
index 73b1c7ab2..68fa45173 100644
--- a/src/environment.js
+++ b/src/environment.js
@@ -1,6 +1,13 @@
1import isDev from 'electron-is-dev'; 1import isDev from 'electron-is-dev';
2 2
3import { LIVE_API, DEV_API, LOCAL_API } from './config'; 3import {
4 LIVE_API,
5 DEV_API,
6 LOCAL_API,
7 LOCAL_API_WEBSITE,
8 DEV_API_WEBSITE,
9 LIVE_API_WEBSITE,
10} from './config';
4 11
5export const isDevMode = isDev; 12export const isDevMode = isDev;
6export const useLiveAPI = process.env.LIVE_API; 13export const useLiveAPI = process.env.LIVE_API;
@@ -19,12 +26,17 @@ export const ctrlKey = isMac ? '⌘' : 'Ctrl';
19export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; 26export const cmdKey = isMac ? 'Cmd' : 'Ctrl';
20 27
21let api; 28let api;
29let web;
22if (!isDevMode || (isDevMode && useLiveAPI)) { 30if (!isDevMode || (isDevMode && useLiveAPI)) {
23 api = LIVE_API; 31 api = LIVE_API;
32 web = LIVE_API_WEBSITE;
24} else if (isDevMode && useLocalAPI) { 33} else if (isDevMode && useLocalAPI) {
25 api = LOCAL_API; 34 api = LOCAL_API;
35 web = LOCAL_API_WEBSITE;
26} else { 36} else {
27 api = DEV_API; 37 api = DEV_API;
38 web = DEV_API_WEBSITE;
28} 39}
29 40
30export const API = api; 41export const API = api;
42export const WEBSITE = web;
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 750b6bedd..b286c6f1b 100644
--- a/src/styles/settings.scss
+++ b/src/styles/settings.scss
@@ -62,13 +62,18 @@
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
71 .premium-info { 76 .premium-info {
72 background: $dark-theme-gray-darker; 77 background: $dark-theme-gray-darker;
73 border: 2px solid $theme-brand-primary; 78 border: 2px solid $theme-brand-primary;
74 } 79 }