199 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// License: LGPL-3.0-or-later
 | 
						|
const h = require('snabbdom/h')
 | 
						|
const R = require('ramda')
 | 
						|
const flyd = require('flyd')
 | 
						|
const format = require('../../common/format')
 | 
						|
flyd.scanMerge = require('flyd/module/scanmerge')
 | 
						|
 | 
						|
function init(donationDefaults, params$) {
 | 
						|
    var state = {
 | 
						|
        params$: params$
 | 
						|
        , evolveDonation$: flyd.stream() // Stream of objects that can be used to R.evolve the initial donation object
 | 
						|
        , buttonAmountSelected$: flyd.stream(true) // Whether the button or input is selected
 | 
						|
        , currentStep$: flyd.stream()
 | 
						|
    }
 | 
						|
 | 
						|
  // A stream of objects that an be used to modify the existing donation by using R.evolve
 | 
						|
  donationDefaults = R.merge(donationDefaults, {
 | 
						|
    amount: format.dollarsToCents(state.params$().single_amount || 0)
 | 
						|
  , designation: state.params$().designation
 | 
						|
  , recurring: state.params$().type === 'recurring'
 | 
						|
  , weekly: (typeof state.params$().weekly !== 'undefined')
 | 
						|
  })
 | 
						|
  // Apply R.evolve using every value on the evolveDonation$ stream, starting with the defaults
 | 
						|
  state.donation$ = flyd.scanMerge([
 | 
						|
    [state.params$ || flyd.stream(), setDonationFromParams]
 | 
						|
  , [state.evolveDonation$, R.flip(R.evolve)]
 | 
						|
  ], donationDefaults)
 | 
						|
 | 
						|
    return state
 | 
						|
}
 | 
						|
 | 
						|
const setDonationFromParams = (donation, params) => {
 | 
						|
    if(params.single_amount) {
 | 
						|
        donation.amount = format.dollarsToCents(params.single_amount)
 | 
						|
    }
 | 
						|
    else
 | 
						|
        donation.amount = undefined
 | 
						|
    if(params.designation)
 | 
						|
        donation.designation = params.designation
 | 
						|
    else
 | 
						|
        donation.designation = undefined
 | 
						|
    if (params.type === 'recurring')
 | 
						|
        donation.recurring = true
 | 
						|
    else
 | 
						|
        donation.recurring = undefined
 | 
						|
    return donation
 | 
						|
}
 | 
						|
 | 
						|
function view(state) {
 | 
						|
    const isRecurring = state.donation$().recurring
 | 
						|
    return h('div.wizard-step.amount-step', [
 | 
						|
        chooseDesignation(state)
 | 
						|
        , recurringCheckbox(isRecurring, state)
 | 
						|
        , recurringMessage(isRecurring, state)
 | 
						|
        , amountFields(state)
 | 
						|
        , showSingleAmount(isRecurring, state)
 | 
						|
    ])
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Dropdown to choose among custom designations
 | 
						|
function chooseDesignation(state) {
 | 
						|
  if(!state.params$().multiple_designations) return ''
 | 
						|
  var defaultDesigs = [
 | 
						|
    state.params$().designations_prompt || I18n.t('nonprofits.donate.amount.designation.choose')
 | 
						|
  , I18n.t('nonprofits.donate.amount.designation.most_needed')
 | 
						|
  ]
 | 
						|
  return h('section.u-paddingX--5', {
 | 
						|
    class: {'u-hide': !state.params$().multiple_designations}
 | 
						|
  }, [
 | 
						|
    h('select.donate-designationDropdown.select.u-marginBottom--10', {
 | 
						|
      on: { change: ev => state.evolveDonation$({designation: R.always(ev.currentTarget.value)}) }
 | 
						|
    }, R.concat(
 | 
						|
        R.map(
 | 
						|
          d => h('option', {props: {value: ''}}, d)
 | 
						|
        , defaultDesigs
 | 
						|
        )
 | 
						|
      , R.map(
 | 
						|
          d => h('option', {props: {value: d}}, d)
 | 
						|
        , state.params$().multiple_designations
 | 
						|
            )
 | 
						|
        )
 | 
						|
    )
 | 
						|
    ])
 | 
						|
}
 | 
						|
 | 
						|
// Checkbox to make the donation monthly recurring
 | 
						|
function recurringCheckbox(isRecurring, state) {
 | 
						|
  if(state.params$().type === 'recurring' || state.params$().type === 'one-time') return ''
 | 
						|
  return h('section.donate-recurringCheckbox.u-paddingX--5 u-marginBottom--10', [
 | 
						|
    h('div.u-padding--8.u-background--grey.u-centered', {
 | 
						|
      class: {highlight: isRecurring}
 | 
						|
    }, [
 | 
						|
      h('input.u-margin--0.donationWizard-amount-input', {
 | 
						|
        props: {type: 'checkbox', selected: isRecurring, id: 'checkbox-recurring'}
 | 
						|
      , on: {change: ev => state.evolveDonation$({recurring: t => !t})}
 | 
						|
      })
 | 
						|
    , h('label', {props: {htmlFor: 'checkbox-recurring'}}, composeTranslation(
 | 
						|
          I18n.t('nonprofits.donate.amount.sustaining')
 | 
						|
        , I18n.t('nonprofits.donate.amount.sustaining_bold')
 | 
						|
        )
 | 
						|
      )
 | 
						|
    ])
 | 
						|
    ])
 | 
						|
}
 | 
						|
 | 
						|
// If recurring, an extra message to reinforce that it is in fact charged every month
 | 
						|
function recurringMessage(isRecurring, state) {
 | 
						|
  if(!isRecurring) return ''
 | 
						|
  var label=I18n.t('nonprofits.donate.amount.sustaining_selected')
 | 
						|
  var bolded=I18n.t('nonprofits.donate.amount.sustaining_selected_bold');
 | 
						|
  if (state.donation$().weekly) {
 | 
						|
    label = label.replace(I18n.t('nonprofits.donate.amount.monthly'),I18n.t('nonprofits.donate.amount.weekly'));
 | 
						|
     bolded=I18n.t('nonprofits.donate.amount.weekly');
 | 
						|
  }
 | 
						|
  return h('section.donate-recurringMessage.group', [
 | 
						|
    h('p.u-paddingX--5.u-centered', {
 | 
						|
      class: {'u-hide': !isRecurring}
 | 
						|
    }, [
 | 
						|
      state.params$().single_amount ? '' : h('small.info', composeTranslation(label,bolded))
 | 
						|
      ])
 | 
						|
    ])
 | 
						|
}
 | 
						|
 | 
						|
function prependCurrencyClassname() {
 | 
						|
  if (app.currency_symbol === '$') {
 | 
						|
    return 'prepend--dollar'
 | 
						|
  } else if (app.currency_symbol === '€') {
 | 
						|
    return 'prepend--euro'
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function composeTranslation(full, bold) {
 | 
						|
  const texts = full.split(bold)
 | 
						|
  if(texts.length > 1) {
 | 
						|
    return [texts[0], h('strong', bold), texts[1]]
 | 
						|
  } else {
 | 
						|
    return full
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// All the buttons and the custom input for the amounts to select
 | 
						|
function amountFields(state) {
 | 
						|
  if(state.params$().single_amount) return ''
 | 
						|
  return h('div.u-inline.fieldsetLayout--three--evenPadding', [
 | 
						|
    h('span',
 | 
						|
      R.map(
 | 
						|
        amt => h('fieldset', [
 | 
						|
          h('button.button.u-width--full.white.amount', {
 | 
						|
            class: {'is-selected': state.buttonAmountSelected$() && state.donation$().amount === amt*100}
 | 
						|
          , on: {click: ev => {
 | 
						|
              state.evolveDonation$({amount: R.always(format.dollarsToCents(amt))})
 | 
						|
              state.buttonAmountSelected$(true)
 | 
						|
              state.currentStep$(1) // immediately advance steps when selecting an amount button
 | 
						|
            } }
 | 
						|
          }, [
 | 
						|
            h('span.dollar', app.currency_symbol)
 | 
						|
          , String(amt)
 | 
						|
          ])
 | 
						|
        ])
 | 
						|
    , state.params$().custom_amounts || [] )
 | 
						|
    )
 | 
						|
  , h('fieldset.' + prependCurrencyClassname(), [
 | 
						|
      h('input.amount.other', {
 | 
						|
        props: {name: 'amount', step: 'any', type: 'number', min: 1, placeholder: I18n.t('nonprofits.donate.amount.custom')}
 | 
						|
      , class: {'is-selected': !state.buttonAmountSelected$()}
 | 
						|
      , on: {
 | 
						|
          focus: ev => state.buttonAmountSelected$(false)
 | 
						|
        , change: ev => state.evolveDonation$({amount: R.always(format.dollarsToCents(ev.currentTarget.value))})
 | 
						|
        }
 | 
						|
      })
 | 
						|
    ])
 | 
						|
  , h('fieldset', [
 | 
						|
      h('button.button.u-width--full.btn-next', {
 | 
						|
        props: {type: 'submit', disabled: !state.donation$().amount || state.donation$().amount <= 0}
 | 
						|
      , on: {click: [state.currentStep$, 1]}
 | 
						|
      }, I18n.t('nonprofits.donate.amount.next'))
 | 
						|
    ])
 | 
						|
  ])
 | 
						|
}
 | 
						|
 | 
						|
// If the params have a single amount, show a large message saying how much it is
 | 
						|
function showSingleAmount(isRecurring, state) {
 | 
						|
  if(!state.params$().single_amount) return ''
 | 
						|
  var gift = state.params$().gift_option || {}
 | 
						|
  if(state.params$().gift_option_name) gift.name = state.params$().gift_option_name
 | 
						|
  var desig = state.params$().designation
 | 
						|
  return h('section.u-centered', [
 | 
						|
    h('p.singleAmount-message', [
 | 
						|
      h('strong', app.currency_symbol + format.centsToDollars(format.dollarsToCents(state.params$().single_amount)))
 | 
						|
    , h('span.u-padding--0', { class: {'u-hide': !isRecurring} }, ' monthly')
 | 
						|
    , h('span', {class: {'u-hide': !state.params$().designation && !gift.id}}, [ ' for ' + (desig || gift.name) ])
 | 
						|
    ])
 | 
						|
  , h('button.button.u-marginBottom--20', {on: {click: [state.currentStep$, 1]}}, I18n.t('nonprofits.donate.amount.next'))
 | 
						|
  ])
 | 
						|
}
 | 
						|
 | 
						|
module.exports = {view, init}
 | 
						|
 |