From 62942d4f8a31005dd186cd9632ee7a9d7c94bc59 Mon Sep 17 00:00:00 2001 From: Tobias Pickel Date: Wed, 9 Jan 2019 15:00:09 +0100 Subject: [PATCH] feat(user-multi-selection): add component --- .../split-invoice/split-invoice.tsx | 114 +++++++----------- src/components/user/user-multi-selection.tsx | 48 ++++++++ 2 files changed, 91 insertions(+), 71 deletions(-) create mode 100644 src/components/user/user-multi-selection.tsx diff --git a/src/components/transaction/split-invoice/split-invoice.tsx b/src/components/transaction/split-invoice/split-invoice.tsx index 0e794ceb..76a7c825 100644 --- a/src/components/transaction/split-invoice/split-invoice.tsx +++ b/src/components/transaction/split-invoice/split-invoice.tsx @@ -1,8 +1,5 @@ import { - AlertText, Block, - CancelButton, - Card, Input, PrimaryButton, ResponsiveGrid, @@ -16,13 +13,14 @@ import { CreateTransactionParams, Transaction, User, + UsersState, startCreatingTransaction, } from '../../../store/reducers'; import { ConnectedIdleTimer } from '../../common/idle-timer'; import { Currency, CurrencyInput } from '../../currency'; import { ConnectedUserSelectionList } from '../../user'; -import { ConnectedTransactionListItem } from '../transaction-list-item'; -import { ConnectedTransactionValidator } from '../validator'; +import { ConnectedUserMultiSelection } from '../../user/user-multi-selection'; +import { isTransactionValid } from '../validator'; interface State { recipient: User | undefined; @@ -30,6 +28,7 @@ interface State { comment: string; amount: number; responseState: { [userId: number]: Transaction | 'error' }; + validation: { [userId: number]: string }; } interface Props {} @@ -40,6 +39,7 @@ const initialState: State = { comment: '', amount: 0, responseState: {}, + validation: {}, }; const GridContainer = styled('div')({ @@ -96,16 +96,18 @@ export class SplitInvoiceForm extends React.Component { public setAmount = (amount: number) => { this.setState({ amount }); + this.updateValidation(); }; public setComment = (e: React.ChangeEvent) => { this.setState({ comment: e.target.value }); }; - public addParticipant = (user: User) => { - this.setState(state => ({ - participants: [...(state.participants || []), user], - })); + public addParticipant = (user: UsersState) => { + this.setState({ + participants: Object.values(user), + }); + this.updateValidation(); }; public removeParticipant = (userToRemove: User) => { @@ -138,7 +140,8 @@ export class SplitInvoiceForm extends React.Component { return ( this.state.recipient && this.state.participants.length && - this.state.amount > 0 + this.state.amount > 0 && + this.formIsValid() ); }; @@ -156,6 +159,33 @@ export class SplitInvoiceForm extends React.Component { return transactionState === 'error'; }; + public updateValidation = () => { + const value = this.getSplitAmount(); + const boundary = store.getState().settings.payment.boundary; + const initialValue: { [key: number]: string } = {}; + const validation = Object.values(this.state.participants).reduce( + (acc, participant) => { + return { + ...acc, + [participant.id]: isTransactionValid({ + value, + isDeposit: true, + boundary, + balance: participant.balance, + }) + ? '' + : `can't afford it`, + }; + }, + initialValue + ); + this.setState({ validation }); + }; + + public formIsValid = () => { + return Object.values(this.state.validation).every(item => item === ''); + }; + public render(): JSX.Element { return ( @@ -226,70 +256,12 @@ export class SplitInvoiceForm extends React.Component { )} /> - 0 && this.state.recipient)} - userId={this.getRecipientUserId(this.state.recipient)} - getString={() => ''} - placeholder="add participant" - autoFocus + - - {this.state.participants.map(participant => ( - - {this.getTransactionId(participant) ? ( - <> - {participant.name}{' '} - - - - ) : ( - - {this.hasErrorState(participant) ? ( - this.createTransaction(participant)} - > - - - ) : ( - this.removeParticipant(participant)} - /> - )} - ( - <> - {!isValid && this.state.amount > 0 && ( - - )} - - )} - />{' '} - {participant.name}{' '} - - - - - )} - - ))} -
); } diff --git a/src/components/user/user-multi-selection.tsx b/src/components/user/user-multi-selection.tsx new file mode 100644 index 00000000..ff9ca924 --- /dev/null +++ b/src/components/user/user-multi-selection.tsx @@ -0,0 +1,48 @@ +import { MultiSelectionBox } from 'bricks-of-sand'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { AppState } from '../../store'; +import { User, UsersState } from '../../store/reducers'; + +interface OwnProps { + placeholder: string; + validation: { [userId: number]: string }; + onSelect(selection: UsersState): void; +} + +interface StateProps { + users: UsersState; +} + +interface ActionProps {} + +export type UserMultiSelectionProps = ActionProps & StateProps & OwnProps; + +export function UserMultiSelection({ + placeholder, + onSelect, + users, + validation, +}: UserMultiSelectionProps): JSX.Element | null { + return ( + (user ? user.id : 0)} + itemToString={user => user.name} + items={users} + onSelect={onSelect} + placeholder={placeholder} + /> + ); +} + +const mapStateToProps = (state: AppState): StateProps => ({ + users: state.user, +}); + +const mapDispatchToProps = {}; + +export const ConnectedUserMultiSelection = connect( + mapStateToProps, + mapDispatchToProps +)(UserMultiSelection);