diff options
Diffstat (limited to 'src/components/ui')
-rw-r--r-- | src/components/ui/Subscription.js | 278 | ||||
-rw-r--r-- | src/components/ui/SubscriptionPopup.js | 83 |
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 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | |||
6 | import Form from '../../lib/Form'; | ||
7 | import Radio from '../ui/Radio'; | ||
8 | import Button from '../ui/Button'; | ||
9 | import Loader from '../ui/Loader'; | ||
10 | |||
11 | import { required } from '../../helpers/validation-helpers'; | ||
12 | |||
13 | const 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 | ||
103 | export 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 | | ||
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 @@ | |||
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 Webview from 'react-electron-web-view'; | ||
6 | |||
7 | import Button from '../ui/Button'; | ||
8 | |||
9 | const 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 | ||
21 | export 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 | } | ||