Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
refer client workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
John O'Malley committed Oct 23, 2016
1 parent 11ff2bd commit f8d36d2
Show file tree
Hide file tree
Showing 19 changed files with 301 additions and 42 deletions.
3 changes: 3 additions & 0 deletions services/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ router.use('/clients', require('./clients'))

router.use('/shelters', require('./shelters'))

router.get('/program-types', require('./programs/programTypes'))
router.use('/programs', require('./programs'))

router.use('/notifications', require('./sms'))

// make sure /services sends a 404
Expand Down
2 changes: 1 addition & 1 deletion services/clients/updateTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ module.exports = ({ params: { id }, body }, res, next) => {
doc.tags = _(doc.tags || []).chain().union(add || []).without(remove || []).value()
putDoc(db, doc)
.then(({ body }) => res.json(body))
.catch(next)
} else {
res.status(404).send(`client ${id} not found`)
}
})
.catch(next)
}
40 changes: 38 additions & 2 deletions services/docs.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
[
{
"name": "alice"
"_id": "city-seeds",
"name": "City Seeds",
"type": "training",
"location": "St. Patrick's Center"
},
{
"name": "bob"
"_id": "mcmurphys",
"name": "McMurphy’s Cafe",
"type": "training",
"location": "St. Patrick's Center"
},
{
"_id": "homeless-employment",
"name": "Homeless Employment",
"type": "training",
"location": "St. Patrick's Center"
},
{
"_id": "labre-center",
"name": "Labre Center",
"type": "training",
"location": "Peter and Paul"
},
{
"_id": "community-collaborative",
"name": "Community CollabARTive",
"type": "training",
"location": "Peter and Paul"
},
{
"_id": "skills-4-success",
"name": "Skills 4 Success",
"type": "training",
"location": "Gateway 180"
},
{
"_id": "twice-blessed",
"name": "Twice Blessed",
"type": "training",
"location": "Our Lady's Inn"
}
]
10 changes: 7 additions & 3 deletions services/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ const express = require('express')
const router = express.Router()

router.post('/', (req, res, next) => {
agent.post(`${couchUrl}/foobar/_bulk_docs`)
.send({ docs: require('./docs.json') })
.then(({ body }) => res.json(body))
const docs = require('./docs.json')
Promise.all(docs.map(d =>
agent.put(`${couchUrl}/programs/${d._id}`)
.send(d)
.then(({ body }) => body)
))
.then(results => res.json(results))
.catch(next)
})

Expand Down
14 changes: 14 additions & 0 deletions services/programs/findPrograms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const agent = require('../../src/agent')
const { couchUrl } = require('../config')
const mango = require('../mango')

const db = 'programs'

const findByType = (type) =>
mango(db, { selector: { type } })

const findAll = () =>
agent.get(`${couchUrl}/${db}/_all_docs?include_docs=true`)
.then(({ body: { rows } }) => rows.filter(row => row.id[0] !== '_').map(({ doc }) => doc))

module.exports = (type) => type ? findByType(type) : findAll()
6 changes: 6 additions & 0 deletions services/programs/getPrograms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const findPrograms = require('./findPrograms')

module.exports = ({ query: { type } }, res, next) =>
findPrograms(type)
.then(programs => res.json(programs))
.catch(next)
6 changes: 6 additions & 0 deletions services/programs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const express = require('express')
const router = express.Router()

router.get('/', require('./getPrograms'))

module.exports = router
9 changes: 9 additions & 0 deletions services/programs/programTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const _ = require('underscore')
const findPrograms = require('./findPrograms')

module.exports = (req, res, next) =>
findPrograms()
.then(
programs => res.json(_(programs).chain().map(p => [p.type, true]).object().keys().compact().value())
)
.catch(next)
20 changes: 20 additions & 0 deletions src/Toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar'
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'

const Toolbar = ({ children }) => {
let key = 0
return (
<ButtonToolbar>
{[].concat(children).map(child => (
<ButtonGroup key={key++}>
{child}
</ButtonGroup>
))}
</ButtonToolbar>
)
}

Toolbar.displayName = 'Toolbar'

export default Toolbar
4 changes: 1 addition & 3 deletions src/admin/Admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ const onShelterSelected = (shelterId) =>

const Admin = ({ params: { shelterId, clientId }, children }) => (
<div className='admin'>
{clientId ? null : (
<Shelters value={shelterId} onSelection={onShelterSelected}/>
)}
{clientId ? null : (<Shelters value={shelterId} onSelection={onShelterSelected}/>)}
{children}
</div>
)
Expand Down
27 changes: 7 additions & 20 deletions src/admin/CheckInClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import React from 'react'
import agent from '../agent'
import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar'
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup'
import Button from 'react-bootstrap/lib/Button'
import Alert from 'react-bootstrap/lib/Alert'
import FadeIn from '../FadeIn'
import Toolbar from '../Toolbar'
import { Link } from 'react-router'
import _ from 'underscore'

Expand All @@ -29,19 +29,6 @@ const categories = {
}
}

const Buttons = ({ children }) => {
let key = 0
return (
<ButtonToolbar>
{[].concat(children).map(child => (
<ButtonGroup key={key++}>
{child}
</ButtonGroup>
))}
</ButtonToolbar>
)
}

export default class CheckInClient extends React.Component {
constructor(props, context) {
super(props, context)
Expand Down Expand Up @@ -90,9 +77,9 @@ export default class CheckInClient extends React.Component {
{total > 1 ? ` and ${total - 1} other(s) have ` : ' has '}
{`successfully checked into ${shelter.name}.`}
</Alert>
<Buttons>
<Toolbar>
{cancelButton('Done', 'primary')}
</Buttons>
</Toolbar>
</FadeIn>
) : (
<FadeIn className='check-in'>
Expand All @@ -101,10 +88,10 @@ export default class CheckInClient extends React.Component {
{' '}
{result.error || 'unknown error'}
</Alert>
<Buttons>
<Toolbar>
<Button bsStyle='primary' onClick={() => this.setState({ result: undefined })}>Try Again</Button>
{cancelButton()}
</Buttons>
</Toolbar>
</FadeIn>
)

Expand Down Expand Up @@ -172,10 +159,10 @@ export default class CheckInClient extends React.Component {
{busy ? (
<div className='spinner'/>
) : (
<Buttons>
<Toolbar>
<Button bsStyle='primary' onClick={onCheckIn} disabled={total === 0}>Check In</Button>
{cancelButton()}
</Buttons>
</Toolbar>
)
}
</FadeIn>
Expand Down
107 changes: 107 additions & 0 deletions src/admin/ReferClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react'
import agent from '../agent'
import { Link } from 'react-router'
import Button from 'react-bootstrap/lib/Button'
import Alert from 'react-bootstrap/lib/Alert'
import ReferralTable from './ReferralTable'
import Toolbar from '../Toolbar'
import FadeIn from '../FadeIn'

export default class ReferClient extends React.Component {
update(params = this.props.params) {
Promise.all([
agent.get(`/services/clients/${encodeURIComponent(params.clientId)}`).then(({ body }) => body),
agent.get('/services/programs').then(({ body }) => body)
])
.then(([client, programs]) => this.setState({ client, programs }))
}

componentWillReceiveProps({ params }) {
this.update(params)
}

componentWillMount() {
this.update()
}

render() {
const { client, programs, selectedId, result } = this.state || {}
const { clientId, shelterId } = this.props.params
const clientName = client && `${client.first_name} ${client.last_name} `

const setResult = (result) => this.setState({ result })

const onSend = () =>
agent.patch(`/services/clients/${encodeURIComponent(clientId)}/tags`)
.send({
add: [selectedId]
})
.then(({ body }) => setResult(body))
.catch(e => setResult({ error: e.message || e.toString() }))

const cancelButton = (label = 'Cancel', bsStyle = 'default') => (
<Link to={`/admin/${encodeURIComponent(shelterId)}`} className={`btn btn-${bsStyle}`}>
{label}
</Link>
)

const renderResult = () =>
result.ok ? (
<FadeIn className='check-in'>
<Alert bsStyle="success">
<strong>Success</strong>
{' Referral was sent successfully for client '}
{clientName}
{'.'}
</Alert>
<Toolbar>
{cancelButton('Done', 'primary')}
</Toolbar>
</FadeIn>
) : (
<FadeIn className='check-in'>
<Alert bsStyle="danger">
<strong>Referral Failed</strong>
{' '}
{result.error || 'unknown error'}
</Alert>
<Toolbar>
<Button bsStyle='primary' onClick={() => this.setState({ result: undefined })}>Try Again</Button>
{cancelButton()}
</Toolbar>
</FadeIn>
)

if (result) {
return renderResult()
} else if (client && programs) {
return (
<div className='refer-client'>
<h2>
{`${client.first_name} ${client.last_name} `}
<small>
refer client
</small>
</h2>
<hr/>
<h4>Select a program below</h4>
<Toolbar>
<Button bsStyle='primary' disabled={!selectedId} onClick={onSend}>
Send Referral
</Button>
<Link to={`/admin/${shelterId}`} className='btn btn-default'>
Cancel
</Link>
</Toolbar>
<hr/>
<ReferralTable programs={programs} selectedId={selectedId}
onSelected={selectedId => this.setState({ selectedId })}/>
</div>
)
} else {
return (
<div className='spinner'/>
)
}
}
}
16 changes: 16 additions & 0 deletions src/admin/ReferralHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'

const RefferalHeader = () => (
<thead>
<tr>
<th>Select</th>
<th>Program Name</th>
<th>Program Location</th>
<th>Program Type</th>
</tr>
</thead>
)

RefferalHeader.displayName = 'RefferalHeader'

export default RefferalHeader
18 changes: 18 additions & 0 deletions src/admin/ReferralRow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'
import Radio from 'react-bootstrap/lib/Radio'
import programTypes from './programTypes'

const ReferralRow = ({ selected, program: { _id, name, type, location }, onSelected }) => (
<tr className={selected ? 'selected' : ''}>
<td>
<Radio checked={selected} onChange={() => onSelected(_id)}/>
</td>
<td>{name}</td>
<td>{location}</td>
<td>{programTypes[type] || type}</td>
</tr>
)

ReferralRow.displayName = 'ReferralRow'

export default ReferralRow
19 changes: 19 additions & 0 deletions src/admin/ReferralTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import Table from 'react-bootstrap/lib/Table'
import RefferalHeader from './ReferralHeader'
import ReferralRow from './ReferralRow'

const ReferralTable = ({programs, selectedId, onSelected}) => (
<Table striped bordered>
<RefferalHeader/>
<tbody>
{programs.map(program => (
<ReferralRow key={program._id} program={program} selected={program._id === selectedId}
onSelected={onSelected}/>
))
}
</tbody>
</Table>
)

export default ReferralTable
Loading

0 comments on commit f8d36d2

Please sign in to comment.