187 lines
6.4 KiB
JavaScript
187 lines
6.4 KiB
JavaScript
// License: LGPL-3.0-or-later
|
|
const h = require('snabbdom/h')
|
|
const R = require('ramda')
|
|
const flyd = require('flyd')
|
|
const uuid = require('uuid')
|
|
const supporterFields = require('../../components/supporter-fields')
|
|
const button = require('ff-core/button')
|
|
const dedicationForm = require('./dedication-form')
|
|
const serialize = require('form-serialize')
|
|
const request = require('../../common/request')
|
|
const format = require('../../common/format')
|
|
|
|
const sepaTab = 'sepa'
|
|
const cardTab = 'credit_card'
|
|
|
|
function init(donation$, parentState) {
|
|
//console.log(donation$().val);
|
|
var state = {
|
|
donation$: donation$
|
|
, submitSupporter$: flyd.stream()
|
|
, submitDedication$: flyd.stream()
|
|
, params$: parentState.params$
|
|
, currentStep$: flyd.stream()
|
|
, selectedPayment$: parentState.selectedPayment$
|
|
}
|
|
|
|
|
|
// Save supporter for dedication logic
|
|
state.dedicationData$ = flyd.map(form => serialize(form, {hash: true}), state.submitDedication$)
|
|
const dedicationSuppData$ = flyd.map(
|
|
data => R.merge(
|
|
R.pick(['phone', 'email', 'address'], data)
|
|
, {name: `${data.first_name||''} ${data.last_name||''}`}
|
|
)
|
|
, state.dedicationData$
|
|
)
|
|
state.showDedicationForm$ = flyd.map(()=> false, state.submitDedication$)
|
|
|
|
// Save donor supporter record
|
|
state.supporterFields = supporterFields.init({required: {email: true}}, parentState.params$)
|
|
state.savedSupp$ = flyd.flatMap(postSupporter , flyd.map(formatFormData, state.submitSupporter$))
|
|
state.savedDedicatee$ = flyd.map(
|
|
supporter => ({supporter, note: state.dedicationData$().dedication_note, type: state.dedicationData$().dedication_type})
|
|
, flyd.flatMap(postSupporter, dedicationSuppData$)
|
|
)
|
|
const changedDedication$ = flyd.merge(state.dedicationData$, state.savedDedicatee$)
|
|
state.supporter$ = flyd.merge(flyd.stream({}), state.savedSupp$)
|
|
|
|
return state
|
|
}
|
|
|
|
const formatFormData = form => {
|
|
const data = serialize(form, {hash: true})
|
|
return R.evolve({customFields: R.toPairs}, data)
|
|
}
|
|
|
|
const postSupporter = supporter =>
|
|
flyd.map(
|
|
resp => resp.body
|
|
, request({
|
|
method: 'post'
|
|
, path: `/nonprofits/${app.nonprofit_id}/supporters`
|
|
, send: R.merge(supporter, {locale: I18n.locale})
|
|
}).load
|
|
)
|
|
|
|
|
|
const customFields = fields => {
|
|
if(!fields) return ''
|
|
const input = field => h('input', {
|
|
props: {
|
|
name: `customFields[${field.name}]`
|
|
, placeholder: field.label
|
|
}
|
|
})
|
|
return h('div', R.map(input, fields))
|
|
}
|
|
|
|
function recurringMessage(state){
|
|
//function recurringMessage(isRecurring, state) {
|
|
var isRecurring=state.donation$().recurring;
|
|
var amountLabel = isRecurring ? ` ${I18n.t('nonprofits.donate.payment.monthly_recurring')}` : ` ${I18n.t('nonprofits.donate.payment.one_time')}`
|
|
var weekly= "";
|
|
if (state.donation$().weekly) {
|
|
amountLabel = amountLabel.replace(I18n.t('nonprofits.donate.amount.monthly'),I18n.t('nonprofits.donate.amount.weekly')) + "*";
|
|
weekly= h('div.u-centered.notice',[h("small",I18n.t('nonprofits.donate.amount.weekly_notice',{amount:(format.weeklyToMonthly(state.donation$().amount)/100.0),currency:app.currency_symbol}))]);
|
|
|
|
}
|
|
return h('div', [
|
|
h('p.u-fontSize--18 u.marginBottom--0.u-centered.amount', [
|
|
h('span', app.currency_symbol + format.centsToDollars(state.donation$().amount))
|
|
, h('strong', amountLabel)
|
|
])
|
|
, weekly]
|
|
)
|
|
}
|
|
|
|
function view(state) {
|
|
|
|
var form = h('form', {
|
|
on: {
|
|
submit: ev => {ev.preventDefault(); state.currentStep$(2); state.submitSupporter$(ev.currentTarget)}
|
|
}
|
|
}, [
|
|
recurringMessage(state)
|
|
, supporterFields.view(state.supporterFields)
|
|
, customFields(state.params$().custom_fields)
|
|
, dedicationLink(state)
|
|
, app.nonprofit.no_anon ? '' : anonField(state)
|
|
, h('fieldset.u-inlineBlock.u-marginTop--10', paymentMethodButtons(["card", "sepa"], state))
|
|
])
|
|
return h('div.wizard-step.info-step.u-padding--10', [
|
|
form
|
|
, h('div', {
|
|
style: {background: '#f8f8f8', position: 'absolute', 'top': '0', left: '3px', height: '100%', width: '99%'}
|
|
, class: {'u-hide': !state.showDedicationForm$(), opacity: 0, transition: 'opacity 1s', delay: {opacity: 1}}
|
|
}, [dedicationForm.view(state)] )
|
|
])
|
|
}
|
|
|
|
function paymentMethodButtons(paymentMethods, state){
|
|
return h('section.group'), [
|
|
paymentButton({error$: state.errors$, buttonText: I18n.t('nonprofits.donate.payment.tabs.sepa')}, sepaTab, state)
|
|
, paymentButton({error$: state.errors$, buttonText: I18n.t('nonprofits.donate.payment.tabs.card')}, cardTab, state)
|
|
]
|
|
}
|
|
|
|
function paymentButton(options, label, state){
|
|
options.error$ = options.error$ || flyd.stream()
|
|
options.loading$ = options.loading$ || flyd.stream()
|
|
|
|
let btnclass={ 'ff-button--loading': options.loading$() };
|
|
btnclass[label]=true;
|
|
|
|
return h('div.ff-buttonWrapper.u-floatL.u-marginBottom--10', {
|
|
class: { 'ff-buttonWrapper--hasError': options.error$() }
|
|
}, [
|
|
h('p.ff-button-error', {style: {display: options.error$() ? 'block' : 'none'}} , options.error$())
|
|
, h('button.ff-button', {
|
|
props: { type: 'submit', disabled: options.loading$() }
|
|
, on: { click: e => state.selectedPayment$(label) }
|
|
, class: btnclass
|
|
}, [
|
|
options.loading$() ? (options.loadingText || " Saving...") : (options.buttonText || I18n.t('nonprofits.donate.payment.card.submit'))
|
|
])
|
|
])
|
|
}
|
|
|
|
function anonField(state) {
|
|
state.anon_id = state.anon_id || uuid.v1() // we need a unique id in case there are multiple supporter forms on the page -- the label 'for' attribute needs to be unique
|
|
return h('div.u-marginTop--10.u-centered', [
|
|
h('input', {
|
|
props: {
|
|
type: 'checkbox'
|
|
, name: 'anonymous'
|
|
, checked: state.anonymous
|
|
, id: `anon-checkbox-${state.anon_id}`
|
|
}
|
|
})
|
|
, h('label', {
|
|
props: {
|
|
type: 'checkbox'
|
|
, htmlFor: `anon-checkbox-${state.anon_id}`
|
|
, id: 'anonLabel'
|
|
}
|
|
}, [
|
|
h('small', I18n.t('nonprofits.donate.info.anonymous_checkbox'))
|
|
])
|
|
])
|
|
}
|
|
|
|
const dedicationLink = state => {
|
|
if(state.params$().hide_dedication) return ''
|
|
return h('label.u-centered.u-marginTop--10', [
|
|
h('small', [
|
|
h('a', {
|
|
on: {click: [state.showDedicationForm$, true]}
|
|
}, state.dedicationData$() && state.dedicationData$().first_name
|
|
? [h('i.fa.fa-check'), I18n.t('nonprofits.donate.info.dedication_saved') + `${state.dedicationData$().first_name || ''} ${state.dedicationData$().last_name || ''}`]
|
|
: [I18n.t('nonprofits.donate.info.dedication_link')]
|
|
)
|
|
])
|
|
])
|
|
}
|
|
|
|
|
|
module.exports = {view, init}
|