147 lines
4.6 KiB
JavaScript
147 lines
4.6 KiB
JavaScript
// License: LGPL-3.0-or-later
|
|
const R = require('ramda')
|
|
const h = require('snabbdom/h')
|
|
const flyd = require('flyd')
|
|
const url$ = require('flyd-url')
|
|
const render = require('ff-core/render')
|
|
const filter = require('flyd/module/filter')
|
|
const snabbdom = require('snabbdom')
|
|
const mergeAll = require('flyd/module/mergeall')
|
|
const sampleOn = require('flyd/module/sampleon')
|
|
const queryString = require('query-string')
|
|
const notification = require('ff-core/notification')
|
|
|
|
const request = require('../../../../common/request')
|
|
const confirm = require('../../../../components/confirmation-modal')
|
|
|
|
const actions = require('./supporter-actions')
|
|
const activities = require('./supporter-activities')
|
|
const offsiteDonationForm = require('./offsite-donation-form')
|
|
const supporterNoteForm = require('./supporter-note-form')
|
|
|
|
const flatMap = R.curry(require('flyd/module/flatmap'))
|
|
|
|
const init = _ => {
|
|
var state = {
|
|
clickComposing$: flyd.stream()
|
|
, threadId$: flyd.stream()
|
|
, newNote$: flyd.stream()
|
|
, editNote$: flyd.stream()
|
|
, deleteNote$: flyd.stream()
|
|
, newDonation$: flyd.stream()
|
|
}
|
|
|
|
const supporterID$ = R.compose(
|
|
filter(Boolean )
|
|
, flyd.map(url => queryString.parse(url.search).sid)
|
|
)(url$)
|
|
|
|
state.pathPrefix$ = flyd.map(constructPathPrefix, supporterID$)
|
|
|
|
const supporterPath$ = flyd.map(id => `/nonprofits/${app.nonprofit_id}/supporters/${id}`, supporterID$)
|
|
|
|
const supporterResp$ = R.compose(
|
|
flyd.map(x => x.body.data)
|
|
, filter(x => x.status === 200)
|
|
, flatMap(path => request({method: 'get', path}).load)
|
|
)(supporterPath$)
|
|
|
|
state.supporter$ = flyd.merge(supporterResp$, flyd.stream({}))
|
|
|
|
|
|
state.offsiteDonationForm = offsiteDonationForm.init(state)
|
|
|
|
state.editNoteData$ = flyd.merge(
|
|
flyd.map(R.always({}), state.newNote$)
|
|
, flyd.map(d => ({id: d.attachment_id, content: d.json_data.content}), state.editNote$))
|
|
|
|
const deleteNoteId$ = flyd.map(d => d.attachment_id, state.deleteNote$)
|
|
|
|
state.noteAjaxMethod$ = mergeAll([
|
|
flyd.map(R.always('post'), state.newNote$)
|
|
, flyd.map(R.always('put'), state.editNote$)
|
|
])
|
|
|
|
state.supporterNoteForm = supporterNoteForm.init(state)
|
|
|
|
state.confirmDelete = confirm.init(deleteNoteId$)
|
|
|
|
const deleteNoteResp$ = flatMap(ajaxDeleteNote(supporterPath$, deleteNoteId$), state.confirmDelete.confirm$)
|
|
|
|
// All streams that we want to trigger a refresh of the supporter timeline
|
|
const fetchActivitiesWith$ = mergeAll([
|
|
state.pathPrefix$
|
|
, state.offsiteDonationForm.saved$
|
|
, state.supporterNoteForm.saved$
|
|
, deleteNoteResp$
|
|
])
|
|
|
|
// Stream of activities data, using the pathPrefix$ stream, triggered by fetchActivitiesWith$
|
|
state.activities$ = R.compose(
|
|
R.curryN(2, flatMap)(getActivities)
|
|
, sampleOn(R.__, state.pathPrefix$)
|
|
)(fetchActivitiesWith$)
|
|
|
|
state.activities = activities.init(state)
|
|
|
|
state.modalID$ = mergeAll([
|
|
, flyd.map(()=> 'newSupporterNoteModal', state.editNoteData$)
|
|
, flyd.map(()=> null, state.supporterNoteForm.saved$)
|
|
])
|
|
|
|
|
|
const message$ = mergeAll([
|
|
, flyd.map(()=> 'Successfully created a new offsite contribution', state.offsiteDonationForm.saved$)
|
|
, flyd.map(()=> `Successfully ${noteMsg(state.noteAjaxMethod$)} supporter note`, state.supporterNoteForm.saved$)
|
|
, flyd.map(()=> 'Successfully deleted supporter note', deleteNoteResp$)
|
|
])
|
|
|
|
state.notification = notification.init({message$})
|
|
|
|
window.state = state
|
|
return state
|
|
}
|
|
|
|
const ajaxDeleteNote = (pathPrefix$, id$) => () => {
|
|
const path = `${pathPrefix$()}/supporter_notes/${id$()}`
|
|
return request({
|
|
method: 'delete'
|
|
, path
|
|
}).load
|
|
}
|
|
|
|
const noteMsg = method$ => {
|
|
if(method$() === 'put') return 'edited'
|
|
if(method$() === 'post') return 'created a new'
|
|
}
|
|
|
|
const getActivities = path =>
|
|
flyd.map(req => req.body, request({path: path + 'activities', method: 'get'}).load)
|
|
|
|
const constructPathPrefix = sid => `/nonprofits/${app.nonprofit_id}/supporters/${sid}/`
|
|
|
|
const view = state => {
|
|
return h('div', [
|
|
actions.view(state)
|
|
, activities.view(state)
|
|
, notification.view(state.notification)
|
|
, offsiteDonationForm.view(R.merge(state.offsiteDonationForm))
|
|
, supporterNoteForm.view(R.merge(state.supporterNoteForm, {modalID$: state.modalID$}))
|
|
, confirm.view(state.confirmDelete, 'Are you sure you want to delete this note?')
|
|
])
|
|
}
|
|
|
|
var container = document.querySelector('#js-sidePanel')
|
|
|
|
// -- Render to the page
|
|
// render takes state, view function, patch function, and DOM container
|
|
const patch = snabbdom.init([
|
|
require('snabbdom/modules/eventlisteners')
|
|
, require('snabbdom/modules/class')
|
|
, require('snabbdom/modules/props')
|
|
, require('snabbdom/modules/attributes')
|
|
, require('snabbdom/modules/style')
|
|
])
|
|
|
|
render({ patch, container , view, state: init() })
|
|
|