import React, { PureComponent } from 'react'; import classnames from 'classnames'; import { Option } from 'react-select'; import './SwapDropdown.scss'; export interface SingleCoin { id: string; name: string; image: string; status: string; } interface Props { options: SingleCoin[]; disabledOption?: string; value: string; onChange(value: SingleCoin): void; } interface State { isOpen: boolean; mainOptions: SingleCoin[]; otherOptions: SingleCoin[]; } const MAIN_OPTIONS = ['ETH', 'BTC']; class SwapDropdown extends PureComponent { public state: State = { isOpen: false, mainOptions: [], otherOptions: [] }; public dropdown: HTMLDivElement | null; public UNSAFE_componentWillMount() { this.buildOptions(this.props.options); document.addEventListener('click', this.handleBodyClick); } public componentWillUnmount() { document.removeEventListener('click', this.handleBodyClick); } public UNSAFE_componentWillReceiveProps(nextProps: Props) { if (this.props.options !== nextProps.options) { this.buildOptions(nextProps.options); } } public render() { const { options, value, disabledOption } = this.props; const { isOpen, mainOptions, otherOptions } = this.state; const selectedOption = options.find(opt => opt.name === value); return (
(this.dropdown = el)}> {isOpen && (
{mainOptions.map(opt => ( ))} {otherOptions.map(opt => ( ))}
)}
); } private toggleMenu = () => { this.setState({ isOpen: !this.state.isOpen }); }; private handleChange = (coin: SingleCoin) => { this.props.onChange(coin); if (this.state.isOpen) { this.toggleMenu(); } }; private handleBodyClick = (ev: MouseEvent) => { if (!this.state.isOpen || !this.dropdown) { return; } if ( ev.target !== this.dropdown && ev.target instanceof HTMLElement && !this.dropdown.contains(ev.target) ) { this.toggleMenu(); } }; private buildOptions(options: Props['options']) { const mainOptions: SingleCoin[] = []; let otherOptions: SingleCoin[] = []; options.forEach(opt => { if (MAIN_OPTIONS.includes(opt.id)) { mainOptions.push(opt); } else { otherOptions.push(opt); } }); // Sort non-main coins alphabetically otherOptions = otherOptions.sort( (opt1, opt2) => (opt1.id.toLowerCase() > opt2.id.toLowerCase() ? 1 : -1) ); this.setState({ mainOptions, otherOptions }); } } interface SwapOptionProps { option: SingleCoin; isMain?: boolean; isDisabled?: boolean; onChange(opt: Option): void; } const SwapOption: React.SFC = ({ option, isMain, isDisabled, onChange }) => { const handleChange = (ev: React.MouseEvent) => { ev.preventDefault(); onChange({ label: option.id, value: option.name }); }; const classNames = classnames('SwapOption', isMain && 'is-main', isDisabled && 'is-disabled'); return ( ); }; export default SwapDropdown;