aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/subscription/SubscriptionForm.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/subscription/SubscriptionForm.js')
-rw-r--r--src/components/subscription/SubscriptionForm.js220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/components/subscription/SubscriptionForm.js b/src/components/subscription/SubscriptionForm.js
new file mode 100644
index 000000000..dd350479d
--- /dev/null
+++ b/src/components/subscription/SubscriptionForm.js
@@ -0,0 +1,220 @@
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 includedFeatures: {
35 id: 'subscription.includedFeatures',
36 defaultMessage: '!!!The Franz Premium Supporter Account includes',
37 },
38 features: {
39 unlimitedServices: {
40 id: 'subscription.features.unlimitedServices',
41 defaultMessage: '!!!Add unlimited services',
42 },
43 onpremise: {
44 id: 'subscription.features.onpremise',
45 defaultMessage: '!!!Add on-premise/hosted services like HipChat',
46 },
47 customServices: {
48 id: 'subscription.features.customServices',
49 defaultMessage: '!!!Add your custom services',
50 },
51 encryptedSync: {
52 id: 'subscription.features.encryptedSync',
53 defaultMessage: '!!!Encrypted session synchronization',
54 },
55 vpn: {
56 id: 'subscription.features.vpn',
57 defaultMessage: '!!!Proxy & VPN support',
58 },
59 ads: {
60 id: 'subscription.features.ads',
61 defaultMessage: '!!!No ads, ever!',
62 },
63 comingSoon: {
64 id: 'subscription.features.comingSoon',
65 defaultMessage: '!!!coming soon',
66 },
67 },
68 euTaxInfo: {
69 id: 'subscription.euTaxInfo',
70 defaultMessage: '!!!EU residents: local sales tax may apply',
71 },
72});
73
74@observer
75export default class SubscriptionForm extends Component {
76 static propTypes = {
77 plan: MobxPropTypes.objectOrObservableObject.isRequired,
78 isLoading: PropTypes.bool.isRequired,
79 handlePayment: PropTypes.func.isRequired,
80 retryPlanRequest: PropTypes.func.isRequired,
81 isCreatingHostedPage: PropTypes.bool.isRequired,
82 error: PropTypes.bool.isRequired,
83 showSkipOption: PropTypes.bool,
84 skipAction: PropTypes.func,
85 skipButtonLabel: PropTypes.string,
86 hideInfo: PropTypes.bool.isRequired,
87 };
88
89 static defaultProps ={
90 content: '',
91 showSkipOption: false,
92 skipAction: () => null,
93 skipButtonLabel: '',
94 }
95
96 static contextTypes = {
97 intl: intlShape,
98 };
99
100 componentWillMount() {
101 this.form = this.prepareForm();
102 }
103
104 prepareForm() {
105 const { intl } = this.context;
106
107 const form = {
108 fields: {
109 paymentTier: {
110 value: 'year',
111 validators: [required],
112 options: [{
113 value: 'month',
114 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'month')
115 ? `${this.props.plan.month.price} / ${intl.formatMessage(messages.typeMonthly)}`
116 : 'monthly'}`,
117 }, {
118 value: 'year',
119 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'year')
120 ? `${this.props.plan.year.price} / ${intl.formatMessage(messages.typeYearly)}`
121 : 'yearly'}`,
122 }],
123 },
124 },
125 };
126
127 if (this.props.showSkipOption) {
128 form.fields.paymentTier.options.unshift({
129 value: 'skip',
130 label: `€ 0 / ${intl.formatMessage(messages.typeFree)}`,
131 });
132 }
133
134 return new Form(form, this.context.intl);
135 }
136
137 render() {
138 const {
139 isLoading,
140 isCreatingHostedPage,
141 handlePayment,
142 retryPlanRequest,
143 error,
144 showSkipOption,
145 skipAction,
146 skipButtonLabel,
147 hideInfo,
148 } = this.props;
149 const { intl } = this.context;
150
151 if (error) {
152 return (
153 <Button
154 label="Reload"
155 onClick={retryPlanRequest}
156 isLoaded={!isLoading}
157 />
158 );
159 }
160
161 return (
162 <Loader loaded={!isLoading}>
163 <Radio field={this.form.$('paymentTier')} showLabel={false} className="paymentTiers" />
164 {!hideInfo && (
165 <div className="subscription__premium-info">
166 <div>
167 <p>
168 <strong>{intl.formatMessage(messages.includedFeatures)}</strong>
169 </p>
170 <div className="subscription">
171 <ul className="subscription__premium-features">
172 <li>{intl.formatMessage(messages.features.onpremise)}</li>
173 <li>
174 {intl.formatMessage(messages.features.encryptedSync)}
175 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
176 </li>
177 <li>
178 {intl.formatMessage(messages.features.customServices)}
179 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
180 </li>
181 <li>
182 {intl.formatMessage(messages.features.vpn)}
183 <span className="badge">{intl.formatMessage(messages.features.comingSoon)}</span>
184 </li>
185 <li>
186 {intl.formatMessage(messages.features.ads)}
187 </li>
188 </ul>
189 </div>
190 </div>
191 </div>
192 )}
193 <div>
194 {error.code === 'no-payment-session' && (
195 <p className="error-message center">{intl.formatMessage(messages.paymentSessionError)}</p>
196 )}
197 </div>
198 {showSkipOption && this.form.$('paymentTier').value === 'skip' ? (
199 <Button
200 label={skipButtonLabel}
201 className="auth__button"
202 onClick={skipAction}
203 />
204 ) : (
205 <Button
206 label={intl.formatMessage(messages.submitButtonLabel)}
207 className="auth__button"
208 loaded={!isCreatingHostedPage}
209 onClick={() => handlePayment(this.form.$('paymentTier').value)}
210 />
211 )}
212 {this.form.$('paymentTier').value !== 'skip' && (
213 <p className="legal">
214 {intl.formatMessage(messages.euTaxInfo)}
215 </p>
216 )}
217 </Loader>
218 );
219 }
220}