From 1c7586e7a4abe80f4abb4ea25a864e32c3fbd190 Mon Sep 17 00:00:00 2001 From: Mirlan Date: Mon, 6 Jul 2020 15:19:46 +0600 Subject: [PATCH] Ott 156 language selector (#22) --- src/config/lexics/public.tsx | 3 +++ src/features/App/UnauthenticatedApp.tsx | 31 ++++++++++++++--------- src/features/LexicsStore/index.tsx | 10 ++++++++ src/features/OutsideClick/hooks/index.tsx | 30 ++++++++++++++++++++++ src/features/OutsideClick/index.tsx | 28 ++++++++++++++++++++ src/hooks/index.tsx | 1 + src/hooks/useToggle.tsx | 14 ++++++++++ 7 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 src/config/lexics/public.tsx create mode 100644 src/features/OutsideClick/hooks/index.tsx create mode 100644 src/features/OutsideClick/index.tsx create mode 100644 src/hooks/useToggle.tsx diff --git a/src/config/lexics/public.tsx b/src/config/lexics/public.tsx new file mode 100644 index 00000000..72a7c501 --- /dev/null +++ b/src/config/lexics/public.tsx @@ -0,0 +1,3 @@ +export const publicLexics = { + authorization: 500, +} diff --git a/src/features/App/UnauthenticatedApp.tsx b/src/features/App/UnauthenticatedApp.tsx index a4e7a5a8..bad1d9b6 100644 --- a/src/features/App/UnauthenticatedApp.tsx +++ b/src/features/App/UnauthenticatedApp.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { Fragment } from 'react' import { Route, Redirect, @@ -6,20 +6,27 @@ import { } from 'react-router-dom' import { PAGES } from 'config' +import { publicLexics } from 'config/lexics/public' import { Login } from 'features/Login' import { Register } from 'features/Register' +import { useLexicsConfig } from 'features/LexicsStore' -export const UnauthenticatedApp = () => ( - - - - +export const UnauthenticatedApp = () => { + useLexicsConfig(publicLexics) + return ( + + + + + - - - + + + - - -) + + + + ) +} diff --git a/src/features/LexicsStore/index.tsx b/src/features/LexicsStore/index.tsx index 23325084..1e21c456 100644 --- a/src/features/LexicsStore/index.tsx +++ b/src/features/LexicsStore/index.tsx @@ -2,8 +2,10 @@ import type { ReactNode } from 'react' import React, { createContext, useContext, + useEffect, } from 'react' +import { LexicsConfig } from './types' import { useLexics } from './hooks' type LexicsStore = ReturnType @@ -17,3 +19,11 @@ export const LexicsStore = ({ children }: Props) => { } export const useLexicsStore = () => useContext(LexicsContext) + +export const useLexicsConfig = (config: LexicsConfig) => { + const { addLexicsConfig } = useLexicsStore() + + useEffect(() => { + addLexicsConfig(config) + }, [addLexicsConfig, config]) +} diff --git a/src/features/OutsideClick/hooks/index.tsx b/src/features/OutsideClick/hooks/index.tsx new file mode 100644 index 00000000..ca065c82 --- /dev/null +++ b/src/features/OutsideClick/hooks/index.tsx @@ -0,0 +1,30 @@ +import { useEffect, useRef } from 'react' + +type TUseOutsideClickEffect = { + onClick: Function, +} + +export const useOutsideClickEffect = ({ + onClick, +}: TUseOutsideClickEffect) => { + const wrapperRef = useRef(null) + useEffect(() => { + const handleOutsideClick = ({ target }: MouseEvent) => { + const targetNode = target instanceof Node + ? target + : null + + /** деструктуризация wrapperRef не сработает, ссылка на реф теряется */ + if (wrapperRef.current && !wrapperRef.current.contains(targetNode)) { + onClick() + } + } + + window.addEventListener('mousedown', handleOutsideClick) + + return () => { + window.removeEventListener('mousedown', handleOutsideClick) + } + }, [onClick, wrapperRef]) + return wrapperRef +} diff --git a/src/features/OutsideClick/index.tsx b/src/features/OutsideClick/index.tsx new file mode 100644 index 00000000..822cb023 --- /dev/null +++ b/src/features/OutsideClick/index.tsx @@ -0,0 +1,28 @@ +import type { ReactNode } from 'react' +import React from 'react' + +import styled from 'styled-components' + +import { useOutsideClickEffect } from './hooks' + +type Props = { + /** элемент, которому необходим функционал `OutsideClick` */ + children: ReactNode, + /** функция-коллбек, отрабатывающая по клику вне области элемента */ + onClick: () => void, +} + +const OutsideClickWrapper = styled.div`` + +export const OutsideClick = ({ + children, + onClick, +}: Props) => { + const wrapperRef = useOutsideClickEffect({ onClick }) + + return ( + + {children} + + ) +} diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx index 4c227a28..c0595961 100644 --- a/src/hooks/index.tsx +++ b/src/hooks/index.tsx @@ -1,2 +1,3 @@ export * from './usePageId' export * from './useCurrentLang' +export * from './useToggle' diff --git a/src/hooks/useToggle.tsx b/src/hooks/useToggle.tsx new file mode 100644 index 00000000..a2827d0f --- /dev/null +++ b/src/hooks/useToggle.tsx @@ -0,0 +1,14 @@ +import { useState, useCallback } from 'react' + +export const useToggle = () => { + const [isOpen, setIsOpen] = useState(false) + const open = useCallback(() => setIsOpen(true), []) + const close = useCallback(() => setIsOpen(false), []) + const toggle = useCallback(() => setIsOpen((state) => !state), []) + return { + close, + isOpen, + open, + toggle, + } +}