110 lines
3.6 KiB
JavaScript
110 lines
3.6 KiB
JavaScript
// License: LGPL-3.0-or-later
|
|
const h = require('snabbdom/h')
|
|
const R = require('ramda')
|
|
const validatedForm = require('ff-core/validated-form')
|
|
const button = require('ff-core/button')
|
|
const flyd = require('flyd')
|
|
flyd.flatMap = require('flyd/module/flatmap')
|
|
flyd.filter = require('flyd/module/filter')
|
|
flyd.sampleOn = require('flyd/module/sampleon')
|
|
const scanMerge = require('flyd/module/scanmerge')
|
|
const IBAN = require('iban')
|
|
|
|
|
|
const request = require('../common/request')
|
|
|
|
// Form validation constraints, validator functions, and error messages:
|
|
const constraints = {
|
|
name: {required: true}
|
|
, iban: {required: true, ibanFormat: /[a-zA-Z]{2}\d{14}/}
|
|
, bic: {required: true}
|
|
}
|
|
|
|
const validators = { ibanFormat: IBAN.isValid }
|
|
|
|
// You can pass in the .hideButton boolean if you want to control whether the submit button is shown/hidden
|
|
// Pass in a .card object, which can have default objects for the card form (name, number, cvc, exp_month, etc)
|
|
// Pass in .path to set the endpoint for saving the card
|
|
// Pass in .payload for default data to send to the server for every card save request (such as a request token)
|
|
const init = (state) => {
|
|
state = state || {}
|
|
|
|
var messages = {
|
|
required: I18n.t('nonprofits.donate.payment.card.errors.field.presence')
|
|
, ibanFormat: I18n.t('nonprofits.donate.payment.card.errors.field.format')
|
|
}
|
|
|
|
state.form = validatedForm.init({constraints, validators, messages})
|
|
state.supp$ = flyd.sampleOn(state.form.validData$, state.supporter)
|
|
state.sepa$ = flyd.combine((supporter, sepaParams) => {
|
|
return {sepa_params: sepaParams(), supporter_id: supporter()}
|
|
}, [state.supp$, state.form.validData$])
|
|
|
|
const response$ = flyd.flatMap(saveTransferData, state.sepa$)
|
|
state.reponseOk$ = flyd.filter(response => !response.error, response$)
|
|
state.error$ = flyd.map(R.prop('error'), flyd.filter(response => response.error, state.reponseOk$))
|
|
state.saved$ = flyd.filter(response => !response.error, state.reponseOk$)
|
|
|
|
state.loading$ = scanMerge([
|
|
[state.form.validSubmit$, R.always(true)]
|
|
, [state.error$, R.always(false)]
|
|
, [state.saved$, R.always(false)]
|
|
], false)
|
|
|
|
return state
|
|
}
|
|
|
|
// Save transfer details to our own servers, and return a response stream
|
|
function saveTransferData(params){
|
|
return flyd.map(R.prop('body'), request({
|
|
method: 'post'
|
|
, path: '/sepa'
|
|
, send: params
|
|
}).load
|
|
)
|
|
}
|
|
|
|
// -- Virtual DOM
|
|
|
|
const view = state => {
|
|
var field = validatedForm.field(state.form)
|
|
return validatedForm.form(state.form, h('form.sepaForm', [
|
|
h('div.u-background--grey.group.u-padding--8', [
|
|
nameInput(field)
|
|
, ibanInput(field)
|
|
, bicInput(field)
|
|
])
|
|
, h('div.u-centered', [
|
|
button({
|
|
error$: state.hideErrors ? flyd.stream() : state.error$
|
|
, buttonText: I18n.t('nonprofits.donate.payment.card.submit')
|
|
, loadingText: ` ${I18n.t('nonprofits.donate.payment.card.loading')}`
|
|
, loading$: state.loading$
|
|
})
|
|
])
|
|
])
|
|
)
|
|
}
|
|
|
|
const nameInput = (field, name) =>
|
|
h('fieldset', [
|
|
field(h('input.u-margin--0',
|
|
{ props: { name: 'name' , value: name || '', placeholder: I18n.t('nonprofits.donate.payment.sepa.name') } }
|
|
))
|
|
])
|
|
|
|
const ibanInput = field =>
|
|
h('fieldset.col-12.u-margin--0', [
|
|
field(h('input.u-margin--0',
|
|
{props: { type: 'text' , name: 'iban' , placeholder: I18n.t('nonprofits.donate.payment.sepa.iban') } }
|
|
))
|
|
])
|
|
|
|
const bicInput = field =>
|
|
h('fieldset.col-right-0.u-margin--0', [
|
|
field(h('input.u-margin--0.hidden',
|
|
{ props: { name: 'bic' , type: 'hidden', value:'NOTPROVIDED', placeholder: I18n.t('nonprofits.donate.payment.sepa.bic') } }
|
|
))
|
|
])
|
|
|
|
module.exports = {view, init}
|