1- import React , { Fragment } from "react"
2- import PropTypes from "prop-types"
1+ import React , { useState , useEffect } from "react"
32import classNames from "classnames"
43import throttle from "lodash/throttle"
54import { NavLink } from "react-router-dom"
65import Menu from "react-feather/dist/icons/menu"
76import ChevronRight from "react-feather/dist/icons/chevron-right"
8- import { Accordions } from "undernet"
97
8+ import { NAV_DATA } from "app/components/SideNav/navData"
9+ import { Accordions } from "undernet"
1010import "./styles.scss"
1111
1212const pkg = require ( "projectRoot/package.json" )
1313const MENU_COLLAPSE_WIDTH = 1199
1414
15- export default class SideNav extends React . Component {
16- constructor ( props ) {
17- super ( props )
18- this . handleMenuVisibility = throttle ( this . handleMenuVisibility , 50 )
15+ export default function SideNav ( ) {
16+ // set up effects and state
1917
20- this . state = {
21- menuIsOpen : window . innerWidth > MENU_COLLAPSE_WIDTH ,
22- }
18+ const getWindowInnerWidth = ( ) => {
19+ return window . innerWidth
2320 }
2421
25- static propTypes = {
26- navItems : PropTypes . arrayOf (
27- PropTypes . shape ( {
28- header : PropTypes . string ,
29- links : PropTypes . arrayOf (
30- PropTypes . shape ( {
31- name : PropTypes . string ,
32- url : PropTypes . string ,
33- } )
34- ) ,
35- } )
36- ) . isRequired ,
37- navListClasses : PropTypes . string ,
38- }
22+ const isLargerThanCollapseWidth = getWindowInnerWidth ( ) > MENU_COLLAPSE_WIDTH
23+ const [ menuIsOpen , setMenuIsOpen ] = useState ( isLargerThanCollapseWidth )
3924
40- componentDidMount ( ) {
41- window . addEventListener ( "resize" , this . handleMenuVisibility )
25+ let handleMenuVisibility = ( ) => {
26+ if ( isLargerThanCollapseWidth ) {
27+ setMenuIsOpen ( true )
28+ }
29+ }
4230
43- const menuIsOpen = window . innerWidth > MENU_COLLAPSE_WIDTH
44- this . setState ( { menuIsOpen } )
31+ handleMenuVisibility = throttle ( handleMenuVisibility , 50 )
4532
33+ useEffect ( ( ) => {
4634 Accordions . start ( )
47- }
48-
49- componentWillUnmount ( ) {
50- window . removeEventListener ( "resize" , this . handleMenuVisibility )
51- Accordions . stop ( )
52- }
35+ window . addEventListener ( "resize" , handleMenuVisibility )
36+ setMenuIsOpen ( isLargerThanCollapseWidth )
5337
54- componentDidUpdate ( _ , prevState ) {
55- if ( prevState . menuIsOpen !== this . state . menuIsOpen ) {
38+ return ( ) => {
39+ window . removeEventListener ( "resize" , handleMenuVisibility )
5640 Accordions . stop ( )
57- Accordions . start ( )
5841 }
59- }
42+ } , [ ] )
6043
61- handleCollapseClick = ( ) => {
62- if ( window . innerWidth <= MENU_COLLAPSE_WIDTH ) {
63- this . setState ( { menuIsOpen : false } )
64- }
65- }
44+ useEffect ( ( ) => {
45+ Accordions . stop ( )
46+ Accordions . start ( )
47+ } , [ menuIsOpen ] )
6648
67- handleMenuVisibility = ( ) => {
68- if ( window . innerWidth > MENU_COLLAPSE_WIDTH ) {
69- this . setState ( { menuIsOpen : true } )
49+ // set up handlers
50+
51+ const handleCollapseClick = ( ) => {
52+ if ( getWindowInnerWidth ( ) <= MENU_COLLAPSE_WIDTH ) {
53+ setMenuIsOpen ( false )
7054 }
7155 }
7256
73- handleMenuToggleClick = event => {
57+ const handleMenuToggleClick = event => {
7458 event . preventDefault ( )
75- this . setState ( { menuIsOpen : ! this . state . menuIsOpen } )
59+ setMenuIsOpen ( ! menuIsOpen )
7660 }
7761
78- get buttonClasses ( ) {
62+ const buttonClasses = ( ) => {
7963 return classNames ( "is-justified-center is-aligned-center is-flex is-hidden-xlarge" , {
80- "rotate-180" : ! this . state . menuIsOpen ,
64+ "rotate-180" : ! menuIsOpen ,
8165 } )
8266 }
8367
84- get menuClasses ( ) {
68+ const menuClasses = ( ) => {
8569 return classNames ( "row side-nav-menu accordion has-padding-3" , {
86- "is-hidden" : ! this . state . menuIsOpen ,
70+ "is-hidden" : ! menuIsOpen ,
8771 } )
8872 }
8973
90- accordionIsActive ( items ) {
74+ const accordionIsActive = items => {
9175 let isActive = false
9276
9377 items . forEach ( item => {
@@ -99,14 +83,16 @@ export default class SideNav extends React.Component {
9983 return isActive
10084 }
10185
102- renderAccordionChildLink = item => {
86+ // render content
87+
88+ const renderAccordionChildLink = item => {
10389 return (
10490 < li key = { item . name } role = "none" >
10591 < NavLink
10692 role = "listitem"
10793 className = "side-nav-link-item has-black-text is-flex is-aligned-center"
10894 activeClassName = "active"
109- onClick = { this . handleCollapseClick }
95+ onClick = { handleCollapseClick }
11096 to = { item . url }
11197 >
11298 { item . name } < ChevronRight size = { 16 } role = "presentation" focusable = "false" />
@@ -115,11 +101,11 @@ export default class SideNav extends React.Component {
115101 )
116102 }
117103
118- renderAccordionRow ( section , index ) {
119- const listItems = section . links . map ( this . renderAccordionChildLink )
104+ const renderAccordionRow = ( section , index ) => {
105+ const listItems = section . links . map ( renderAccordionChildLink )
120106
121107 return (
122- < Fragment key = { section . header } >
108+ < React . Fragment key = { section . header } >
123109 < h4 className = "paragraph" >
124110 < button
125111 id = { `nav-acc-button${ index } ` }
@@ -133,53 +119,47 @@ export default class SideNav extends React.Component {
133119 < ul className = "accordion-content" id = { `nav-acc-content${ index } ` } >
134120 { listItems }
135121 </ ul >
136- </ Fragment >
122+ </ React . Fragment >
137123 )
138124 }
139125
140- renderNavAccordion ( ) {
141- return this . props . navItems . map ( ( section , i ) => {
126+ const renderNavAccordion = ( ) => {
127+ return NAV_DATA . map ( ( section , i ) => {
142128 return (
143129 < div
144- data-visible = { this . accordionIsActive ( section . links ) ? "true" : "false" }
130+ data-visible = { accordionIsActive ( section . links ) ? "true" : "false" }
145131 data-accordion-row = { `nav-acc-content${ i } ` }
146- className = { classNames ( "accordion-row" , this . props . navListClasses ) }
132+ className = "accordion-row xsmall-12 columns has-no-padding"
147133 key = { section . links [ 0 ] . url }
148134 >
149- { this . renderAccordionRow ( section , i ) }
135+ { renderAccordionRow ( section , i ) }
150136 </ div >
151137 )
152138 } )
153139 }
154140
155- render ( ) {
156- return (
157- < div className = "xsmall-12 xlarge-2 columns has-no-padding" id = "side-nav" >
158- < div className = "fluid grid side-nav-wrapper" >
159- < div className = "row is-flex is-hidden-xlarge side-nav-expand" >
160- < button
161- onClick = { this . handleMenuToggleClick }
162- className = { this . buttonClasses }
163- aria-controls = "side-nav-wrapper"
164- aria-expanded = { this . state . menuIsOpen }
165- >
166- < Menu size = { 20 } role = "presentation" focusable = "false" /> { " " }
167- < span className = "has-black-text" > Explore</ span >
168- </ button >
169- </ div >
170-
171- < nav
172- data-accordion = "side-nav-accordion"
173- className = { this . menuClasses }
174- id = "side-nav-wrapper"
141+ return (
142+ < div className = "xsmall-12 xlarge-2 columns has-no-padding" id = "side-nav" >
143+ < div className = "fluid grid side-nav-wrapper" >
144+ < div className = "row is-flex is-hidden-xlarge side-nav-expand" >
145+ < button
146+ onClick = { handleMenuToggleClick }
147+ className = { buttonClasses ( ) }
148+ aria-controls = "side-nav-wrapper"
149+ aria-expanded = { menuIsOpen }
175150 >
176- < p className = "version-text has-no-padding has-gray800-text xsmall-12 columns" >
177- Version { pkg . version }
178- </ p >
179- { this . renderNavAccordion ( ) }
180- </ nav >
151+ < Menu size = { 20 } role = "presentation" focusable = "false" /> { " " }
152+ < span className = "has-black-text" > Explore</ span >
153+ </ button >
181154 </ div >
155+
156+ < nav data-accordion = "side-nav-accordion" className = { menuClasses ( ) } id = "side-nav-wrapper" >
157+ < p className = "version-text has-no-padding has-gray800-text xsmall-12 columns" >
158+ Version { pkg . version }
159+ </ p >
160+ { renderNavAccordion ( ) }
161+ </ nav >
182162 </ div >
183- )
184- }
163+ </ div >
164+ )
185165}
0 commit comments