/ common / components / Header / index.tsx
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);