112 lines
3.4 KiB
Text
112 lines
3.4 KiB
Text
|
// License: LGPL-3.0-or-later
|
||
|
const request = require("../common/super-agent-frp")
|
||
|
const view = require("vvvview")
|
||
|
const flyd = require('flyd')
|
||
|
const flatMap = require('flyd/module/flatmap')
|
||
|
const scanMerge = require('flyd/module/scanmerge')
|
||
|
const h = require('virtual-dom/h')
|
||
|
const Im = require('immutable')
|
||
|
const Map = Im.Map
|
||
|
const fromJS = Im.fromJS
|
||
|
const OrderedMap = Im.OrderedMap
|
||
|
const format = require('../common/format')
|
||
|
|
||
|
var state = fromJS({is_visible: false, data: {}, coords: {top: 0, right: 0, left: 0}})
|
||
|
|
||
|
var $showClicks = flyd.stream()
|
||
|
var $hideClicks = flyd.stream()
|
||
|
|
||
|
const root = state => {
|
||
|
if(state.get('is_visible') && state.get('data')) {
|
||
|
return h('aside.infoCard', {
|
||
|
style: {
|
||
|
display: state.get('is_visible') ? 'block' : 'none',
|
||
|
top: state.getIn(['coords', 'top']) - state.get('rows') * 23 + 'px',
|
||
|
left: state.getIn(['coords', 'left']) + 'px',
|
||
|
right: state.getIn(['coords', 'right']) + 'px'
|
||
|
}
|
||
|
}, [
|
||
|
h('i.fa.fa-times', {onclick: $hideClicks}),
|
||
|
supporterTable(state.get('data')),
|
||
|
h('a.button--micro', {href: state.getIn(['data', 'link'])}, 'View Full Details')
|
||
|
])
|
||
|
} else return h('span')
|
||
|
}
|
||
|
|
||
|
const supporterDetail = pair => {
|
||
|
var [key, val] = pair
|
||
|
if(key === 'link') return ''
|
||
|
return val ? h('tr', [h('td', format.snake_to_words(key)), h('td', val)]) : ''
|
||
|
}
|
||
|
|
||
|
const supporterTable = supporter =>
|
||
|
h('table', supporter.entrySeq().map(supporterDetail).toJS())
|
||
|
|
||
|
const displayCard = (state, node) => {
|
||
|
var clientTop = document.documentElement.clientTop
|
||
|
var clientLeft = document.documentElement.clientLeft
|
||
|
var box = node.getBoundingClientRect()
|
||
|
var top = box.top + window.pageYOffset - clientTop
|
||
|
var left = box.left + window.pageXOffset - clientLeft
|
||
|
|
||
|
// Place card 15px from right when it's too far over.
|
||
|
if(left + 350 >= document.body.offsetWidth) {
|
||
|
state = state.setIn(['coords', 'right'], 15)
|
||
|
state = state.setIn(['coords', 'left'], 'initial')
|
||
|
} else {
|
||
|
state = state.setIn(['coords', 'left'], left)
|
||
|
state = state.setIn(['coords', 'right'], 'initial')
|
||
|
}
|
||
|
|
||
|
return state
|
||
|
.setIn(['coords', 'top'], top)
|
||
|
.set('is_visible', true)
|
||
|
.set('data', false)
|
||
|
}
|
||
|
|
||
|
// Count the number of rows of data the supporter has
|
||
|
const calculateRows = state =>
|
||
|
state.set('rows', state.get('data').entrySeq().filter(pair => {
|
||
|
var [key, val] = pair
|
||
|
return val && String(val).length
|
||
|
}).count() + 1.5)
|
||
|
|
||
|
const ajaxSupporter = node => {
|
||
|
var id = node.getAttribute('data-id')
|
||
|
return request.get(`/nonprofits/${app.nonprofit_id}/supporters/${id}/info_card`).perform()
|
||
|
}
|
||
|
|
||
|
var $responses = flatMap(ajaxSupporter, $showClicks)
|
||
|
|
||
|
const setSupporterData = (state, response) => {
|
||
|
var d = response.body
|
||
|
if(!d) return state
|
||
|
state = state.set('data', OrderedMap({
|
||
|
name: d.name
|
||
|
, email: d.email
|
||
|
, phone: utils.pretty_phone(d.phone)
|
||
|
, address: utils.address_with_commas(d.address, d.city, d.state_code, d.zip_code,d.country)
|
||
|
, organization: d.organization
|
||
|
, total_raised: '$' + utils.cents_to_dollars(d.raised)
|
||
|
, link: `/nonprofits/${app.nonprofit_id}/supporters?sid=${d.id}/`
|
||
|
}))
|
||
|
// Count the rows of present data to calculate the card height
|
||
|
state = calculateRows(state)
|
||
|
return state
|
||
|
}
|
||
|
|
||
|
var $state = flyd.immediate(scanMerge([
|
||
|
[$hideClicks, state => state.set('is_visible', false)],
|
||
|
[$showClicks, displayCard],
|
||
|
[$responses, setSupporterData],
|
||
|
], state))
|
||
|
|
||
|
var infoCard = view(root, document.body, state)
|
||
|
|
||
|
flyd.map(infoCard, $state)
|
||
|
|
||
|
|
||
|
// XXX viewscript lol
|
||
|
appl.def('show_supporter_info_card', function(node){ $showClicks(appl.prev_elem(node)) })
|
||
|
|