Skip to content

Commit

Permalink
Added ability to add new institutions (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
JackNeto committed Mar 5, 2019
1 parent d2d87cc commit 77b761c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 50 deletions.
23 changes: 20 additions & 3 deletions src/common/AutoComplete/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { withStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import Select from 'react-select'
import AsyncSelect from 'react-select/lib/Async'
import CreatableSelect from 'react-select/lib/Creatable'
import Typography from '@material-ui/core/Typography'
import FormHelperText from '@material-ui/core/FormHelperText'

Expand All @@ -25,6 +26,7 @@ const styles = theme => ({

const AutoComplete = ({
async,
creatable,
label,
name,
value,
Expand All @@ -44,7 +46,7 @@ const AutoComplete = ({
>
{label}
</Typography>
{ !async && (
{ !async && !creatable && (
<Select
placeholder={label}
name={name}
Expand All @@ -53,7 +55,20 @@ const AutoComplete = ({
options={options}
inputProps={{ 'aria-label': label, required: true }}
onChange={selection => onChange(name, selection)}
isClearable={true}
isClearable
className={className}
/>
)}
{ !async && creatable && (
<CreatableSelect
placeholder={label}
name={name}
value={value}
defaultValue={value}
options={options}
inputProps={{ 'aria-label': label, required: true }}
onChange={selection => onChange(name, selection)}
isClearable
className={className}
/>
)}
Expand All @@ -67,7 +82,7 @@ const AutoComplete = ({
loadOptions={loadOptions}
inputProps={{ 'aria-label': label }}
onChange={selection => onChange(name, selection)}
isClearable={true}
isClearable
className={className}
/>
)}
Expand All @@ -81,6 +96,7 @@ const AutoComplete = ({

AutoComplete.propTypes = {
async: PropTypes.bool,
creatable: PropTypes.bool,
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.object,
Expand All @@ -95,6 +111,7 @@ AutoComplete.propTypes = {

AutoComplete.defaultProps = {
async: false,
creatable: false,
value: null,
options: undefined,
loadOptions: undefined,
Expand Down
14 changes: 2 additions & 12 deletions src/core/Accounts/ImportTransactions/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import ListItem from '@material-ui/core/ListItem'
import ListItemText from '@material-ui/core/ListItemText'
import InstitutionIcon from '../../../common/InstitutionIcon'
import { addTransactions } from '../../../store/transactions/actions'
import institutions from '../../../data/institutions'
import CsvImportForm from './CsvImportForm'
import ImportedResults from './ImportedResults'

Expand Down Expand Up @@ -109,20 +108,11 @@ export class ImportTransactionsComponent extends React.Component {
<Grid container>
<Grid item xs={3}>
<List>
{institutions[account.institution].importTypes.map(text => (
<ListItem button key={text} selected={true}>
{['CSV', 'Microsoft Money', 'Intuit Quicken', 'Intuit QuickBooks'].map((text, index) => (
<ListItem button key={text} selected={index === 0}>
<ListItemText primary={text} />
</ListItem>
))}
<ListItem button key="Microsoft Money" disabled={true}>
<ListItemText primary="Microsoft Money" />
</ListItem>
<ListItem button key="Intuit Quicken" disabled={true}>
<ListItemText primary="Intuit Quicken" />
</ListItem>
<ListItem button key="Intuit QuickBooks" disabled={true}>
<ListItemText primary="Intuit QuickBooks" />
</ListItem>
</List>
</Grid>
<Grid item xs={9}>
Expand Down
6 changes: 6 additions & 0 deletions src/core/Accounts/__tests__/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ exports[`Accounts index (Left Nav) snapshot matches snapshot with a few account
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="TD"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down Expand Up @@ -277,6 +278,7 @@ exports[`Accounts index (Left Nav) snapshot matches snapshot with a few account
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="BMO"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down Expand Up @@ -394,6 +396,7 @@ exports[`Accounts index (Left Nav) snapshot matches snapshot with a few account
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="Coinbase"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down Expand Up @@ -573,6 +576,7 @@ exports[`Accounts index (Left Nav) snapshot matches with a few accounts but none
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="TD"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down Expand Up @@ -773,6 +777,7 @@ exports[`Accounts index (Left Nav) snapshot matches with a few accounts but none
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="BMO"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down Expand Up @@ -890,6 +895,7 @@ exports[`Accounts index (Left Nav) snapshot matches with a few accounts but none
</div>
<div
className="MuiListItemText-root-94 MuiListItemText-dense-96"
title="Coinbase"
>
<span
className="MuiTypography-root-38 MuiTypography-subheading-45 MuiListItemText-primary-97 MuiListItemText-textDense-99"
Expand Down
11 changes: 7 additions & 4 deletions src/core/Accounts/__tests__/form.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('Account form', () => {
handleDelete={mochHandleDelete}
handleCancel={mochHandleCancel}
classes={{ }}
accountInstitutions={[]}
/>
))
expect(component.toJSON()).toMatchSnapshot()
Expand All @@ -49,6 +50,7 @@ describe('Account form', () => {
handleDelete={mochHandleDelete}
handleCancel={mochHandleCancel}
classes={{ }}
accountInstitutions={['My institution']}
/>
))
expect(component.toJSON()).toMatchSnapshot()
Expand All @@ -69,6 +71,7 @@ describe('Account form', () => {
handleDelete={mochHandleDelete}
handleCancel={mochHandleCancel}
classes={{ }}
accountInstitutions={['My institution']}
/>
))
const instance = wrapper.instance()
Expand Down Expand Up @@ -99,8 +102,8 @@ describe('Account form', () => {

expect(instance.institutionOptions()).toBeNull()

expect(institutions.BMO.importTypes).not.toContain('API')
expect(instance.institutionOptions({ value: 'BMO' })).toBeNull()
expect(institutions['Bank of Montreal'].importTypes).not.toContain('API')
expect(instance.institutionOptions({ value: 'Bank of Montreal' })).toBeNull()

expect(institutions.Coinbase.importTypes).toContain('API')
expect(instance.institutionOptions({ value: 'Coinbase' })).not.toBeNull()
Expand All @@ -112,8 +115,8 @@ describe('Account form', () => {

expect(instance.institutionOptions()).toBeNull()

expect(institutions.BMO.importTypes).not.toContain('API')
expect(instance.institutionOptions({ value: 'BMO' })).toBeNull()
expect(institutions['Bank of Montreal'].importTypes).not.toContain('API')
expect(instance.institutionOptions({ value: 'Bank of Montreal' })).toBeNull()

expect(institutions.Coinbase.importTypes).toContain('API')
expect(instance.institutionOptions({ value: 'Coinbase' })).toBeNull()
Expand Down
15 changes: 12 additions & 3 deletions src/core/Accounts/form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import format from 'date-fns/format'
import parse from 'date-fns/parse'
import currencies, { filteredCurrencies } from '../../data/currencies'
import AutoComplete from '../../common/AutoComplete'
import institutions, { formatedInstitutions } from '../../data/institutions'
import institutions from '../../data/institutions'
import SubmitButtonWithProgress from '../../common/SubmitButtonWithProgress'
import DescriptionCard from '../../common/DescriptionCard'

Expand Down Expand Up @@ -67,6 +67,7 @@ const styles = theme => ({

const mapStateToProps = (state, ownProps) => ({
settings: state.settings,
accountInstitutions: Object.keys(state.accounts.byInstitution),
account: state.accounts.byId[ownProps.accountId]
})

Expand All @@ -80,7 +81,7 @@ export class AccountFormComponent extends React.Component {
const { hideInstitutionOptions } = this.state
const { value } = (institution || {})

if (value === undefined || hideInstitutionOptions) return null
if (!Object.keys(institutions).includes(value) || hideInstitutionOptions) return null

if (institutions[value].importTypes.includes('API')) {
return (
Expand Down Expand Up @@ -132,6 +133,12 @@ export class AccountFormComponent extends React.Component {
this.setState({ hideInstitutionOptions: true })
}


formatedInstitutions = () => {
const allInstitutions = new Set(this.props.accountInstitutions.concat(Object.keys(institutions)))
return Array.from(allInstitutions).sort().map(key => ({ value: key, label: key }))
}

render() {
const {
classes,
Expand Down Expand Up @@ -161,11 +168,12 @@ export class AccountFormComponent extends React.Component {
<Divider />
<form onSubmit={handleSubmit} className={classes.form}>
<AutoComplete
creatable
className={classes.input}
label="Institution"
name="institution"
value={values.institution}
options={formatedInstitutions}
options={this.formatedInstitutions()}
onChange={this.handleInstitutionChange}
error={errors.institution && touched.institution}
helperText={errors.institution}
Expand Down Expand Up @@ -259,6 +267,7 @@ AccountFormComponent.propTypes = {
setFieldValue: PropTypes.func.isRequired,
handleDelete: PropTypes.func,
handleCancel: PropTypes.func.isRequired,
accountInstitutions: PropTypes.array.isRequired,
account: PropTypes.object
}

Expand Down
26 changes: 21 additions & 5 deletions src/core/Accounts/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,22 @@ const styles = theme => ({
margin: '0 20px 20px 25px',
padding: theme.spacing.unit
},
institutionListItem: {
institutionListItemRoot: {
padding: '4px 24px'
},
institutionListItem: {
paddingRight: 0
},
institutionListItemIcon: {
margin: 0
},
institution: {
paddingLeft: 0
padding: 0,
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
maxWidth: 100,
fontWeight: 500
},
account: {
padding: '4px 24px 4px 40px'
Expand Down Expand Up @@ -104,11 +115,16 @@ export const AccountsComponent = ({
{Object.keys(accounts.byInstitution).map(institution => (
Object.values(accounts.byInstitution[institution].groups).map(accountGroup => (
<div key={`${institution}-${accountGroup.id}`}>
<ListItem className={classes.institutionListItem}>
<ListItemIcon>
<ListItem className={classes.institutionListItemRoot}>
<ListItemIcon className={classes.institutionListItemIcon}>
<InstitutionIcon institution={institution} size="small" />
</ListItemIcon>
<ListItemText primary={institution} className={classes.institution} />
<ListItemText
primary={institution}
className={classes.institutionListItem}
classes={{ primary: classes.institution }}
title={institution}
/>
{accountGroup.type === 'api' && (
<ListItemSecondaryAction>
<Tooltip id="tooltip-icon" title="Edit API details">
Expand Down
32 changes: 9 additions & 23 deletions src/data/institutions.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,41 @@
const institutions = {
TD: {
name: 'TD EasyWeb',
'TD EasyWeb': {
importTypes: ['CSV'],
url: 'https://www.td.com',
favicon: 'https://www.td.com/ca/en/personal-banking/system/v1.5/assets/img/favicon.ico'
},
BMO: {
name: 'Bank of Montreal',
'Bank of Montreal': {
importTypes: ['CSV'],
url: 'https://www12.bmo.com',
favicon: 'https://www12.bmo.com/onlinebanking/onlinebanking/en/images/favicon.ico'
},
PCFinancial: {
name: 'PC Financial',
'PC Financial': {
importTypes: ['CSV'],
url: 'https://www.pcfinancial.ca',
favicon: 'https://www.pcfinancial.ca/assets/media/img/favicon.ico'
},
Tangerine: {
name: 'Tangerine',
importTypes: ['CSV'],
url: 'https://www.tangerine.ca',
favicon: 'https://www.tangerine.ca/favicon.ico '
},
RBC: {
name: 'Royal Bank',
'Royal Bank': {
importTypes: ['CSV'],
url: 'https://www.rbcroyalbank.com',
favicon: 'https://www.rbcroyalbank.com/uos/_assets/images/icons/favicon.ico'
},
Coinbase: {
name: 'Coinbase',
importTypes: ['API'],
url: 'https://www.coinbase.com',
favicon: 'https://www.coinbase.com/favicon.ico'
},
Questrade: {
importTypes: ['CSV'],
url: 'https://www.questrade.com',
favicon: 'https://www.questrade.com/Resources/images/favicon.ico'
}
}

// Questrade: {
// name: 'Questrade',
// importTypes: ['API'],
// url: 'https://www.questrade.com',
// favicon: 'https://www.questrade.com/Resources/images/favicon.ico'
// }

export const formatedInstitutions = Object.keys(institutions)
.map(key => ({
value: key,
label: institutions[key].name
}))

// Sorted institutions
export default Object.keys(institutions)
.sort((a, b) => (a > b))
Expand Down

0 comments on commit 77b761c

Please sign in to comment.