/* @flow */ import React from 'react'; import styled, { css } from 'styled-components'; import { Select } from 'components/Select'; import Button from 'components/Button'; import Input from 'components/inputs/Input'; import Icon from 'components/Icon'; import Link from 'components/Link'; import ICONS from 'config/icons'; import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables'; import colors from 'config/colors'; import P from 'components/Paragraph'; import { H2 } from 'components/Heading'; import SelectedAccount from 'views/Wallet/components/SelectedAccount'; import type { Token } from 'flowtype'; import AdvancedForm from './components/AdvancedForm'; import PendingTransactions from './components/PendingTransactions'; import type { Props } from './Container'; // TODO: Decide on a small screen width for the whole app // and put it inside config/variables.js const SmallScreenWidth = '850px'; const Wrapper = styled.section` padding: 0 48px; `; const StyledH2 = styled(H2)` padding: 20px 0; `; const AmountInputLabelWrapper = styled.div` display: flex; justify-content: space-between; `; const AmountInputLabel = styled.span` text-align: right; color: ${colors.TEXT_SECONDARY}; `; const InputRow = styled.div` margin-bottom: 20px; `; const SetMaxAmountButton = styled(Button)` height: 34px; padding: 0 10px; display: flex; align-items: center; justify-content: center; font-size: ${FONT_SIZE.SMALLER}; font-weight: ${FONT_WEIGHT.SMALLEST}; color: ${colors.TEXT_SECONDARY}; border-radius: 0; border: 1px solid ${colors.DIVIDER}; border-right: 0; border-left: 0; background: transparent; transition: ${TRANSITION.HOVER}; &:hover { background: ${colors.GRAY_LIGHT}; } ${props => props.isActive && css` color: ${colors.WHITE}; background: ${colors.GREEN_PRIMARY}; border-color: ${colors.GREEN_PRIMARY}; &:hover { background: ${colors.GREEN_SECONDARY}; } &:active { background: ${colors.GREEN_TERTIARY}; } `} `; const CurrencySelect = styled(Select)` min-width: 77px; height: 34px; flex: 0.2; `; const FeeOptionWrapper = styled.div` display: flex; justify-content: space-between; `; const FeeLabelWrapper = styled.div` display: flex; align-items: center; margin-bottom: 4px; `; const FeeLabel = styled.span` color: ${colors.TEXT_SECONDARY}; `; const UpdateFeeWrapper = styled.span` margin-left: 8px; display: flex; align-items: center; font-size: ${FONT_SIZE.SMALLER}; color: ${colors.WARNING_PRIMARY}; `; const StyledLink = styled(Link)` margin-left: 4px; `; const ToggleAdvancedSettingsWrapper = styled.div` min-height: 40px; margin-bottom: 20px; display: flex; flex-direction: row; justify-content: space-between; @media screen and (max-width: ${SmallScreenWidth}) { ${props => (props.isAdvancedSettingsHidden && css` flex-direction: column; `)} } `; const ToggleAdvancedSettingsButton = styled(Button)` min-height: 40px; padding: 0; display: flex; align-items: center; font-weight: ${FONT_WEIGHT.BIGGER}; `; const SendButton = styled(Button)` min-width: ${props => (props.isAdvancedSettingsHidden ? '50%' : '100%')}; font-size: 13px; @media screen and (max-width: ${SmallScreenWidth}) { margin-top: ${props => (props.isAdvancedSettingsHidden ? '10px' : 0)}; } `; const AdvancedSettingsIcon = styled(Icon)` margin-left: 10px; `; // render helpers const getAddressInputState = (address: string, addressErrors: string, addressWarnings: string): string => { let state = ''; if (address && !addressErrors) { state = 'success'; } if (addressWarnings && !addressErrors) { state = 'warning'; } if (addressErrors) { state = 'error'; } return state; }; const getAmountInputState = (amountErrors: string, amountWarnings: string): string => { let state = ''; if (amountWarnings && !amountErrors) { state = 'warning'; } if (amountErrors) { state = 'error'; } return state; }; const getTokensSelectData = (tokens: Array, accountNetwork: any): Array<{ value: string, label: string }> => { const tokensSelectData: Array<{ value: string, label: string }> = tokens.map(t => ({ value: t.symbol, label: t.symbol })); tokensSelectData.unshift({ value: accountNetwork.symbol, label: accountNetwork.symbol }); return tokensSelectData; }; // stateless component const AccountSend = (props: Props) => { const device = props.wallet.selectedDevice; const { account, network, discovery, tokens, } = props.selectedAccount; const { address, amount, setMax, networkSymbol, currency, feeLevels, selectedFeeLevel, gasPriceNeedsUpdate, total, errors, warnings, infos, sending, advanced, } = props.sendForm; const { toggleAdvanced, onAddressChange, onAmountChange, onSetMax, onCurrencyChange, onFeeLevelChange, updateFeeLevels, onSend, } = props.sendFormActions; const isCurrentCurrencyToken = networkSymbol !== currency; let selectedTokenBalance = 0; const selectedToken = tokens.find(t => t.symbol === currency); if (selectedToken) { selectedTokenBalance = selectedToken.balance; } if (!device || !account || !discovery || !network) return null; let isSendButtonDisabled: boolean = Object.keys(errors).length > 0 || total === '0' || amount.length === 0 || address.length === 0 || sending; let sendButtonText: string = 'Send'; if (networkSymbol !== currency && amount.length > 0 && !errors.amount) { sendButtonText += ` ${amount} ${currency.toUpperCase()}`; } else if (networkSymbol === currency && total !== '0') { sendButtonText += ` ${total} ${network.symbol}`; } if (!device.connected) { sendButtonText = 'Device is not connected'; isSendButtonDisabled = true; } else if (!device.available) { sendButtonText = 'Device is unavailable'; isSendButtonDisabled = true; } else if (!discovery.completed) { sendButtonText = 'Loading accounts'; isSendButtonDisabled = true; } const tokensSelectData = getTokensSelectData(tokens, network); const isAdvancedSettingsHidden = !advanced; return ( Send Ethereum or tokens onAddressChange(event.target.value)} /> Amount {(isCurrentCurrencyToken && selectedToken) && ( You have: {selectedTokenBalance} {selectedToken.symbol} )} )} value={amount} onChange={event => onAmountChange(event.target.value)} bottomText={errors.amount || warnings.amount || infos.amount} sideAddons={[ ( onSetMax()} isActive={setMax} > {!setMax && ( )} {setMax && ( )} Set max ), ( ), ]} /> Fee {gasPriceNeedsUpdate && ( Recommended fees updated. Click here to use them )}