From 90fea7aadf68cec26cc0253b33c62d1f9dcad792 Mon Sep 17 00:00:00 2001 From: JCNoguera Date: Thu, 25 Jan 2024 15:38:27 +0100 Subject: [PATCH] refactor: cleanup Header and create HeaderDropdown --- client/src/app/components/header/Header.tsx | 530 ++++++++---------- .../app/components/header/HeaderDropdown.tsx | 52 ++ 2 files changed, 285 insertions(+), 297 deletions(-) create mode 100644 client/src/app/components/header/HeaderDropdown.tsx diff --git a/client/src/app/components/header/Header.tsx b/client/src/app/components/header/Header.tsx index defb5ad46..171c7b9d2 100644 --- a/client/src/app/components/header/Header.tsx +++ b/client/src/app/components/header/Header.tsx @@ -1,9 +1,7 @@ -/* eslint-disable react/jsx-closing-tag-location */ +import React, { useEffect, useState } from "react"; +import * as H from "history"; import classNames from "classnames"; -import React, { Component, ReactNode } from "react"; import { Link } from "react-router-dom"; -import { HeaderProps } from "./HeaderProps"; -import { HeaderState } from "./HeaderState"; import Logo from "~assets/logo-header.svg?react"; import mainChrysalisMessage from "~assets/modals/chrysalis/search/main-header.json"; import mainLegacyMessage from "~assets/modals/legacy/search/main-header.json"; @@ -11,326 +9,264 @@ import mainStardustMessage from "~assets/modals/stardust/search/main-header.json import ShimmerLogo from "~assets/shimmer-logo-header.svg?react"; import { ServiceFactory } from "~factories/serviceFactory"; import { isMarketedNetwork, isShimmerUiTheme } from "~helpers/networkHelper"; -import { CHRYSALIS, LEGACY, STARDUST } from "~models/config/protocolVersion"; +import { CHRYSALIS, LEGACY, ProtocolVersion, STARDUST } from "~models/config/protocolVersion"; import { SettingsService } from "~services/settingsService"; import FiatSelector from "../FiatSelector"; -import "./Header.scss"; import Modal from "../Modal"; import NetworkSwitcher from "../NetworkSwitcher"; +import { INetwork } from "~/models/config/INetwork"; +import SearchInput from "../SearchInput"; +import "./Header.scss"; +import GroupDropdown from "./HeaderDropdown"; -/** - * Component which will show the header. - */ -class Header extends Component { - /** - * Settings service. - */ - private readonly _settingsService: SettingsService; +const NETWORK_DROPDOWN_LABEL = "Network Switcher"; - /** - * Create a new instance of Header. - * @param props The props. - */ - constructor(props: HeaderProps) { - super(props); +const EVM_EXPLORER_DROPDOWN = { + label: "EVM Explorer", + routes: [ + { + label: "EVM Explorer", + url: "https://explorer.evm.shimmer.network/", + }, + { + label: "EVM Explorer Testnet", + url: "https://explorer.evm.testnet.shimmer.network/", + }, + ], +}; - this._settingsService = ServiceFactory.get("settings"); +interface IHeader { + rootPath: string; + currentNetwork?: INetwork; + networks: INetwork[]; + history?: H.History; + action?: string; + protocolVersion: ProtocolVersion; + pages?: Route[]; +} - this.state = { - isNetworkSwitcherExpanded: false, - isEvmDropdownExpanded: false, - isMenuExpanded: false, - darkMode: this._settingsService.get().darkMode ?? false, - show: false, - }; - } +export type Route = IRoute | IGroupRoute; + +export interface IRoute { + label: string; + url: string; +} + +export interface IGroupRoute { + label: string; + isExpanded: boolean; + setExpandedDropdownId: (state?: string) => void; + routes: IRoute[]; +} + +export default function Header({ rootPath, currentNetwork, networks, history, action, protocolVersion, pages }: IHeader) { + const settingsService = ServiceFactory.get("settings"); + + const [isMenuExpanded, setIsMenuExpanded] = useState(false); + const [darkMode, setDarkMode] = useState(settingsService.get().darkMode ?? false); + const [show, setShow] = useState(false); + const [expandedDropdownLabel, setExpandedDropdownLabel] = useState(); + + const isEvmDropdownExpanded = expandedDropdownLabel === EVM_EXPLORER_DROPDOWN.label; + const isNetworkSwitcherExpanded = expandedDropdownLabel === NETWORK_DROPDOWN_LABEL; + const isShimmerUi = isShimmerUiTheme(currentNetwork?.uiTheme); + const isMarketed = isMarketedNetwork(currentNetwork?.network); + + useEffect(() => { + toggleModeClass(); + }, []); /** - * The component mounted. + * Toggle the display mode. */ - public componentDidMount(): void { - if (this.state.darkMode) { - this.toggleModeClass(); + function toggleMode(): void { + setDarkMode((darkMode) => !darkMode); + settingsService.saveSingle("darkMode", darkMode); + const event = new CustomEvent("theme-change", { detail: { darkMode: darkMode } }); + window.dispatchEvent(event); + toggleModeClass(); + } + + function toggleModeClass(): void { + const body = document.querySelector("body"); + if (body) { + body.classList.toggle("darkmode", darkMode); } } - /** - * Render the component. - * @returns The node to render. - */ - public render(): ReactNode { - const { rootPath, currentNetwork, networks, history, action, search, pages } = this.props; - const isShimmerUi = isShimmerUiTheme(currentNetwork?.uiTheme); - const isMarketed = isMarketedNetwork(currentNetwork?.network); + function resetExpandedDropdowns(e?: React.MouseEvent): void { + setIsMenuExpanded(false); + closeDropdowns(); + } - const EVM_EXPLORER_DROPDOWN = { - label: "EVM Explorer", - routes: [ - { - label: "EVM Explorer", - url: "https://explorer.evm.shimmer.network/", - }, - { - label: "EVM Explorer Testnet", - url: "https://explorer.evm.testnet.shimmer.network/", - }, - ], - }; + function closeDropdowns(e?: React.MouseEvent): void { + setExpandedDropdownLabel(undefined); + } - return ( -
- -
- ); - } - - /** - * Close expanded dropdowns - */ - private resetExpandedDropdowns(): void { - this.setState({ - isEvmDropdownExpanded: false, - isNetworkSwitcherExpanded: false, - isMenuExpanded: false, - }); - } - - /** - * Toggle the display mode. - */ - private toggleMode(): void { - this.setState( - { - darkMode: !this.state.darkMode, - }, - () => { - this._settingsService.saveSingle("darkMode", this.state.darkMode); - const event = new CustomEvent("theme-change", { detail: { darkMode: this.state.darkMode } }); - window.dispatchEvent(event); - }, - ); - this.toggleModeClass(); - } - - /** - * Toggle darkmode classname to the body DOM node - */ - private toggleModeClass(): void { - const body = document.querySelector("body"); - body?.classList.toggle("darkmode"); - } + +
+ { + history?.push( + action === "streams" + ? `/${targetNetwork}/streams/0/` + : action === "visualizer" + ? `/${targetNetwork}/visualizer/` + : `/${targetNetwork}`, + ); + }} + /> +
+ + + ); } - -export default Header; diff --git a/client/src/app/components/header/HeaderDropdown.tsx b/client/src/app/components/header/HeaderDropdown.tsx new file mode 100644 index 000000000..141410809 --- /dev/null +++ b/client/src/app/components/header/HeaderDropdown.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { IGroupRoute } from "./Header"; +import classNames from "classnames"; +import { Link } from "react-router-dom"; + +export default function GroupDropdown({ label, routes, isExpanded, setExpandedDropdownId }: IGroupRoute): React.JSX.Element { + function toggleOpen(): void { + setExpandedDropdownId(isExpanded ? undefined : label); + } + + function closeDropdown(e: React.MouseEvent): void { + setExpandedDropdownId(); + } + + return ( +
+
+
{label}
+
+ expand_more +
+
+ +
+
+
{label}
+ {routes.map((route) => ( +
+ + {route.label} + +
+ ))} +
+
+ {isExpanded &&
} +
+ ); +}