houdini/client/js/cards/create.js

130 lines
3.6 KiB
JavaScript
Raw Normal View History

// License: LGPL-3.0-or-later
// Include the cards/fields partial to use with this.
// Call appl.card_form.create(card_obj) to start the card creation process.
// Use the appl.card_form.on_fail callback to handle failures.
// Use the appl.card_form.on_complete callback to handle completion.
// This does not create any donations -- do the donation creation inside appl.card_form.on_complete.
// Not namespacing card_form; only show one card form on the page at any time
var request = require('../common/super-agent-promise')
var format_err = require('../common/format_response_error')
module.exports = create_card
// UI state defaults
appl.def('card_form', {
loading: false,
error: false,
status: '',
on_complete: function() {},
on_fail: function() {},
progress_width: '0%' // Width of the progress bar
})
// Define some status messages and progress bar widths for each step of the process
var statuses = {
before_tokenization: {
progress_width: '20%',
status: 'Double-checking your card...'
},
before_create: {
progress_width: '75%',
status: 'Looks good! Sending the carrier pigeons...'
},
on_complete: {
progress_width: '100%',
status: 'Processing payment...'
}
}
// Tokenize with stripe, then save to our db.
// The first argument must be a holder object that has 'type' and 'id' keys.
// eg: {holder: {type: 'Nonprofit', id: 1}}
function create_card(holder, card_obj, options) {
options = options || {}
if(appl.card_form.loading) return
appl.def('card_form', { loading: true, error: false })
appl.def('card_form', statuses.before_tokenization)
// Delete the cvc key from card_obj if
// the value of cvc is a blank string.
// Otherwise, Stripe will return an error for
// incorrect security code.
if(card_obj.cvc === '') {
delete card_obj['cvc']
}
// First, tokenize the card with Stripe.js
return tokenize_with_stripe(card_obj)
.catch(display_stripe_err)
// Then, save a Card record in our db
.then(function(stripe_resp) {
appl.def('card_form', statuses.before_create)
return create_record(holder, stripe_resp, options)
})
.then(function(resp) {
appl.def('card_form', statuses.on_complete)
return resp.body
})
.catch(display_err)
}
// Post to stripe to get back a stripe_card_token
function tokenize_with_stripe(card_obj) {
return new Promise(function(resolve, reject) {
Stripe.card.createToken(card_obj, function(status, resp) {
if(resp.error) reject(resp)
else resolve(resp)
})
})
}
// Save a record of the card in our own db
function create_record(holder, stripe_resp, options={}) {
var output = {card: {
holder_type: holder.type,
holder_id: holder.id,
email: holder.email,
cardholders_name: stripe_resp.name,
name: stripe_resp.card.brand + ' *' + stripe_resp.card.last4,
stripe_card_token: stripe_resp.id,
stripe_card_id: stripe_resp.card.id
}}
if (options['event_id'])
{
output['event_id'] = options['event_id']
}
return request.post(options.path || '/cards')
.send(output)
.perform()
}
// Set UI state to display an error in the card form.
function display_err(resp) {
if(resp && resp.body) {
appl.def('card_form', {
loading: false,
error: true,
status: format_err(resp),
progress_width: '0%'
})
appl.def('loading', false)
}
}
function display_stripe_err(resp) {
if(resp && resp.error) {
appl.def('card_form', {
loading: false,
error: true,
status: resp.error.message,
progress_width: '0%'
})
appl.def('loading', false)
throw new Error()
}
}