Skip to content

Instantly share code, notes, and snippets.

@flavienbonvin
Last active July 10, 2019 08:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flavienbonvin/313e675c4b9ce7a6bb67d4c994b588b2 to your computer and use it in GitHub Desktop.
Save flavienbonvin/313e675c4b9ce7a6bb67d4c994b588b2 to your computer and use it in GitHub Desktop.
import { Button, Col, Divider, Modal, Radio, Row, Spin } from 'antd'
import React, { Component } from 'react'
import { USER_STATUS_BASIC, USER_STATUS_PREMIUM, USER_STATUS_STARTER } from '../../models/User'
import { Pricing } from '../../models/Pricing'
import { StripeForm } from './StripeForm'
import axios from 'axios'
import { track } from '../../helpers/trackerHelper'
import withCurrentUser from '../currentUser/withCurrentUser'
import { compose } from 'recompose'
import _ from 'lodash'
import { $, key } from '../../localization/localization'
import firebase from 'firebase/app'
import { getCustomerCardInformation } from '../../helpers/customerCardInformation'
const RadioGroup = Radio.Group
const withModal = (WrappedComponent) => ({children, visible, handleCancel, onToken, currentUser, loading, upgradeTo, onChange, selectedStatus, cardRegistered, stripeSubscriptionId}) => {
return (
<WrappedComponent>
<Modal
visible={visible}
onCancel={handleCancel}
title={$(key.pricingModalTitle)}
footer={null}
width={893}>
{loading
? (
<div className="loader-modal">
<Spin size='large'/>
</div>
)
: (
<RadioGroup onChange={onChange} name="radiogroup" className="pricing-modal" defaultValue={2}>
<p style={{textAlign: 'center'}}>{$(key.pricingModalDescription)}</p>
<Row style={{textAlign: 'center', marginBottom: '17px'}}>
<Col lg={8}>
<div className='pricing-plan'>
<p className="pricing-title-p-tag">{$(key.pricingModalBasicTitle)}</p>
<Divider/>
<img src={process.env.PUBLIC_URL + '/images/icon_basic.png'} style={{height: '80px', width: '80px', marginBottom: '17px'}}
alt='icon_basic'/>
<p style={{marginBottom: '37px'}}>{$(key.pricingModalBasicNumberPlans)}</p>
<p style={{marginBottom: '0px'}}>{Pricing.priceWithCurrentCurrency(USER_STATUS_BASIC)}</p>
<p style={{padding: '20px'}}>{$(key.pricingModalChargedHow, Pricing.annualPriceWithCurrentCurrency(USER_STATUS_BASIC))}</p>
</div>
{_.isEmpty(currentUser.status) ||
![USER_STATUS_BASIC, USER_STATUS_STARTER, USER_STATUS_PREMIUM].includes(currentUser.status) ||
(currentUser.status === USER_STATUS_BASIC && currentUser.hasOutdatedSubscription()) ||
!currentUser.stripeSubscriptionId
? <Radio value={1}/>
: null
}
</Col>
<Col lg={8}>
<div className='pricing-plan pricing-premium'>
<p className="pricing-title-p-tag">{$(key.pricingModalPremiumTitle)}</p>
<Divider/>
<img src={process.env.PUBLIC_URL + '/images/icon_premium.png'} style={{marginBottom: '17px'}} alt='icon_premium'/>
<p style={{marginBottom: '37px'}}>{$(key.pricingModalPremiumNumberPlans)}</p>
<p style={{marginBottom: '0px'}}>{Pricing.priceWithCurrentCurrency(USER_STATUS_PREMIUM)}</p>
<p style={{padding: '20px'}}>{$(key.pricingModalChargedHow, Pricing.annualPriceWithCurrentCurrency(USER_STATUS_PREMIUM))}</p>
</div>
{_.isEmpty(currentUser.status) || ![USER_STATUS_PREMIUM].includes(currentUser.status) || (currentUser.status === USER_STATUS_PREMIUM && currentUser.hasOutdatedSubscription())
? <Radio value={2}/>
: null
}
</Col>
<Col lg={8}>
<div className='pricing-plan'>
<p className="pricing-title-p-tag">{$(key.pricingModalStarterTitle)}</p>
<Divider/>
<img src={process.env.PUBLIC_URL + '/images/icon_starter.png'} style={{height: '80px', width: '80px', marginBottom: '17px'}}
alt='icon_starter'/>
<p style={{marginBottom: '37px'}}>{$(key.pricingModalStarterNumberPlans)}</p>
<p style={{marginBottom: '0px'}}>{Pricing.priceWithCurrentCurrency(USER_STATUS_STARTER)}</p>
<p style={{padding: '20px'}}>{$(key.pricingModalChargedHow, Pricing.annualPriceWithCurrentCurrency(USER_STATUS_STARTER))}</p>
</div>
{_.isEmpty(currentUser.status) || ![USER_STATUS_STARTER, USER_STATUS_PREMIUM].includes(currentUser.status) || (currentUser.status === USER_STATUS_STARTER && currentUser.hasOutdatedSubscription())
? <Radio value={3}/>
: null
}
</Col>
</Row>
<hr/>
<div className="button-div">
<Button className="cancel-button" onClick={handleCancel}>{$(key.cancel)}</Button>
{cardRegistered
? <Button type='primary' onClick={() => upgradeTo(selectedStatus)}>{$(key.pricingModalUpgradePlanCTA)}</Button>
: stripeSubscriptionId
? <StripeForm status={selectedStatus} onToken={() => upgradeTo(selectedStatus)}/>
: <StripeForm status={selectedStatus} onToken={onToken}/>
}
</div>
</RadioGroup>
)
}
</Modal>
{children}
</WrappedComponent>
)
}
const DivWithModal = withModal(({children}) => <div>{children}</div>)
class PricingModal extends Component {
state = {
visible: false,
loading: false,
selectedStatus: USER_STATUS_PREMIUM,
cardInformation: {},
}
showModal = () => {
this.setState({visible: true, selectedStatus: USER_STATUS_PREMIUM})
track('pricing_modal', {from: this.props.from})
axios.post(`${process.env.REACT_APP_FUNCTION_URL}/updateStripeName`, {
userId: this.props.currentUser.id,
name: firebase.auth().currentUser.displayName
})
}
handleCancel = () => this.setState({visible: false, loading: false})
onToken = (token, planId) => {
this.setState({loading: true})
axios.post(`${process.env.REACT_APP_FUNCTION_URL}/createStripeSubscription`, {
userId: this.props.currentUser.id,
stripeCustomerId: this.props.currentUser.stripeCustomerId,
stripePlanId: planId,
token: token.id
})
.then(() => {
track('user_subscribed', {plan: Pricing.planTypeFor(planId)})
this.setState({loading: false, visible: false})
})
.catch((e) => {
this.setState({loading: false, visible: false})
})
}
upgradeTo = (status) => {
this.setState({loading: true})
const planId = Pricing.planIdForCurrentCurrency(status)
axios.post(`${process.env.REACT_APP_FUNCTION_URL}/updateStripeSubscription`, {
userId: this.props.currentUser.id,
stripeCustomerId: this.props.currentUser.stripeCustomerId,
stripeSubscriptionId: this.props.currentUser.stripeSubscriptionId,
stripePlanId: planId,
})
.then(() => {
track('user_upgraded', {plan: Pricing.planTypeFor(planId)})
this.setState({loading: false, visible: false})
})
.catch((e) => {
this.setState({loading: false, visible: false})
})
}
onChange = (e) => {
let selectedStatus
switch (e.target.value) {
case 1:
selectedStatus = USER_STATUS_BASIC
break
case 2:
selectedStatus = USER_STATUS_PREMIUM
break
case 3:
selectedStatus = USER_STATUS_STARTER
break
default:
break
}
this.setState({
selectedStatus: selectedStatus,
})
}
componentWillMount () {
getCustomerCardInformation(this.props.currentUser.id).then(cardInformation => {
this.setState({cardInformation: cardInformation})
})
}
render () {
const {buttonRendering, currentUser} = this.props
const {cardRegistered} = this.state.cardInformation
const {visible, loading, selectedStatus} = this.state
if (this.props.currentUser.status === USER_STATUS_PREMIUM && !this.props.currentUser.hasOutdatedSubscription()) {
return null
} else {
return (
<DivWithModal visible={visible} handleCancel={this.handleCancel} onToken={this.onToken} currentUser={currentUser} loading={loading}
upgradeTo={this.upgradeTo} onChange={this.onChange} selectedStatus={selectedStatus} cardRegistered={cardRegistered}
stripeSubscriptionId={currentUser.stripeSubscriptionId}>
<div onClick={this.showModal}>
{buttonRendering}
</div>
</DivWithModal>
)
}
}
}
export default compose(
withCurrentUser
)(PricingModal)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment