ducky/web

Paddy 2015-06-30 Parent:62e0c0df28bb Child:ef386518fa14

9:e9e0a28a7419 Browse Files

Update to use plans instead of PWYW. If we're going to lean on Stripe for most of our subscription processing, we need to use plans, instead of pay what you want. This updates the page to replace our amount input with a plan select box. It also removes the nonsense about finding your first charge date, because Stripe forced us into a simpler, but harder to predict, billing model. We also updated our CSS to work with select boxes, as well as text inputs.

src/pages/payment.jsx src/styles/onboarding.scss

     1.1 --- a/src/pages/payment.jsx	Thu Jun 04 23:56:35 2015 -0400
     1.2 +++ b/src/pages/payment.jsx	Tue Jun 30 01:16:45 2015 -0400
     1.3 @@ -24,11 +24,19 @@
     1.4        number: null,
     1.5        name: null,
     1.6        cvc: null,
     1.7 +      plan: this.getDefaultPlan(),
     1.8        expireMonth: null,
     1.9        expireYear: null,
    1.10      }
    1.11    },
    1.12  
    1.13 +  getDefaultPlan () {
    1.14 +    if (app.me && app.me.subscription && app.me.subscription.plan) {
    1.15 +      return app.me.subscription.plan
    1.16 +    }
    1.17 +    return 'basic_monthly'
    1.18 +  },
    1.19 +
    1.20    nameValidationOutputs: {
    1.21    },
    1.22    numberValidationOutputs: {
    1.23 @@ -46,6 +54,9 @@
    1.24    balanceValidationOutputs: {
    1.25      'insufficient': 'Your card was declined.',
    1.26    },
    1.27 +  planValidationOutputs: {
    1.28 +    'invalid_value': 'That’s not a valid plan!',
    1.29 +  },
    1.30  
    1.31    catchAllValidationOutputs: {
    1.32    },
    1.33 @@ -59,25 +70,6 @@
    1.34      this.setState({stripeFailedToLoad: true, errors: [{'error': 'act_of_god'}]})
    1.35    },
    1.36  
    1.37 -  getChargeDate () {
    1.38 -    let created = new Date()
    1.39 -    if (app.me && app.me.profile && app.me.profile.created && app.me.profile.created < created) {
    1.40 -      console.log("using register date...")
    1.41 -      created = app.me.profile.created
    1.42 -    }
    1.43 -    let month = created.getMonth()
    1.44 -    let day = created.getDate()
    1.45 -    month = month + 1
    1.46 -    if (day > 1) {
    1.47 -      day = 1
    1.48 -      month = month + 1
    1.49 -    }
    1.50 -    let result = new Date(created.toString())
    1.51 -    result.setDate(day)
    1.52 -    result.setMonth(month)
    1.53 -    return result
    1.54 -  },
    1.55 -
    1.56    addCard (e) {
    1.57      e.preventDefault()
    1.58      if (this.state.stripeLoading || this.state.stripeFailedToLoad) {
    1.59 @@ -149,9 +141,10 @@
    1.60    render () {
    1.61      return (
    1.62        <div className='container'>
    1.63 -        <HeroUnit title='Add a Payment Method'>Gotta keep our servers online and food on the table.</HeroUnit>
    1.64 +        <HeroUnit title='Set Up Your Subscription'>Gotta pay those bills.</HeroUnit>
    1.65          <article className='onboarding payment'>
    1.66 -          <p>Ducky costs $2 a month to use. We’ll charge the card you enter below on the first of every month until your account is disabled. You won’t be charged before {this.getChargeDate().toLocaleDateString(navigator.languages, {month: 'long', year: 'numeric', day: 'numeric'})}.</p>
    1.67 +          <p>Ducky costs money to run, and to keep it improving. We pass these costs on to you. There’s no parent company, no ads, nothing but people making software they want you to enjoy. Also, you get a
    1.68 +          free 31 day trial. Cancel before it ends, and we won’t charge you at all.</p>
    1.69            <form onSubmit={this.addCard}>
    1.70              <div>
    1.71                <label htmlFor='name'>Cardholder Name</label>
    1.72 @@ -170,11 +163,21 @@
    1.73                <input id='expireYear'  className='expiration year' type='text' placeholder='15' valueLink={this.linkState('expireYear')} />
    1.74                <ValidationError errors={this.state.errors} field='/cvc' outputs={this.cvcValidationOutputs} />
    1.75                <ValidationError errors={this.state.errors} field='/expiration' outputs={this.expirationValidationOutputs} />
    1.76 +
    1.77 +              <label htmlFor='plan'>Plan</label>
    1.78 +              <select id='plan' className='plan' defaultValue={this.getDefaultPlan()}>
    1.79 +                <option value='basic_monthly'>Basic Monthly - $2/month</option>
    1.80 +                <option value='basic_yearly'>Basic Yearly - $20/year</option>
    1.81 +                <option value='supporter_monthly'>Supporter Monthly - $5/month</option>
    1.82 +                <option value='supporter_yearly'>Supporter Yearly - $50/year</option>
    1.83 +              </select>
    1.84 +              <ValidationError errors={this.state.errors} field='/plan' outputs={this.planValidationOutputs} />
    1.85 +              <p>There’s no difference between the Supporter and Basic tiers. The Supporter tier is just for people who love Ducky and want to see it grow and improve.</p>
    1.86 +
    1.87                <ValidationError errors={this.state.errors} field='/balance' outputs={this.balanceValidationOutputs} />
    1.88 -              <ValidationError errors={this.state.errors} notFields={['/name', '/number', '/cvc', '/expiration', '/balance']} notParams={[]} notHeaders={[]} outputs={this.catchAllValidationOutputs} />
    1.89 +              <ValidationError errors={this.state.errors} notFields={['/name', '/number', '/cvc', '/expiration', '/plan', '/balance']} notParams={[]} notHeaders={[]} outputs={this.catchAllValidationOutputs} />
    1.90  
    1.91                <div className='actionbuttons'>
    1.92 -                <button type='button' onClick={this.skip} className='ladda-button' disabled={this.state.active}>Not Now</button>
    1.93                  <LaddaButton style='expand-right' active={this.state.active}>
    1.94                    <button type='submit' className='primary' disabled={this.state.stripeLoading || this.state.stripeFailedToLoad || this.state.active || this.state.errors.length}>Add Card</button>
    1.95                  </LaddaButton>
     2.1 --- a/src/styles/onboarding.scss	Thu Jun 04 23:56:35 2015 -0400
     2.2 +++ b/src/styles/onboarding.scss	Tue Jun 30 01:16:45 2015 -0400
     2.3 @@ -18,7 +18,7 @@
     2.4  		list-style-type: square;
     2.5  	}
     2.6  
     2.7 -	#{$all-text-inputs}, label {
     2.8 +	#{$all-text-inputs}, label, select {
     2.9  		display: inline-block;
    2.10  	}
    2.11  
    2.12 @@ -26,12 +26,12 @@
    2.13  		max-width: 35%;
    2.14  	}
    2.15  
    2.16 -	#{$all-text-inputs} {
    2.17 +	#{$all-text-inputs}, select {
    2.18  		width: 65%;
    2.19  	}
    2.20  
    2.21  	&.register {
    2.22 -		#{$all-text-inputs} {
    2.23 +		#{$all-text-inputs}, select {
    2.24  			width: 60%;
    2.25  		}
    2.26  
    2.27 @@ -47,10 +47,14 @@
    2.28  		}
    2.29  	}
    2.30  	&.payment {
    2.31 -		#{$all-text-inputs} {
    2.32 +		#{$all-text-inputs}, select {
    2.33  			width: 60%;
    2.34  		}
    2.35  
    2.36 +		select {
    2.37 +			font-size: 1.5em;
    2.38 +		}
    2.39 +
    2.40  		input.expiration {
    2.41  			width: 10%;
    2.42  		}
    2.43 @@ -79,6 +83,10 @@
    2.44  			padding-right: 1em;
    2.45  		}
    2.46  
    2.47 +		select.plan {
    2.48 +			margin-bottom: 0.5em;
    2.49 +		}
    2.50 +
    2.51  		form {
    2.52  			font-size: 75%;
    2.53  			margin: 0px auto;