Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.63 KB | None | 0 0
  1. import { Props } from 'react'
  2.  
  3. export interface IHeaderProps extends Props<{}> {
  4. offset?: number
  5. header?: boolean
  6. }
  7.  
  8. export interface IAddressProps extends Props<{}> {
  9. isVisible: boolean
  10. }
  11.  
  12. export interface ILogoImgProps extends Props<{}> {
  13. mobile: boolean
  14. }
  15.  
  16. export interface ISidebarProps extends IAddressProps { }
  17.  
  18. import * as React from 'react'
  19. import { observable, action, autorun } from 'mobx'
  20. import { inject, observer } from 'mobx-react'
  21. import styled, { css } from 'styled-components'
  22. import { NavLink } from 'react-router-dom'
  23. import MediaQuery from 'react-responsive'
  24. const throttle = require('lodash.throttle')
  25.  
  26. import {
  27. Sidebar,
  28. Navigation,
  29. MobileMenu,
  30. AccessibleHiddenText
  31. } from '~/components/common'
  32. import {
  33. IconBtn,
  34. IconName,
  35. TooltipPosition,
  36. HamburgerBtn,
  37. SecondaryBtn,
  38. SecondaryBtnIcon,
  39. SecondaryBtnIconPos,
  40. SecondaryBtnSize
  41. } from '~/components/pru'
  42. import { STORE_MODALS, STORE_UI, STORE_AUTH } from '~/constants/stores'
  43. import { MODAL_REQUEST } from '~/constants/modals'
  44. import { MEDIA } from '~/constants/media-queries'
  45. import {
  46. IHeaderProps,
  47. IAddressProps,
  48. ILogoImgProps,
  49. ISidebarProps
  50. } from './Header.d'
  51. import { LIGHT_LINES } from '~/components/pru/ui-colors'
  52. import { IReactionDisposer } from 'mobx/lib/core/reaction'
  53.  
  54. const logo = require('./img/logo.svg')
  55. const mobileLogo = require('./img/logo_mobile.svg')
  56.  
  57. const HeaderElem = styled.header`
  58. display: flex;
  59. position: fixed;
  60. top: 0;
  61. left: 0;
  62. right: 0;
  63. background-color: #fff;
  64. box-shadow: 0 1px 0 ${LIGHT_LINES};
  65. z-index: 10;
  66.  
  67. ${(props: IHeaderProps) =>
  68. props.offset !== 0 ? `margin-right: ${props.offset}px` : ''};
  69. `
  70.  
  71. const HeaderLeft = styled.section`
  72. display: flex;
  73. flex: 1 0;
  74. align-items: center;
  75. padding: 10px 20px 13px 27px;
  76.  
  77. @media ${MEDIA.untilTablet} {
  78. position: relative;
  79. background-color: #fff;
  80. padding: 0 20px;
  81. }
  82. }`
  83.  
  84. const HeaderRight = HeaderLeft.extend`
  85. justify-content: center;
  86. flex: 0 1;
  87. padding: 0 22px;
  88.  
  89. @media ${MEDIA.untilTablet} {
  90. position: relative;
  91. background-color: #fff;
  92. border-left: 1px solid ${LIGHT_LINES};
  93. padding: 0;
  94. }
  95. `
  96.  
  97. const LogoLink = styled(NavLink).attrs({ exact: true })`
  98. margin-right: 42px;
  99.  
  100. &.active {
  101. pointer-events: none;
  102. }
  103.  
  104. @media ${MEDIA.untilTablet} {
  105. margin-right: 0;
  106. }
  107. `
  108.  
  109. const LogoImg = styled.img.attrs({
  110. src: (props: ILogoImgProps) => (props.mobile ? mobileLogo : logo),
  111. alt: 'ПИК-комфорт'
  112. })`
  113. width: 145px;
  114. height: 41px;
  115.  
  116. @media ${MEDIA.untilTablet} {
  117. // Функцию не удалять, помогает ts в определении типа props для выражение выше.
  118. // внутри styled.attrs определения типа работает не корректно
  119. ${(props: ILogoImgProps) => css`
  120. width: 135px;
  121. height: 33px;
  122. `};
  123. }
  124. `
  125.  
  126. const AddressBlock = styled.p`
  127. position: relative;
  128. display: flex;
  129. align-items: center;
  130. font-size: 13px;
  131. font-weight: 500;
  132. line-height: 1.23;
  133. letter-spacing: 0.6px;
  134. text-align: right;
  135. color: #7f7f7f;
  136. min-height: 32px;
  137. background: url(${require('./img/building.svg')}) no-repeat right center;
  138. padding-right: 35px;
  139. margin: 0 0 0 auto;
  140.  
  141. &::after {
  142. content: '';
  143. display: block;
  144. width: 1px;
  145. position: absolute;
  146. top: 0;
  147. right: -20px;
  148. bottom: 0;
  149. background-color: ${LIGHT_LINES};
  150. }
  151.  
  152. ${(props: IAddressProps) =>
  153. props.isVisible
  154. ? `opacity: 1;
  155. transition: opacity 0.2s linear;`
  156. : `opacity: 0;
  157. transition: opacity 0.1s linear;`};
  158. `
  159.  
  160. const IconButton = styled(IconBtn)`
  161. &:not(:last-child) {
  162. margin-right: 14px;
  163. }
  164. `
  165.  
  166. const Dropdown = styled(Sidebar)`
  167. position: absolute;
  168. top: calc(50% + 23px);
  169. right: 22px;
  170. visibility: hidden;
  171. opacity: 0;
  172. transform: translate(0, 3px);
  173. transition: opacity 0.15s linear, transform 0.15s ease-in-out,
  174. visibility 0.15s linear;
  175. ${(props: ISidebarProps) =>
  176. props.isVisible
  177. ? `
  178. visibility: visible;
  179. opacity: 1;
  180. transform: translate(0, 0);
  181. `
  182. : ``};
  183. `
  184.  
  185. const LogoutBtn = styled(SecondaryBtn)`
  186. min-width: 85px;
  187. `
  188.  
  189. @inject(STORE_MODALS, STORE_UI, STORE_AUTH)
  190. @observer
  191. export default class Header extends React.Component<IHeaderProps> {
  192. @observable addressIsVisible = location.pathname !== '/'
  193.  
  194. static defaultProps = {
  195. header: true
  196. }
  197.  
  198. private scrollListener = throttle(this.handleScroll, 150)
  199. private handleDropdownDisposer: IReactionDisposer
  200.  
  201. constructor(props: React.Props<{}>) {
  202. super(props)
  203.  
  204. this.handleHideDropdownClick = this.handleHideDropdownClick.bind(this)
  205. this.handleRequestBtnClick = this.handleRequestBtnClick.bind(this)
  206. this.handleSidebarBtnClick = this.handleSidebarBtnClick.bind(this)
  207. this.handleHamburgerBtnClick = this.handleHamburgerBtnClick.bind(this)
  208. }
  209.  
  210. componentDidMount() {
  211. const isDesktop =
  212. window.matchMedia && window.matchMedia(MEDIA.fromDesktop_S).matches
  213.  
  214. if (isDesktop && location.pathname === '/') {
  215. window.addEventListener('scroll', this.scrollListener)
  216. }
  217.  
  218. this.props[STORE_UI].toggleMenu(false)
  219. if (this.props[STORE_UI].sidebarIsVisible) {
  220. setTimeout(() => {
  221. this.props[STORE_UI].toggleSidebar(false)
  222. }, 100)
  223. }
  224.  
  225. this.handleDropdownDisposer = autorun(() => {
  226. if (this.props[STORE_UI].sidebarIsVisible) {
  227. document.addEventListener('click', this.handleHideDropdownClick)
  228. } else {
  229. document.removeEventListener('click', this.handleHideDropdownClick)
  230. }
  231. })
  232. }
  233.  
  234. componentWillUnmount() {
  235. window.removeEventListener('scroll', this.scrollListener)
  236. document.removeEventListener('click', this.handleHideDropdownClick)
  237. this.handleDropdownDisposer()
  238. }
  239.  
  240. handleHideDropdownClick({ target }: MouseEvent) {
  241. const isMenuElem = target && (target as Element).closest('#js-sidebar-root')
  242.  
  243. if (!isMenuElem) this.props[STORE_UI].toggleSidebar(false)
  244. }
  245.  
  246. handleRequestBtnClick() {
  247. this.props[STORE_MODALS].openModal(MODAL_REQUEST)
  248. }
  249.  
  250. handleSidebarBtnClick() {
  251. this.props[STORE_UI].toggleSidebar()
  252. }
  253.  
  254. handleHamburgerBtnClick() {
  255. this.props[STORE_UI].toggleMenu()
  256. }
  257.  
  258. @action.bound
  259. handleScroll() {
  260. this.addressIsVisible = window.pageYOffset !== 0
  261. }
  262.  
  263. render() {
  264. const {
  265. layoutOffset,
  266. sidebarIsVisible,
  267. menuIsVisible,
  268. isMobile
  269. } = this.props[STORE_UI]
  270. const { header, [STORE_AUTH]: auth } = this.props
  271.  
  272. return (
  273. <HeaderElem offset={layoutOffset}>
  274. <HeaderLeft>
  275. <LogoLink to="/">
  276. <LogoImg mobile={isMobile} />
  277. </LogoLink>
  278. { header && (<MediaQuery query={MEDIA.fromTablet}>
  279. <nav>
  280. <Navigation />
  281. </nav>
  282. <AddressBlock isVisible={this.addressIsVisible}>
  283. Шмидтовский пр-кт<br />
  284. д. 20, кв. 145
  285. </AddressBlock>
  286. </MediaQuery>) }
  287. </HeaderLeft>
  288. <HeaderRight>
  289. <MediaQuery query={MEDIA.untilTablet}>
  290. <HamburgerBtn
  291. isPressed={menuIsVisible}
  292. onClick={this.handleHamburgerBtnClick}
  293. >
  294. <AccessibleHiddenText>Меню</AccessibleHiddenText>
  295. </HamburgerBtn>
  296. </MediaQuery>
  297. { header ? (<MediaQuery query={MEDIA.fromTablet}>
  298. <IconButton
  299. icon={IconName.WRITE}
  300. tooltip="Электронное обращение"
  301. onClick={this.handleRequestBtnClick}
  302. />
  303. <IconButton
  304. icon={IconName.USER}
  305. tooltip="Вкабинетус Вкабинетовский"
  306. tooltipPosition={TooltipPosition.LEFT}
  307. onClick={this.handleSidebarBtnClick}
  308. >
  309. <AccessibleHiddenText>Профиль</AccessibleHiddenText>
  310. </IconButton>
  311. </MediaQuery>) : <MediaQuery query={MEDIA.fromTablet}>
  312. <LogoutBtn
  313. icon={SecondaryBtnIcon.LOGOUT}
  314. iconPos={SecondaryBtnIconPos.RIGHT}
  315. size={SecondaryBtnSize.SMALL}
  316. onClick={auth.logout}
  317. >
  318. Выйти
  319. </LogoutBtn>
  320. </MediaQuery>}
  321. </HeaderRight>
  322. <Dropdown isVisible={sidebarIsVisible} />
  323. <MediaQuery query={MEDIA.untilTablet}>
  324. <MobileMenu isVisible={menuIsVisible} />
  325. </MediaQuery>
  326. </HeaderElem>
  327. )
  328. }
  329. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement