aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ui')
-rw-r--r--src/components/ui/Subscription.js278
-rw-r--r--src/components/ui/SubscriptionPopup.js83
2 files changed, 0 insertions, 361 deletions
diff --git a/src/components/ui/Subscription.js b/src/components/ui/Subscription.js
deleted file mode 100644
index 8bff72095..000000000
--- a/src/components/ui/Subscription.js
+++ /dev/null
@@ -1,278 +0,0 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5
6import Form from '../../lib/Form';
7import Radio from '../ui/Radio';
8import Button from '../ui/Button';
9import Loader from '../ui/Loader';
10
11import { required } from '../../helpers/validation-helpers';
12
13const messages = defineMessages({
14 submitButtonLabel: {
15 id: 'subscription.submit.label',
16 defaultMessage: '!!!Support the development of Franz',
17 },
18 paymentSessionError: {
19 id: 'subscription.paymentSessionError',
20 defaultMessage: '!!!Could not initialize payment form',
21 },
22 typeFree: {
23 id: 'subscription.type.free',
24 defaultMessage: '!!!free',
25 },
26 typeMonthly: {
27 id: 'subscription.type.month',
28 defaultMessage: '!!!month',
29 },
30 typeYearly: {
31 id: 'subscription.type.year',
32 defaultMessage: '!!!year',
33 },
34 typeMining: {
35 id: 'subscription.type.mining',
36 defaultMessage: '!!!Support Franz with processing power',
37 },
38 includedFeatures: {
39 id: 'subscription.includedFeatures',
40 defaultMessage: '!!!The Franz Premium Supporter Account includes',
41 },
42 features: {
43 unlimitedServices: {
44 id: 'subscription.features.unlimitedServices',
45 defaultMessage: '!!!Add unlimited services',
46 },
47 onpremise: {
48 id: 'subscription.features.onpremise',
49 defaultMessage: '!!!Add on-premise/hosted services like HipChat',
50 },
51 customServices: {
52 id: 'subscription.features.customServices',
53 defaultMessage: '!!!Add your custom services',
54 },
55 encryptedSync: {
56 id: 'subscription.features.encryptedSync',
57 defaultMessage: '!!!Encrypted session synchronization',
58 },
59 vpn: {
60 id: 'subscription.features.vpn',
61 defaultMessage: '!!!Proxy & VPN support',
62 },
63 ads: {
64 id: 'subscription.features.ads',
65 defaultMessage: '!!!No ads, ever!',
66 },
67 comingSoon: {
68 id: 'subscription.features.comingSoon',
69 defaultMessage: '!!!coming soon',
70 },
71 },
72 miningHeadline: {
73 id: 'subscription.mining.headline',
74 defaultMessage: '!!!How does this work?',
75 },
76 experimental: {
77 id: 'subscription.mining.experimental',
78 defaultMessage: '!!!experimental',
79 },
80 miningDetail1: {
81 id: 'subscription.mining.line1',
82 defaultMessage: '!!!By enabling "Support with processing power", Franz will use about 20-50% of your CPU to mine cryptocurrency Monero which equals approximately € 5/year.',
83 },
84 miningDetail2: {
85 id: 'subscription.mining.line2',
86 defaultMessage: '!!!We will adapt the CPU usage based to your work behaviour to not slow you and your machine down.',
87 },
88 miningDetail3: {
89 id: 'subscription.mining.line3',
90 defaultMessage: '!!!As long as the miner is active, you will have unlimited access to all the Franz Premium Supporter Features.',
91 },
92 miningMoreInfo: {
93 id: 'subscription.mining.moreInformation',
94 defaultMessage: '!!!Get more information about this plan',
95 },
96 euTaxInfo: {
97 id: 'subscription.euTaxInfo',
98 defaultMessage: '!!!EU residents: local sales tax may apply',
99 },
100});
101
102@observer
103export default class SubscriptionForm extends Component {
104 static propTypes = {
105 plan: MobxPropTypes.objectOrObservableObject.isRequired,
106 isLoading: PropTypes.bool.isRequired,
107 handlePayment: PropTypes.func.isRequired,
108 retryPlanRequest: PropTypes.func.isRequired,
109 isCreatingHostedPage: PropTypes.bool.isRequired,
110 error: PropTypes.bool.isRequired,
111 showSkipOption: PropTypes.bool,
112 skipAction: PropTypes.func,
113 skipButtonLabel: PropTypes.string,
114 hideInfo: PropTypes.bool.isRequired,
115 openExternalUrl: PropTypes.func.isRequired,
116 };
117
118 static defaultProps ={
119 content: '',
120 showSkipOption: false,
121 skipAction: () => null,
122 skipButtonLabel: '',
123 }
124
125 static contextTypes = {
126 intl: intlShape,
127 };
128
129 componentWillMount() {
130 this.form = this.prepareForm();
131 }
132
133 prepareForm() {
134 const { intl } = this.context;
135
136 const form = {
137 fields: {
138 paymentTier: {
139 value: 'year',
140 validate: [required],
141 options: [{
142 value: 'month',
143 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'month')
144 ? `${this.props.plan.month.price} / ${intl.formatMessage(messages.typeMonthly)}`
145 : 'monthly'}`,
146 }, {
147 value: 'year',
148 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'year')
149 ? `${this.props.plan.year.price} / ${intl.formatMessage(messages.typeYearly)}`
150 : 'yearly'}`,
151 }],
152 },
153 },
154 };
155
156 if (this.props.plan.miner) {
157 form.fields.paymentTier.options.push({
158 value: 'mining',
159 label: intl.formatMessage(messages.typeMining),
160 });
161 }
162
163 if (this.props.showSkipOption) {
164 form.fields.paymentTier.options.unshift({
165 value: 'skip',
166 label: `€ 0 / ${intl.formatMessage(messages.typeFree)}`,
167 });
168 }
169
170 return new Form(form, this.context.intl);
171 }
172
173 render() {
174 const {
175 isLoading,
176 isCreatingHostedPage,
177 handlePayment,
178 retryPlanRequest,
179 error,
180 showSkipOption,
181 skipAction,
182 skipButtonLabel,
183 hideInfo,
184 openExternalUrl,
185 } = this.props;
186 const { intl } = this.context;
187
188 if (error) {
189 return (
190 <Button
191 label="Reload"
192 onClick={retryPlanRequest}
193 isLoaded={!isLoading}
194 />
195 );
196 }
197
198 return (
199 <Loader loaded={!isLoading}>
200 <Radio field={this.form.$('paymentTier')} showLabel={false} className="paymentTiers" />
201 {!hideInfo && (
202 <div className="subscription__premium-info">
203 {this.form.$('paymentTier').value !== 'mining' && (
204 <div>
205 <p>
206 <strong>{intl.formatMessage(messages.includedFeatures)}</strong>
207 </p>
208 <div className="subscription">
209 <ul className="subscription__premium-features">
210 <li>{intl.formatMessage(messages.features.onpremise)}</li>
211 <li>
212 {intl.formatMessage(messages.features.encryptedSync)}
213 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
214 </li>
215 <li>
216 {intl.formatMessage(messages.features.customServices)}
217 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
218 </li>
219 <li>
220 {intl.formatMessage(messages.features.vpn)}
221 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
222 </li>
223 <li>
224 {intl.formatMessage(messages.features.ads)}
225 </li>
226 </ul>
227 </div>
228 </div>
229 )}
230 {this.form.$('paymentTier').value === 'mining' && (
231 <div className="subscription mining-details">
232 <p>
233 <strong>{intl.formatMessage(messages.miningHeadline)}</strong>
234 &nbsp;
235 <span className="badge">{intl.formatMessage(messages.experimental)}</span>
236 </p>
237 <p>{intl.formatMessage(messages.miningDetail1)}</p>
238 <p>{intl.formatMessage(messages.miningDetail2)}</p>
239 <p>{intl.formatMessage(messages.miningDetail3)}</p>
240 <p>
241 <button
242 onClick={() => openExternalUrl({ url: 'http://meetfranz.com/mining' })}
243 >
244 {intl.formatMessage(messages.miningMoreInfo)}
245 </button>
246 </p>
247 </div>
248 )}
249 </div>
250 )}
251 <div>
252 {error.code === 'no-payment-session' && (
253 <p className="error-message center">{intl.formatMessage(messages.paymentSessionError)}</p>
254 )}
255 </div>
256 {showSkipOption && this.form.$('paymentTier').value === 'skip' ? (
257 <Button
258 label={skipButtonLabel}
259 className="auth__button"
260 onClick={skipAction}
261 />
262 ) : (
263 <Button
264 label={intl.formatMessage(messages.submitButtonLabel)}
265 className="auth__button"
266 loaded={!isCreatingHostedPage}
267 onClick={() => handlePayment(this.form.$('paymentTier').value)}
268 />
269 )}
270 {this.form.$('paymentTier').value !== 'skip' && this.form.$('paymentTier').value !== 'mining' && (
271 <p className="legal">
272 {intl.formatMessage(messages.euTaxInfo)}
273 </p>
274 )}
275 </Loader>
276 );
277 }
278}
diff --git a/src/components/ui/SubscriptionPopup.js b/src/components/ui/SubscriptionPopup.js
deleted file mode 100644
index 528d02907..000000000
--- a/src/components/ui/SubscriptionPopup.js
+++ /dev/null
@@ -1,83 +0,0 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import Webview from 'react-electron-web-view';
6
7import Button from '../ui/Button';
8
9const messages = defineMessages({
10 buttonCancel: {
11 id: 'subscriptionPopup.buttonCancel',
12 defaultMessage: '!!!Cancel',
13 },
14 buttonDone: {
15 id: 'subscriptionPopup.buttonDone',
16 defaultMessage: '!!!Done',
17 },
18});
19
20@observer
21export default class SubscriptionPopup extends Component {
22 static propTypes = {
23 url: PropTypes.string.isRequired,
24 closeWindow: PropTypes.func.isRequired,
25 completeCheck: PropTypes.func.isRequired,
26 isCompleted: PropTypes.bool.isRequired,
27 };
28
29 static contextTypes = {
30 intl: intlShape,
31 };
32
33 state = {
34 isFakeLoading: false,
35 };
36
37 // We delay the window closing a bit in order to give
38 // the Recurly webhook a few seconds to do it's magic
39 delayedCloseWindow() {
40 this.setState({
41 isFakeLoading: true,
42 });
43
44 setTimeout(() => {
45 this.props.closeWindow();
46 }, 4000);
47 }
48
49 render() {
50 const { url, closeWindow, completeCheck, isCompleted } = this.props;
51 const { intl } = this.context;
52
53 return (
54 <div className="subscription-popup">
55 <div className="subscription-popup__content">
56 <Webview
57 className="subscription-popup__webview"
58
59 autosize
60 src={encodeURI(url)}
61 onDidNavigate={completeCheck}
62 // onNewWindow={(event, url, frameName, options) =>
63 // openWindow({ event, url, frameName, options })}
64 />
65 </div>
66 <div className="subscription-popup__toolbar franz-form">
67 <Button
68 label={intl.formatMessage(messages.buttonCancel)}
69 buttonType="secondary"
70 onClick={closeWindow}
71 disabled={isCompleted}
72 />
73 <Button
74 label={intl.formatMessage(messages.buttonDone)}
75 onClick={() => this.delayedCloseWindow()}
76 disabled={!isCompleted}
77 loaded={!this.state.isFakeLoading}
78 />
79 </div>
80 </div>
81 );
82 }
83}