From 3660ba28d73d70d08bf14c33ef680e5ef3ec7f3b Mon Sep 17 00:00:00 2001
From: Fabio Berger <me@fabioberger.com>
Date: Tue, 21 Nov 2017 14:03:08 -0600
Subject: Add website to mono repo, update packages to align with existing
 sub-packages, use new subscribeAsync 0x.js method

---
 .../ts/components/inputs/balance_bounded_input.tsx | 160 +++++++++++++++++++++
 1 file changed, 160 insertions(+)
 create mode 100644 packages/website/ts/components/inputs/balance_bounded_input.tsx

(limited to 'packages/website/ts/components/inputs/balance_bounded_input.tsx')

diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx
new file mode 100644
index 000000000..1c8b410a4
--- /dev/null
+++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx
@@ -0,0 +1,160 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+import BigNumber from 'bignumber.js';
+import {ValidatedBigNumberCallback, InputErrMsg, WebsitePaths} from 'ts/types';
+import TextField from 'material-ui/TextField';
+import {RequiredLabel} from 'ts/components/ui/required_label';
+import {colors} from 'material-ui/styles';
+import {utils} from 'ts/utils/utils';
+import {Link} from 'react-router-dom';
+
+interface BalanceBoundedInputProps {
+    label?: string;
+    balance: BigNumber;
+    amount?: BigNumber;
+    onChange: ValidatedBigNumberCallback;
+    shouldShowIncompleteErrs?: boolean;
+    shouldCheckBalance: boolean;
+    validate?: (amount: BigNumber) => InputErrMsg;
+    onVisitBalancesPageClick?: () => void;
+    shouldHideVisitBalancesLink?: boolean;
+}
+
+interface BalanceBoundedInputState {
+    errMsg: InputErrMsg;
+    amountString: string;
+}
+
+export class BalanceBoundedInput extends
+    React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> {
+    public static defaultProps: Partial<BalanceBoundedInputProps> = {
+        shouldShowIncompleteErrs: false,
+        shouldHideVisitBalancesLink: false,
+    };
+    constructor(props: BalanceBoundedInputProps) {
+        super(props);
+        const amountString = this.props.amount ? this.props.amount.toString() : '';
+        this.state = {
+            errMsg: this.validate(amountString, props.balance),
+            amountString,
+        };
+    }
+    public componentWillReceiveProps(nextProps: BalanceBoundedInputProps) {
+        if (nextProps === this.props) {
+            return;
+        }
+        const isCurrentAmountNumeric = utils.isNumeric(this.state.amountString);
+        if (!_.isUndefined(nextProps.amount)) {
+            let shouldResetState = false;
+            if (!isCurrentAmountNumeric) {
+                shouldResetState = true;
+            } else {
+                const currentAmount = new BigNumber(this.state.amountString);
+                if (!currentAmount.eq(nextProps.amount) || !nextProps.balance.eq(this.props.balance)) {
+                    shouldResetState = true;
+                }
+            }
+            if (shouldResetState) {
+                const amountString = nextProps.amount.toString();
+                this.setState({
+                    errMsg: this.validate(amountString, nextProps.balance),
+                    amountString,
+                });
+            }
+        } else if (isCurrentAmountNumeric) {
+            const amountString = '';
+            this.setState({
+                errMsg: this.validate(amountString, nextProps.balance),
+                amountString,
+            });
+        }
+    }
+    public render() {
+        let errorText = this.state.errMsg;
+        if (this.props.shouldShowIncompleteErrs && this.state.amountString === '') {
+            errorText = 'This field is required';
+        }
+        let label: React.ReactNode|string = '';
+        if (!_.isUndefined(this.props.label)) {
+            label = <RequiredLabel label={this.props.label}/>;
+        }
+        return (
+            <TextField
+                fullWidth={true}
+                floatingLabelText={label}
+                floatingLabelFixed={true}
+                floatingLabelStyle={{color: colors.grey500, width: 206}}
+                errorText={errorText}
+                value={this.state.amountString}
+                hintText={<span style={{textTransform: 'capitalize'}}>amount</span>}
+                onChange={this.onValueChange.bind(this)}
+                underlineStyle={{width: 'calc(100% + 50px)'}}
+            />
+        );
+    }
+    private onValueChange(e: any, amountString: string) {
+        const errMsg = this.validate(amountString, this.props.balance);
+        this.setState({
+            amountString,
+            errMsg,
+        }, () => {
+            const isValid = _.isUndefined(errMsg);
+            if (utils.isNumeric(amountString)) {
+                this.props.onChange(isValid, new BigNumber(amountString));
+            } else {
+                this.props.onChange(isValid);
+            }
+        });
+    }
+    private validate(amountString: string, balance: BigNumber): InputErrMsg {
+        if (!utils.isNumeric(amountString)) {
+            return amountString !== '' ? 'Must be a number' : '';
+        }
+        const amount = new BigNumber(amountString);
+        if (amount.eq(0)) {
+            return 'Cannot be zero';
+        }
+        if (this.props.shouldCheckBalance && amount.gt(balance)) {
+            return (
+                <span>
+                    Insufficient balance.{' '}
+                    {this.renderIncreaseBalanceLink()}
+                </span>
+            );
+        }
+        const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount);
+        return errMsg;
+    }
+    private renderIncreaseBalanceLink() {
+        if (this.props.shouldHideVisitBalancesLink) {
+            return null;
+        }
+
+        const increaseBalanceText = 'Increase balance';
+        const linkStyle = {
+            cursor: 'pointer',
+            color: colors.grey900,
+            textDecoration: 'underline',
+            display: 'inline',
+        };
+        if (_.isUndefined(this.props.onVisitBalancesPageClick)) {
+            return (
+                <Link
+                    to={`${WebsitePaths.Portal}/balances`}
+                    style={linkStyle}
+                >
+                    {increaseBalanceText}
+                </Link>
+            );
+        } else {
+            return (
+                <div
+                    onClick={this.props.onVisitBalancesPageClick}
+                    style={linkStyle}
+                >
+                    {increaseBalanceText}
+                </div>
+            );
+        }
+    }
+}
-- 
cgit v1.2.3

