|
| 1 | +import React, { Component } from 'react' |
| 2 | +import { connect } from 'react-redux' |
| 3 | + |
| 4 | +import * as callTakerActions from '../../actions/call-taker' |
| 5 | +import DraggableWindow from './draggable-window' |
| 6 | +import Icon from '../narrative/icon' |
| 7 | +import {WindowHeader} from './styled' |
| 8 | +import {createLetter, MAILABLE_FIELDS} from '../../util/mailables' |
| 9 | + |
| 10 | +/** |
| 11 | + * A window enabled through the Call Taker module that allows Call Taker users |
| 12 | + * to generate a PDF with an invoice of items to be mailed to transit customers. |
| 13 | + */ |
| 14 | +class MailablesWindow extends Component { |
| 15 | + constructor (props) { |
| 16 | + super(props) |
| 17 | + this.state = { |
| 18 | + mailables: [] |
| 19 | + } |
| 20 | + } |
| 21 | + |
| 22 | + _addMailable = (mailable) => { |
| 23 | + const mailables = [...this.state.mailables] |
| 24 | + if (!mailables.find(m => m.name === mailable.name)) { |
| 25 | + mailables.push({...mailable, quantity: 1}) |
| 26 | + } else { |
| 27 | + // FIXME: Increase quanity? |
| 28 | + } |
| 29 | + this.setState({mailables}) |
| 30 | + } |
| 31 | + |
| 32 | + _removeMailable = (mailable) => { |
| 33 | + const mailables = [...this.state.mailables] |
| 34 | + const removeIndex = mailables.findIndex(m => m.name === mailable.name) |
| 35 | + mailables.splice(removeIndex, 1) |
| 36 | + this.setState({mailables}) |
| 37 | + } |
| 38 | + |
| 39 | + _updateMailableField = (index, fieldName, value) => { |
| 40 | + const mailables = [...this.state.mailables] |
| 41 | + mailables[index] = {...mailables[index], [fieldName]: value} |
| 42 | + this.setState({mailables}) |
| 43 | + } |
| 44 | + |
| 45 | + _onClickCreateLetter = () => createLetter(this.state, this.props.callConfig.options) |
| 46 | + |
| 47 | + _updateField = (evt) => { |
| 48 | + this.setState({[evt.target.id]: evt.target.value}) |
| 49 | + } |
| 50 | + |
| 51 | + render () { |
| 52 | + const {callConfig, callTaker, toggleMailables} = this.props |
| 53 | + const {mailables: selectedMailables} = this.state |
| 54 | + const {mailables} = callConfig.options |
| 55 | + if (!callTaker.mailables.visible) return null |
| 56 | + const selectableMailables = mailables.filter(m => !selectedMailables.find(mailable => mailable.name === m.name)) |
| 57 | + return ( |
| 58 | + <DraggableWindow |
| 59 | + header={ |
| 60 | + <> |
| 61 | + <WindowHeader> |
| 62 | + <Icon type='graduation-cap' /> Mailables{' '} |
| 63 | + <span className='pull-right'> |
| 64 | + <button |
| 65 | + className='clear-button-formatting' |
| 66 | + onClick={this._onClickCreateLetter} |
| 67 | + style={{marginRight: '5px', verticalAlign: 'bottom'}} |
| 68 | + > |
| 69 | + Create Letter |
| 70 | + </button> |
| 71 | + </span> |
| 72 | + </WindowHeader> |
| 73 | + </> |
| 74 | + } |
| 75 | + onClickClose={toggleMailables} |
| 76 | + scroll={false} |
| 77 | + style={{width: '600px'}} |
| 78 | + > |
| 79 | + <div> |
| 80 | + {MAILABLE_FIELDS.map(f => ( |
| 81 | + <input |
| 82 | + key={f.fieldName} |
| 83 | + id={f.fieldName} |
| 84 | + onChange={this._updateField} |
| 85 | + placeholder={f.fieldName} |
| 86 | + value={this.state[f.fieldName]} /> |
| 87 | + ))} |
| 88 | + </div> |
| 89 | + <div style={{display: 'flex'}}> |
| 90 | + <div style={{width: '300px'}}> |
| 91 | + <h4>All Mailables</h4> |
| 92 | + <div style={{maxHeight: '120px', overflowY: 'scroll'}}> |
| 93 | + {selectableMailables.map((mailable, i) => ( |
| 94 | + <MailableOption |
| 95 | + key={mailable.name} |
| 96 | + mailable={mailable} |
| 97 | + onClick={this._addMailable} /> |
| 98 | + ))} |
| 99 | + </div> |
| 100 | + </div> |
| 101 | + <div style={{width: '300px'}}> |
| 102 | + <h4>Selected Mailables</h4> |
| 103 | + <div style={{maxHeight: '120px', overflowY: 'scroll'}}> |
| 104 | + {selectedMailables.length > 0 |
| 105 | + ? selectedMailables.map((mailable, i) => ( |
| 106 | + <MailableOption |
| 107 | + index={i} |
| 108 | + key={mailable.name} |
| 109 | + mailable={mailable} |
| 110 | + onClear={this._removeMailable} |
| 111 | + updateField={this._updateMailableField} /> |
| 112 | + )) |
| 113 | + : <div className='text-muted'>No mailables selected.</div> |
| 114 | + } |
| 115 | + </div> |
| 116 | + </div> |
| 117 | + </div> |
| 118 | + </DraggableWindow> |
| 119 | + ) |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +class MailableOption extends Component { |
| 124 | + _changeLargeFormat = (evt) => { |
| 125 | + const {index, updateField} = this.props |
| 126 | + updateField(index, 'largeFormat', evt.target.checked) |
| 127 | + } |
| 128 | + |
| 129 | + _changeQuantity = (evt) => { |
| 130 | + const {index, updateField} = this.props |
| 131 | + updateField(index, 'quantity', evt.target.value) |
| 132 | + } |
| 133 | + |
| 134 | + _onClear = () => this.props.onClear && this.props.onClear(this.props.mailable) |
| 135 | + |
| 136 | + _onClick = () => this.props.onClick && this.props.onClick(this.props.mailable) |
| 137 | + |
| 138 | + render () { |
| 139 | + const {mailable, onClear} = this.props |
| 140 | + const isSelected = Boolean(onClear) |
| 141 | + if (isSelected) { |
| 142 | + return ( |
| 143 | + <div> |
| 144 | + {mailable.name} |
| 145 | + <button className='pull-right clear-button-formatting' onClick={onClear}> |
| 146 | + x |
| 147 | + </button> |
| 148 | + <div> |
| 149 | + <input |
| 150 | + min={0} |
| 151 | + onChange={this._changeQuantity} |
| 152 | + step={1} |
| 153 | + style={{marginRight: '5px', width: '50px'}} |
| 154 | + type='number' |
| 155 | + value={mailable.quantity} /> |
| 156 | + {mailable.largePrint && |
| 157 | + <> |
| 158 | + <input |
| 159 | + id='largeFormat' |
| 160 | + onChange={this._changeLargeFormat} |
| 161 | + type='checkbox' |
| 162 | + value={mailable.largeFormat} /> |
| 163 | + <label style={{marginLeft: '5px'}} htmlFor='largeFormat'> |
| 164 | + Large format? |
| 165 | + </label> |
| 166 | + </> |
| 167 | + } |
| 168 | + </div> |
| 169 | + </div> |
| 170 | + ) |
| 171 | + } |
| 172 | + return ( |
| 173 | + <button className='clear-button-formatting' onClick={this._onClick}> |
| 174 | + {mailable.name} |
| 175 | + </button> |
| 176 | + ) |
| 177 | + } |
| 178 | +} |
| 179 | + |
| 180 | +const mapStateToProps = (state, ownProps) => { |
| 181 | + const callConfig = state.otp.config.modules.find(m => m.id === 'call') |
| 182 | + return { |
| 183 | + callConfig, |
| 184 | + callTaker: state.callTaker |
| 185 | + } |
| 186 | +} |
| 187 | + |
| 188 | +const mapDispatchToProps = { |
| 189 | + toggleMailables: callTakerActions.toggleMailables |
| 190 | +} |
| 191 | + |
| 192 | +export default connect(mapStateToProps, mapDispatchToProps)(MailablesWindow) |
0 commit comments