AllenYuan

Untitled

May 31st, 2020
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.40 KB | None | 0 0
  1. import {
  2. IconButton,
  3. List,
  4. ListItem,
  5. ListItemText,
  6. Menu,
  7. MenuItem,
  8. SwipeableDrawer,
  9. } from '@material-ui/core';
  10. import {BugReport, Menu as MenuIcon, Settings} from '@material-ui/icons';
  11. import LogOutButton from 'material-ui/svg-icons/action/power-settings-new';
  12. import {Toolbar, ToolbarGroup} from 'material-ui/Toolbar';
  13. import PropTypes from 'prop-types';
  14. import React, {useCallback, useState, useRef} from 'react';
  15. import {useSelector} from 'react-redux';
  16. import {Link} from 'react-router-dom';
  17. import styled from 'styled-components';
  18.  
  19. import {GITHUB_REPO} from '../../config';
  20. import AppLogo from '../App/AppLogo';
  21. import constants from '../constants';
  22.  
  23. const REPORT_BUG_PATH = `//github.com/${GITHUB_REPO}/issues`;
  24.  
  25. // create styling for each major subcomponent of Header
  26. const VerticalAlignToolbar = styled(ToolbarGroup)`
  27. display: flex;
  28. align-items: center;
  29. justify-content: center;
  30. `;
  31.  
  32. const VerticalAlignDiv = styled.div`
  33. display: flex;
  34. align-items: center;
  35. justify-content: center;
  36. `;
  37.  
  38. const TabContainer = styled.div`
  39. display: flex;
  40. flex-direction: column;
  41. font-weight: ${constants.fontWeightNormal};
  42. height: 100%;
  43. justify-content: center;
  44. margin: 0 12px;
  45. text-align: center;
  46. position: relative;
  47. `;
  48.  
  49. const AppLogoWrapper = styled.div`
  50. // for small screens, remove the applogo from the navigation
  51. @media screen and (max-width: 800px) {
  52. display: none;
  53. }
  54. `;
  55.  
  56. const DropdownMenu = styled(Menu)`
  57. & .MuiMenu-paper {
  58. background: ${constants.primarySurfaceColor};
  59. }
  60. `;
  61.  
  62. const DropdownMenuItem = styled(MenuItem)`
  63. color: ${constants.primaryTextColor} !important;
  64. padding-bottom: 12px !important;
  65. padding-top: 12px !important;
  66. `;
  67.  
  68. const ToolbarHeader = styled(Toolbar)`
  69. backdrop-filter: blur(16px);
  70. background-color: ${constants.defaultPrimaryColorSolid} !important;
  71. height: 56px;
  72. left: 0;
  73. padding: 8px 16px !important;
  74. position: fixed;
  75. top: 0;
  76. width: 100%;
  77. z-index: 100%;
  78.  
  79. & a {
  80. color: ${constants.primaryTextColor};
  81.  
  82. &:hover {
  83. color: ${constants.primaryTextColor};
  84. opacity: 0.6;
  85. }
  86. }
  87. `;
  88.  
  89. const MenuContent = styled.div`
  90. background: ${constants.primarySurfaceColor};
  91. max-width: 300px;
  92. height: 100%;
  93. overflow: auto;
  94. min-width: 220px;
  95. `;
  96.  
  97. const MenuLogoWrapper = styled.div`
  98. align-items: center;
  99. display: flex;
  100. justify-content: center;
  101. padding: 24px 0;
  102. `;
  103.  
  104. const DrawerLink = styled(Link)`
  105. color: ${constants.textColorPrimary};
  106. `;
  107.  
  108. const LinkGroup = ({navbarPages}) => (
  109. <VerticalAlignToolbar>
  110. {navbarPages.map((page) => (
  111. <TabContainer key={page.key}>
  112. <Link to={page.to}>{page.label}</Link>
  113. {Boolean(page.feature) && (
  114. <div
  115. style={{
  116. position: 'absolute',
  117. textTransform: 'uppercase',
  118. fontSize: '10px',
  119. top: '-10px',
  120. right: '0',
  121. color: 'lightblue',
  122. }}
  123. >
  124. {page.feature}
  125. </div>
  126. )}
  127. </TabContainer>
  128. ))}
  129. </VerticalAlignToolbar>
  130. );
  131.  
  132. LinkGroup.propTypes = {
  133. navbarPages: PropTypes.shape([{}]),
  134. };
  135.  
  136. const SettingsGroup = ({ children }) => {
  137. const [anchorEl, setAnchorEl] = useState(null); // setanchorel hook
  138. const buttonRef = useRef(); // ref for anchorEl
  139.  
  140. // init the handleclose callback: clear setanchorel
  141. const handleClose = useCallback(() => {
  142. setAnchorEl(undefined);
  143. }, [setAnchorEl]);
  144.  
  145. return (
  146. <>
  147. <IconButton
  148. ref={buttonRef}
  149. color="inherit"
  150. onClick={(e) => setAnchorEl(e.currentTarget)}
  151. >
  152. <Settings />
  153. </IconButton>
  154. {buttonRef.current && (
  155. <DropdownMenu
  156. anchorEl={buttonRef.current}
  157. open={Boolean(anchorEl)}
  158. onClose={handleClose}
  159. PaperProps={{ style: { maxHeight: 600 }}}
  160. >
  161. {children}
  162. </DropdownMenu>
  163. )}
  164. </>
  165. );
  166. };
  167.  
  168. const MenuButtonWrapper = styled.div`
  169. margin-right: 12px;
  170. `;
  171.  
  172. const LogoGroup = ({ onMenuClick }) => (
  173. <div style={{ marginRight: 16 }}>
  174. <VerticalAlignToolbar>
  175. <MenuButtonWrapper>
  176. <IconButton edge="start" color="inherit" onClick={onMenuClick}>
  177. <MenuIcon />
  178. </IconButton>
  179. </MenuButtonWrapper>
  180. <AppLogoWrapper>
  181. <AppLogo />
  182. </AppLogoWrapper>
  183. </VerticalAlignToolbar>
  184. </div>
  185. );
  186.  
  187. LogoGroup.propTypes = {
  188. onMenuClick: PropTypes.func,
  189. };
  190.  
  191. const ReportBug = ({ strings }) => (
  192. <DropdownMenuItem
  193. component="a"
  194. href={REPORT_BUG_PATH}
  195. target="_blank" // open in new tab
  196. rel="noopener noreferrer" // security for opening in new tab
  197. >
  198. <BugReport style={{ marginRight: 32, width: 24, height: 24 }} />
  199. {strings.app_report_bug}
  200. </DropdownMenuItem>
  201. );
  202.  
  203. ReportBug.propTypes = {
  204. strings: PropTypes.shape({}),
  205. };
  206.  
  207. const LogOut = ({ strings }) => (
  208. <DropdownMenuItem
  209. component="a"
  210. href={`${process.env.REACT_APP_API_HOST}/logout`}
  211. rel="noopener noreferrer"
  212. >
  213. <LogOutButton style={{ marginRight: 32, width: 24, height: 24 }} />
  214. {strings.app_logout}
  215. </DropdownMenuItem>
  216. );
  217.  
  218. LogOut.propTypes = {
  219. strings: PropTypes.shape({}),
  220. };
  221.  
  222. const Header = ({ location, disableSearch }) => {
  223. // set hooks
  224. const [menuIsOpen, setMenuState] = useState(false);
  225.  
  226. // state selectors
  227. const small = useSelector((state) => state.browser.greaterThan.small);
  228. const user = useSelector((state) => state.app.metadata.data.user);
  229. const strings = useSelector((state) => state.app.strings);
  230.  
  231. // data encoding navbar
  232. const navbarPages = [
  233. {
  234. key: 'header_matches',
  235. to: '/matches',
  236. label: strings.header_matches,
  237. },
  238. {
  239. key: 'header_heroes',
  240. to: '/heroes',
  241. label: strings.header_heroes,
  242. },
  243. {
  244. key: 'header_explorer',
  245. to: '/explorer',
  246. label: strings.header_explorer,
  247. },
  248. {
  249. key: 'header_combos',
  250. to: '/combos',
  251. label: strings.combos,
  252. feature: '2020 BP',
  253. },
  254. {
  255. key: 'header_api',
  256. to: '/api-keys',
  257. label: strings.header_api,
  258. },
  259. ];
  260.  
  261. // add some pages revealed by drawer
  262. const drawerPages = [
  263. ...navbarPages,
  264. {
  265. key: 'header_distributions',
  266. to: '/distributions',
  267. label: strings.header_distributions,
  268. },
  269. {
  270. key: 'header_records',
  271. to: '/records',
  272. label: strings.header_records,
  273. },
  274. {
  275. key: 'header_meta',
  276. to: '/meta',
  277. label: strings.header_meta,
  278. },
  279. {
  280. key: 'header_scenarios',
  281. to: '/scenarios',
  282. label: strings.header_scenarios,
  283. },
  284. ];
  285.  
  286. return (
  287. <>
  288. <ToolbarHeader>
  289. {/* logo/settings groups */}
  290. <VerticalAlignDiv>
  291. <LogoGroup onMenuClick={() => setMenuState(true)} />
  292. {small && <LinkGroup navbarPages={navbarPages} />}
  293. </VerticalAlignDiv>
  294. <VerticalAlignDiv style={{ marginLeft: '16px' }}>
  295. <SettingsGroup>
  296. <ReportBug strings={strings} />
  297. {user ? <LogOut strings={strings} /> : null}
  298. </SettingsGroup>
  299. </VerticalAlignDiv>
  300. {/* drawer */}
  301. <SwipeableDrawer
  302. onOpen={() => setMenuState(true)}
  303. onClose = {() => setMenuState(false)}
  304. open = {menuIsOpen}
  305. >
  306. <MenuContent>
  307. <MenuLogoWrapper>
  308. <div>
  309. <AppLogo onClick={() => setMenuState(false)} />
  310. </div>
  311. </MenuLogoWrapper>
  312. {/* render the drawer links */}
  313. <List>
  314. {drawerPages.map((page) => (
  315. <DrawerLink key={`drawer__${page.to}`} to={page.to}>
  316. <ListItem
  317. button
  318. key={`drawer__${page.to}`}
  319. onClick={() => setMenuState(false)}
  320. >
  321. <ListItemText primary={page.label} />
  322. </ListItem>
  323. </DrawerLink>
  324. ))}
  325. </List>
  326. {/* render user links/login links */}
  327. <List>
  328. {user ? (
  329. <>
  330. <DrawerLink to={`/players/${user.account_id}`}>
  331. <ListItem button onClick={() => setMenuState(false)}>
  332. <ListItemText primary={strings.app_my_profile} />
  333. </ListItem>
  334. </DrawerLink>
  335. <DrawerLink
  336. as="a"
  337. href={`${process.env.REACT_APP_API_HOST}/logout`}
  338. >
  339. <ListItem button onClick={() => setMenuState(false)}>
  340. <ListItemText primary={strings.app_logout} />
  341. </ListItem>
  342. </DrawerLink>
  343. </>
  344. ) : (
  345. <>
  346. <DrawerLink
  347. as="a"
  348. href={`${process.env.REACT_APP_API_HOST}/login`}
  349. >
  350. <ListItem button onClick={() => setMenuState(false)}>
  351. <ListItemText primary={strings.app_login} />
  352. </ListItem>
  353. </DrawerLink>
  354. </>
  355. )}
  356. </List>
  357. </MenuContent>
  358. </SwipeableDrawer>
  359. </ToolbarHeader>
  360. </>
  361. );
  362. };
  363.  
  364. export default Header;
Add Comment
Please, Sign In to add comment