aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/announcements/components/AnnouncementScreen.js41
-rw-r--r--src/features/planSelection/components/PlanItem.js19
-rw-r--r--src/features/planSelection/components/PlanSelection.js76
-rw-r--r--src/features/planSelection/containers/PlanSelectionScreen.js4
4 files changed, 81 insertions, 59 deletions
diff --git a/src/features/announcements/components/AnnouncementScreen.js b/src/features/announcements/components/AnnouncementScreen.js
index 38de2dbc8..2f25e7139 100644
--- a/src/features/announcements/components/AnnouncementScreen.js
+++ b/src/features/announcements/components/AnnouncementScreen.js
@@ -192,6 +192,11 @@ class AnnouncementScreen extends Component {
192 stores: PropTypes.shape({ 192 stores: PropTypes.shape({
193 ui: PropTypes.instanceOf(UIStore).isRequired, 193 ui: PropTypes.instanceOf(UIStore).isRequired,
194 }).isRequired, 194 }).isRequired,
195 actions: PropTypes.shape({
196 app: PropTypes.shape({
197 openExternalUrl: PropTypes.func.isRequired,
198 }).isRequired,
199 }).isRequired,
195 }; 200 };
196 201
197 static contextTypes = { 202 static contextTypes = {
@@ -199,7 +204,7 @@ class AnnouncementScreen extends Component {
199 }; 204 };
200 205
201 render() { 206 render() {
202 const { classes, stores } = this.props; 207 const { classes, stores, actions } = this.props;
203 const { intl } = this.context; 208 const { intl } = this.context;
204 const { changelog, announcement } = announcementsStore; 209 const { changelog, announcement } = announcementsStore;
205 const themeImage = stores.ui.isDarkThemeActive ? 'dark' : 'light'; 210 const themeImage = stores.ui.isDarkThemeActive ? 'dark' : 'light';
@@ -223,14 +228,23 @@ class AnnouncementScreen extends Component {
223 __html: marked(announcement.main.text, markedOptions), 228 __html: marked(announcement.main.text, markedOptions),
224 }} 229 }}
225 /> 230 />
226 <div className={classes.mainCtaButton}> 231 {(announcement.main.cta.label || announcement.main.cta.href) && (
227 <Button 232 <div className={classes.mainCtaButton}>
228 label={announcement.main.cta.label} 233 <Button
229 onClick={() => { 234 label={announcement.main.cta.label}
230 window.location.href = `#${announcement.main.cta.href}`; 235 onClick={() => {
231 }} 236 const {
232 /> 237 href,
233 </div> 238 } = announcement.main.cta;
239 if (announcement.main.cta.href.startsWith('http')) {
240 actions.app.openExternalUrl({ url: href });
241 } else {
242 window.location.href = `#${href}`;
243 }
244 }}
245 />
246 </div>
247 )}
234 </div> 248 </div>
235 </div> 249 </div>
236 </div> 250 </div>
@@ -250,7 +264,14 @@ class AnnouncementScreen extends Component {
250 <Button 264 <Button
251 label={announcement.spotlight.cta.label} 265 label={announcement.spotlight.cta.label}
252 onClick={() => { 266 onClick={() => {
253 window.location.href = `#${announcement.spotlight.cta.href}`; 267 const {
268 href,
269 } = announcement.spotlight.cta;
270 if (announcement.spotlight.cta.href.startsWith('http')) {
271 actions.app.openExternalUrl({ url: href });
272 } else {
273 window.location.href = `#${href}`;
274 }
254 }} 275 }}
255 /> 276 />
256 </div> 277 </div>
diff --git a/src/features/planSelection/components/PlanItem.js b/src/features/planSelection/components/PlanItem.js
index ec061377b..3855fedf1 100644
--- a/src/features/planSelection/components/PlanItem.js
+++ b/src/features/planSelection/components/PlanItem.js
@@ -49,6 +49,7 @@ const styles = theme => ({
49 priceWrapper: { 49 priceWrapper: {
50 height: 50, 50 height: 50,
51 marginBottom: 0, 51 marginBottom: 0,
52 marginTop: ({ text }) => (!text ? 15 : 0),
52 }, 53 },
53 price: { 54 price: {
54 fontSize: 50, 55 fontSize: 50,
@@ -64,7 +65,7 @@ const styles = theme => ({
64 cta: { 65 cta: {
65 background: theme.styleTypes.primary.accent, 66 background: theme.styleTypes.primary.accent,
66 color: theme.styleTypes.primary.contrast, 67 color: theme.styleTypes.primary.contrast,
67 margin: [40, 'auto', 0, 'auto'], 68 margin: [30, 'auto', 0, 'auto'],
68 }, 69 },
69 divider: { 70 divider: {
70 width: 40, 71 width: 40,
@@ -77,10 +78,14 @@ const styles = theme => ({
77 background: color(theme.styleTypes.primary.accent).darken(0.25).hex(), 78 background: color(theme.styleTypes.primary.accent).darken(0.25).hex(),
78 color: theme.styleTypes.primary.contrast, 79 color: theme.styleTypes.primary.contrast,
79 position: 'relative', 80 position: 'relative',
81 height: 'auto',
80 }, 82 },
81 content: { 83 content: {
82 padding: [10, 20, 20], 84 padding: [10, 20, 20],
83 background: '#EFEFEF', 85 background: '#EFEFEF',
86 display: 'flex',
87 flexDirection: 'column',
88 justifyContent: 'space-between',
84 }, 89 },
85 simpleCTA: { 90 simpleCTA: {
86 background: 'none', 91 background: 'none',
@@ -167,10 +172,14 @@ export default @observer @injectSheet(styles) class PlanItem extends Component {
167 </div> 172 </div>
168 )} 173 )}
169 <H2 className={classes.planName}>{name}</H2> 174 <H2 className={classes.planName}>{name}</H2>
170 <p className={classes.text}> 175 {text && (
171 {text} 176 <>
172 </p> 177 <p className={classes.text}>
173 <hr className={classes.divider} /> 178 {text}
179 </p>
180 <hr className={classes.divider} />
181 </>
182 )}
174 <p className={classes.priceWrapper}> 183 <p className={classes.priceWrapper}>
175 <span className={classes.currency}>{currency}</span> 184 <span className={classes.currency}>{currency}</span>
176 <span className={classes.price}> 185 <span className={classes.price}>
diff --git a/src/features/planSelection/components/PlanSelection.js b/src/features/planSelection/components/PlanSelection.js
index 4bf5238dd..6f0dd30ad 100644
--- a/src/features/planSelection/components/PlanSelection.js
+++ b/src/features/planSelection/components/PlanSelection.js
@@ -6,7 +6,7 @@ import { defineMessages, intlShape } from 'react-intl';
6import { H1, H2, Icon } from '@meetfranz/ui'; 6import { H1, H2, Icon } from '@meetfranz/ui';
7import color from 'color'; 7import color from 'color';
8 8
9import { mdiRocket, mdiArrowRight } from '@mdi/js'; 9import { mdiArrowRight } from '@mdi/js';
10import PlanItem from './PlanItem'; 10import PlanItem from './PlanItem';
11import { i18nPlanName } from '../../../helpers/plan-helpers'; 11import { i18nPlanName } from '../../../helpers/plan-helpers';
12import { PLANS } from '../../../config'; 12import { PLANS } from '../../../config';
@@ -79,10 +79,10 @@ const styles = theme => ({
79 overflowY: 'scroll', 79 overflowY: 'scroll',
80 }, 80 },
81 container: { 81 container: {
82 width: '80%', 82 // width: '80%',
83 height: 'auto', 83 height: 'auto',
84 background: theme.styleTypes.primary.accent, 84 // background: theme.styleTypes.primary.accent,
85 padding: 40, 85 // padding: 40,
86 borderRadius: theme.borderRadius, 86 borderRadius: theme.borderRadius,
87 maxWidth: 1000, 87 maxWidth: 1000,
88 88
@@ -104,23 +104,6 @@ const styles = theme => ({
104 boxShadow: [0, 2, 30, color('#000').alpha(0.1).rgb().string()], 104 boxShadow: [0, 2, 30, color('#000').alpha(0.1).rgb().string()],
105 }, 105 },
106 }, 106 },
107 bigIcon: {
108 background: theme.styleTypes.danger.accent,
109 width: 120,
110 height: 120,
111 display: 'flex',
112 alignItems: 'center',
113 borderRadius: '100%',
114 justifyContent: 'center',
115 margin: [-100, 'auto', 20],
116
117 '& svg': {
118 width: '80px !important',
119 height: '80px !important',
120 filter: 'drop-shadow( 0px 2px 3px rgba(0, 0, 0, 0.3))',
121 fill: theme.styleTypes.danger.contrast,
122 },
123 },
124 headline: { 107 headline: {
125 fontSize: 40, 108 fontSize: 40,
126 }, 109 },
@@ -158,7 +141,7 @@ const styles = theme => ({
158 overflow: 'scroll-x', 141 overflow: 'scroll-x',
159 }, 142 },
160 featuredPlan: { 143 featuredPlan: {
161 transform: 'scale(1.05)', 144 transform: ({ isPersonalPlanAvailable }) => (isPersonalPlanAvailable ? 'scale(1.05)' : null),
162 }, 145 },
163 disclaimer: { 146 disclaimer: {
164 textAlign: 'right', 147 textAlign: 'right',
@@ -177,8 +160,13 @@ class PlanSelection extends Component {
177 upgradeAccount: PropTypes.func.isRequired, 160 upgradeAccount: PropTypes.func.isRequired,
178 stayOnFree: PropTypes.func.isRequired, 161 stayOnFree: PropTypes.func.isRequired,
179 hadSubscription: PropTypes.bool.isRequired, 162 hadSubscription: PropTypes.bool.isRequired,
163 isPersonalPlanAvailable: PropTypes.bool,
180 }; 164 };
181 165
166 static defaultProps = {
167 isPersonalPlanAvailable: true,
168 }
169
182 static contextTypes = { 170 static contextTypes = {
183 intl: intlShape, 171 intl: intlShape,
184 }; 172 };
@@ -196,6 +184,7 @@ class PlanSelection extends Component {
196 upgradeAccount, 184 upgradeAccount,
197 stayOnFree, 185 stayOnFree,
198 hadSubscription, 186 hadSubscription,
187 isPersonalPlanAvailable,
199 } = this.props; 188 } = this.props;
200 189
201 const { intl } = this.context; 190 const { intl } = this.context;
@@ -206,15 +195,14 @@ class PlanSelection extends Component {
206 className={classes.root} 195 className={classes.root}
207 > 196 >
208 <div className={classes.container}> 197 <div className={classes.container}>
209 <div className={classes.bigIcon}>
210 <Icon icon={mdiRocket} />
211 </div>
212 <H1 className={classes.headline}>{intl.formatMessage(messages.welcome, { name: firstname })}</H1> 198 <H1 className={classes.headline}>{intl.formatMessage(messages.welcome, { name: firstname })}</H1>
213 <H2 className={classes.subheadline}>{intl.formatMessage(messages.subheadline)}</H2> 199 {isPersonalPlanAvailable && (
200 <H2 className={classes.subheadline}>{intl.formatMessage(messages.subheadline)}</H2>
201 )}
214 <div className={classes.plans}> 202 <div className={classes.plans}>
215 <PlanItem 203 <PlanItem
216 name={i18nPlanName(PLANS.FREE, intl)} 204 name={i18nPlanName(PLANS.FREE, intl)}
217 text={intl.formatMessage(messages.textFree)} 205 text={isPersonalPlanAvailable ? intl.formatMessage(messages.textFree) : null}
218 price={0} 206 price={0}
219 currency={currency} 207 currency={currency}
220 ctaLabel={intl.formatMessage(subscriptionExpired ? messages.ctaDowngradeFree : messages.ctaStayOnFree)} 208 ctaLabel={intl.formatMessage(subscriptionExpired ? messages.ctaDowngradeFree : messages.ctaStayOnFree)}
@@ -228,33 +216,35 @@ class PlanSelection extends Component {
228 </PlanItem> 216 </PlanItem>
229 <PlanItem 217 <PlanItem
230 name={i18nPlanName(plans.pro.yearly.id, intl)} 218 name={i18nPlanName(plans.pro.yearly.id, intl)}
231 text={intl.formatMessage(messages.textProfessional)} 219 text={isPersonalPlanAvailable ? intl.formatMessage(messages.textProfessional) : null}
232 price={plans.pro.yearly.price} 220 price={plans.pro.yearly.price}
233 currency={currency} 221 currency={currency}
234 ctaLabel={intl.formatMessage(hadSubscription ? messages.shortActionPro : messages.actionTrial)} 222 ctaLabel={intl.formatMessage(hadSubscription ? messages.shortActionPro : messages.actionTrial)}
235 upgrade={() => upgradeAccount(plans.pro.yearly.id)} 223 upgrade={() => upgradeAccount(plans.pro.yearly.id)}
236 className={classes.featuredPlan} 224 className={classes.featuredPlan}
237 perUser 225 perUser
238 bestValue 226 bestValue={isPersonalPlanAvailable}
239 >
240 <FeatureList
241 plan={PLANS.PRO}
242 className={classes.featureList}
243 />
244 </PlanItem>
245 <PlanItem
246 name={i18nPlanName(plans.personal.yearly.id, intl)}
247 text={intl.formatMessage(messages.textPersonal)}
248 price={plans.personal.yearly.price}
249 currency={currency}
250 ctaLabel={intl.formatMessage(hadSubscription ? messages.shortActionPersonal : messages.actionTrial)}
251 upgrade={() => upgradeAccount(plans.personal.yearly.id)}
252 > 227 >
253 <FeatureList 228 <FeatureList
254 plan={PLANS.PERSONAL} 229 plan={isPersonalPlanAvailable ? PLANS.PRO : null}
255 className={classes.featureList} 230 className={classes.featureList}
256 /> 231 />
257 </PlanItem> 232 </PlanItem>
233 {isPersonalPlanAvailable && (
234 <PlanItem
235 name={i18nPlanName(plans.personal.yearly.id, intl)}
236 text={intl.formatMessage(messages.textPersonal)}
237 price={plans.personal.yearly.price}
238 currency={currency}
239 ctaLabel={intl.formatMessage(hadSubscription ? messages.shortActionPersonal : messages.actionTrial)}
240 upgrade={() => upgradeAccount(plans.personal.yearly.id)}
241 >
242 <FeatureList
243 plan={PLANS.PERSONAL}
244 className={classes.featureList}
245 />
246 </PlanItem>
247 )}
258 </div> 248 </div>
259 <div className={classes.footer}> 249 <div className={classes.footer}>
260 <a 250 <a
diff --git a/src/features/planSelection/containers/PlanSelectionScreen.js b/src/features/planSelection/containers/PlanSelectionScreen.js
index d202c924e..e4d85cda5 100644
--- a/src/features/planSelection/containers/PlanSelectionScreen.js
+++ b/src/features/planSelection/containers/PlanSelectionScreen.js
@@ -53,7 +53,8 @@ class PlanSelectionScreen extends Component {
53 const { intl } = this.context; 53 const { intl } = this.context;
54 54
55 const { user, features } = this.props.stores; 55 const { user, features } = this.props.stores;
56 const { plans, currency } = features.features.pricingConfig; 56 const { isPersonalPlanAvailable, pricingConfig } = features.features;
57 const { plans, currency } = pricingConfig;
57 const { activateTrial } = this.props.actions.user; 58 const { activateTrial } = this.props.actions.user;
58 const { downgradeAccount, hideOverlay } = this.props.actions.planSelection; 59 const { downgradeAccount, hideOverlay } = this.props.actions.planSelection;
59 60
@@ -95,6 +96,7 @@ class PlanSelectionScreen extends Component {
95 }} 96 }}
96 subscriptionExpired={user.team && user.team.state === 'expired' && !user.team.userHasDowngraded} 97 subscriptionExpired={user.team && user.team.state === 'expired' && !user.team.userHasDowngraded}
97 hadSubscription={user.data.hadSubscription} 98 hadSubscription={user.data.hadSubscription}
99 isPersonalPlanAvailable={isPersonalPlanAvailable}
98 /> 100 />
99 </ErrorBoundary> 101 </ErrorBoundary>
100 ); 102 );