index.tsx
1 import React, { Component } from 'react'; 2 import { MapStateToProps, connect } from 'react-redux'; 3 import { Link } from 'react-router-dom'; 4 import classnames from 'classnames'; 5 6 import { ANNOUNCEMENT_MESSAGE, ANNOUNCEMENT_TYPE, languages } from 'config'; 7 import { NetworkConfig } from 'types/network'; 8 import { getKeyByValue } from 'utils/helpers'; 9 import logo from 'assets/images/logo-mycrypto.svg'; 10 import { OldDropDown } from 'components/ui'; 11 import { 12 AddCustomNodeAction, 13 TAddCustomNetwork, 14 TAddCustomNode, 15 TChangeLanguage, 16 TChangeNodeRequestedOneTime, 17 TRemoveCustomNode, 18 getLanguageSelection, 19 getNetworkConfig, 20 getOffline, 21 isNodeChanging, 22 isStaticNodeId, 23 changeLanguage, 24 changeNodeRequestedOneTime, 25 addCustomNode, 26 removeCustomNode, 27 addCustomNetwork 28 } from 'features/config'; 29 import { AppState } from 'features/reducers'; 30 import { transactionFieldsActions } from 'features/transaction'; 31 import CustomNodeModal from 'components/CustomNodeModal'; 32 import NetworkDropdown from './components/NetworkDropdown'; 33 import Navigation from './components/Navigation'; 34 import OnlineStatus from './components/OnlineStatus'; 35 import './index.scss'; 36 37 interface OwnProps { 38 networkParam: string | null; 39 } 40 41 interface DispatchProps { 42 changeLanguage: TChangeLanguage; 43 changeNodeRequestedOneTime: TChangeNodeRequestedOneTime; 44 setGasPriceField: transactionFieldsActions.TSetGasPriceField; 45 addCustomNode: TAddCustomNode; 46 removeCustomNode: TRemoveCustomNode; 47 addCustomNetwork: TAddCustomNetwork; 48 } 49 50 interface StateProps { 51 shouldSetNodeFromQS: boolean; 52 network: NetworkConfig; 53 languageSelection: ReturnType<typeof getLanguageSelection>; 54 isChangingNode: ReturnType<typeof isNodeChanging>; 55 isOffline: ReturnType<typeof getOffline>; 56 } 57 58 interface State { 59 isAddingCustomNode: boolean; 60 } 61 62 type Props = OwnProps & StateProps & DispatchProps; 63 64 class Header extends Component<Props, State> { 65 public state = { 66 isAddingCustomNode: false 67 }; 68 69 public componentDidMount() { 70 this.attemptSetNodeFromQueryParameter(); 71 } 72 73 public render() { 74 const { languageSelection, isChangingNode, isOffline, network } = this.props; 75 const { isAddingCustomNode } = this.state; 76 const selectedLanguage = languageSelection; 77 const LanguageDropDown = OldDropDown as new () => OldDropDown<typeof selectedLanguage>; 78 79 return ( 80 <div className="Header"> 81 {ANNOUNCEMENT_MESSAGE && ( 82 <div className={`Header-announcement is-${ANNOUNCEMENT_TYPE}`}> 83 {ANNOUNCEMENT_MESSAGE} 84 </div> 85 )} 86 87 <section className="Header-branding"> 88 <section className="Header-branding-inner container"> 89 <Link to="/" className="Header-branding-title" aria-label="Go to homepage"> 90 <img 91 className="Header-branding-title-logo" 92 src={logo} 93 height="64px" 94 width="245px" 95 alt="MyCrypto logo" 96 /> 97 </Link> 98 <div className="Header-branding-right"> 99 <div className="Header-branding-right-online"> 100 <OnlineStatus isOffline={isOffline} /> 101 </div> 102 103 <div className="Header-branding-right-dropdown"> 104 <LanguageDropDown 105 ariaLabel={`change language. current language ${languages[selectedLanguage]}`} 106 options={Object.values(languages)} 107 value={languages[selectedLanguage]} 108 onChange={this.changeLanguage} 109 size="smr" 110 color="white" 111 /> 112 </div> 113 <div 114 className={classnames({ 115 'Header-branding-right-dropdown': true, 116 'is-flashing': isChangingNode 117 })} 118 > 119 <NetworkDropdown openCustomNodeModal={this.openCustomNodeModal} /> 120 </div> 121 </div> 122 </section> 123 </section> 124 125 <Navigation 126 color={!network.isCustom && network.color} 127 unsupportedTabs={network.unsupportedTabs} 128 /> 129 130 <CustomNodeModal 131 isOpen={isAddingCustomNode} 132 addCustomNode={this.addCustomNode} 133 handleClose={this.closeCustomNodeModal} 134 /> 135 </div> 136 ); 137 } 138 139 public changeLanguage = (value: string) => { 140 const key = getKeyByValue(languages, value); 141 if (key) { 142 this.props.changeLanguage(key); 143 } 144 }; 145 146 private openCustomNodeModal = () => { 147 this.setState({ isAddingCustomNode: true }); 148 }; 149 150 private closeCustomNodeModal = () => { 151 this.setState({ isAddingCustomNode: false }); 152 }; 153 154 private addCustomNode = (payload: AddCustomNodeAction['payload']) => { 155 this.setState({ isAddingCustomNode: false }); 156 this.props.addCustomNode(payload); 157 }; 158 159 private attemptSetNodeFromQueryParameter() { 160 const { shouldSetNodeFromQS, networkParam } = this.props; 161 if (shouldSetNodeFromQS) { 162 this.props.changeNodeRequestedOneTime(networkParam!); 163 } 164 } 165 } 166 167 const mapStateToProps: MapStateToProps<StateProps, OwnProps, AppState> = ( 168 state, 169 { networkParam } 170 ): StateProps => ({ 171 shouldSetNodeFromQS: !!(networkParam && isStaticNodeId(state, networkParam)), 172 isOffline: getOffline(state), 173 isChangingNode: isNodeChanging(state), 174 languageSelection: getLanguageSelection(state), 175 network: getNetworkConfig(state) 176 }); 177 178 const mapDispatchToProps: DispatchProps = { 179 setGasPriceField: transactionFieldsActions.setGasPriceField, 180 changeLanguage, 181 changeNodeRequestedOneTime, 182 addCustomNode, 183 removeCustomNode, 184 addCustomNetwork 185 }; 186 187 export default connect(mapStateToProps, mapDispatchToProps)(Header);