diff --git a/client/src/components/App.jsx b/client/src/components/App.jsx index 9a815282..d8458c1d 100755 --- a/client/src/components/App.jsx +++ b/client/src/components/App.jsx @@ -1,26 +1,29 @@ import React from 'react'; import PropTypes from 'prop-types'; -import HeaderContainer from '../containers/HeaderContainer'; -import ProjectsContainer from '../containers/ProjectsContainer'; +import ModalTypes from '../constants/ModalTypes'; +import FixedWrapperContainer from '../containers/FixedWrapperContainer'; +import StaticWrapperContainer from '../containers/StaticWrapperContainer'; import UsersModalContainer from '../containers/UsersModalContainer'; import UserSettingsModalContainer from '../containers/UserSettingsModalContainer'; import AddProjectModalContainer from '../containers/AddProjectModalContainer'; -const App = ({ isUsersModalOpened, isUserSettingsModalOpened, isAddProjectModalOpened }) => ( +const App = ({ currentModal }) => ( <> - - - {isUsersModalOpened && } - {isUserSettingsModalOpened && } - {isAddProjectModalOpened && } + + + {currentModal === ModalTypes.USERS && } + {currentModal === ModalTypes.USER_SETTINGS && } + {currentModal === ModalTypes.ADD_PROJECT && } ); App.propTypes = { - isUsersModalOpened: PropTypes.bool.isRequired, - isUserSettingsModalOpened: PropTypes.bool.isRequired, - isAddProjectModalOpened: PropTypes.bool.isRequired, + currentModal: PropTypes.oneOf(Object.values(ModalTypes)), +}; + +App.defaultProps = { + currentModal: undefined, }; export default App; diff --git a/client/src/components/Board/AddList.jsx b/client/src/components/Board/AddList.jsx index e3c2e1f4..a11998e1 100755 --- a/client/src/components/Board/AddList.jsx +++ b/client/src/components/Board/AddList.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { Button, Form, Input } from 'semantic-ui-react'; @@ -12,48 +12,23 @@ const DEFAULT_DATA = { name: '', }; -const AddList = React.forwardRef(({ children, onCreate }, ref) => { +const AddList = React.memo(({ onCreate, onClose }) => { const [t] = useTranslation(); - const [isOpened, setIsOpened] = useState(false); const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA); const [selectNameFieldState, selectNameField] = useToggle(); const nameField = useRef(null); - const open = useCallback(() => { - setIsOpened(true); - }, []); - - const close = useCallback(() => { - setIsOpened(false); - }, []); - - useImperativeHandle( - ref, - () => ({ - open, - close, - }), - [open, close], - ); - - const handleChildrenClick = useCallback(() => { - open(); - }, [open]); - const handleFieldKeyDown = useCallback( (event) => { if (event.key === 'Escape') { - close(); + onClose(); } }, - [close], + [onClose], ); - const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( - isOpened, - close, - ); + const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm(onClose); const handleSubmit = useCallback(() => { const cleanData = { @@ -73,21 +48,13 @@ const AddList = React.forwardRef(({ children, onCreate }, ref) => { }, [onCreate, data, setData, selectNameField]); useEffect(() => { - if (isOpened) { - nameField.current.select(); - } - }, [isOpened]); + nameField.current.select(); + }, []); useDidUpdate(() => { nameField.current.select(); }, [selectNameFieldState]); - if (!isOpened) { - return React.cloneElement(children, { - onClick: handleChildrenClick, - }); - } - return (
{ }); AddList.propTypes = { - children: PropTypes.element.isRequired, onCreate: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, }; -export default React.memo(AddList); +export default AddList; diff --git a/client/src/components/Board/Board.jsx b/client/src/components/Board/Board.jsx index 8a386877..be936b89 100755 --- a/client/src/components/Board/Board.jsx +++ b/client/src/components/Board/Board.jsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import { DragDropContext, Droppable } from 'react-beautiful-dnd'; @@ -35,6 +35,18 @@ const Board = React.memo( onLabelDelete, }) => { const [t] = useTranslation(); + const [isAddListOpened, setIsAddListOpened] = useState(false); + + const wrapper = useRef(null); + const prevPosition = useRef(null); + + const handleAddListClick = useCallback(() => { + setIsAddListOpened(true); + }, []); + + const handleAddListClose = useCallback(() => { + setIsAddListOpened(false); + }, []); const handleDragStart = useCallback(() => { closePopup(); @@ -66,45 +78,110 @@ const Board = React.memo( [onListMove, onCardMove], ); + const handleMouseDown = useCallback( + (event) => { + if (event.target !== wrapper.current && !event.target.dataset.dragScroller) { + return; + } + + prevPosition.current = event.clientX; + }, + [wrapper], + ); + + const handleWindowMouseMove = useCallback( + (event) => { + if (!prevPosition.current) { + return; + } + + event.preventDefault(); + + window.scrollBy({ + left: prevPosition.current - event.clientX, + }); + + prevPosition.current = event.clientX; + }, + [prevPosition], + ); + + const handleWindowMouseUp = useCallback(() => { + prevPosition.current = null; + }, [prevPosition]); + + useEffect(() => { + if (isAddListOpened) { + window.scroll(document.body.scrollWidth, 0); + } + }, [listIds, isAddListOpened]); + + useEffect(() => { + window.addEventListener('mouseup', handleWindowMouseUp); + window.addEventListener('mousemove', handleWindowMouseMove); + + return () => { + window.removeEventListener('mouseup', handleWindowMouseUp); + window.removeEventListener('mousemove', handleWindowMouseMove); + }; + }, [handleWindowMouseUp, handleWindowMouseMove]); + return ( <> - -
- - - {({ innerRef, droppableProps, placeholder }) => ( - // eslint-disable-next-line react/jsx-props-no-spreading -
- {listIds.map((listId, index) => ( - - ))} - {placeholder} -
- - - + {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} +
+ +
+ + + {({ innerRef, droppableProps, placeholder }) => ( +
+ {listIds.map((listId, index) => ( + + ))} + {placeholder} +
+ {isAddListOpened ? ( + + ) : ( + + )} +
-
- )} - - + )} + + +
{isCardModalOpened && } diff --git a/client/src/components/Board/Board.module.css b/client/src/components/Board/Board.module.css index 505dff65..d844b366 100644 --- a/client/src/components/Board/Board.module.css +++ b/client/src/components/Board/Board.module.css @@ -48,5 +48,5 @@ } .wrapper { - height: 100%; + margin: 0 20px; } diff --git a/client/src/components/Board/Filter.jsx b/client/src/components/Board/Filter.jsx index c5bc5f28..01e2fb81 100644 --- a/client/src/components/Board/Filter.jsx +++ b/client/src/components/Board/Filter.jsx @@ -25,14 +25,14 @@ const Filter = React.memo( }) => { const [t] = useTranslation(); - const handleUserRemoveClick = useCallback( + const handleRemoveUserClick = useCallback( (id) => { onUserRemove(id); }, [onUserRemove], ); - const handleLabelRemoveClick = useCallback( + const handleRemoveLabelClick = useCallback( (id) => { onLabelRemove(id); }, @@ -62,7 +62,7 @@ const Filter = React.memo( name={user.name} avatarUrl={user.avatarUrl} size="tiny" - onClick={() => handleUserRemoveClick(user.id)} + onClick={() => handleRemoveUserClick(user.id)} /> ))} @@ -91,7 +91,7 @@ const Filter = React.memo( name={label.name} color={label.color} size="small" - onClick={() => handleLabelRemoveClick(label.id)} + onClick={() => handleRemoveLabelClick(label.id)} /> ))} diff --git a/client/src/components/Boards/Boards.jsx b/client/src/components/Boards/Boards.jsx index 223c0588..364e313e 100755 --- a/client/src/components/Boards/Boards.jsx +++ b/client/src/components/Boards/Boards.jsx @@ -2,16 +2,13 @@ import pick from 'lodash/pick'; import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { useTranslation, Trans } from 'react-i18next'; import { Link } from 'react-router-dom'; import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; import { Button, Icon } from 'semantic-ui-react'; import { closePopup } from '../../lib/popup'; -import { DragScroller } from '../../lib/custom-ui'; import Paths from '../../constants/Paths'; import DroppableTypes from '../../constants/DroppableTypes'; -import BoardWrapperContainer from '../../containers/BoardWrapperContainer'; import AddPopup from './AddPopup'; import EditPopup from './EditPopup'; @@ -19,8 +16,6 @@ import styles from './Boards.module.css'; const Boards = React.memo( ({ items, currentId, isEditable, onCreate, onUpdate, onMove, onDelete }) => { - const [t] = useTranslation(); - const handleDragStart = useCallback(() => { closePopup(); }, []); @@ -139,28 +134,6 @@ const Boards = React.memo( ) : (
{renderItems(items)}
)} - - {currentId ? ( - - ) : ( -
- -

- {t('common.openBoard', { - context: 'title', - })} -

-
- -
-
- )} -
); }, diff --git a/client/src/components/Boards/Boards.module.css b/client/src/components/Boards/Boards.module.css index 122cdc95..d1bdf6ce 100644 --- a/client/src/components/Boards/Boards.module.css +++ b/client/src/components/Boards/Boards.module.css @@ -9,15 +9,6 @@ background: rgba(34, 36, 38, 0.3) !important; } -.board { - display: flex; - flex: 1 1 auto; - flex-direction: column; - margin: 0 -20px 8px; - overflow: auto; - padding: 0 20px; -} - .editButton { background: transparent !important; color: #fff !important; @@ -45,32 +36,6 @@ overflow: hidden; } -.message { - align-content: space-between; - align-items: center; - color: #fff; - display: flex; - flex: 1 1 auto; - flex-direction: column; - justify-content: center; -} - -.messageIcon { - margin-top: -84px; -} - -.messageTitle { - font-size: 32px; - margin: 24px 0 8px; -} - -.messageContent { - font-size: 18px; - line-height: 1.4; - margin: 4px 0 0; - text-align: center; -} - .tab { border-radius: 3px 3px 0 0; min-width: 100px; @@ -104,7 +69,6 @@ display: flex; height: 38px; flex: 0 0 auto; - margin-bottom: 16px; white-space: nowrap; } diff --git a/client/src/components/Card/ActionsPopup.jsx b/client/src/components/Card/ActionsPopup.jsx index 48e636d5..f0286e57 100644 --- a/client/src/components/Card/ActionsPopup.jsx +++ b/client/src/components/Card/ActionsPopup.jsx @@ -51,7 +51,7 @@ const ActionsStep = React.memo( const [t] = useTranslation(); const [step, openStep, handleBack] = useSteps(); - const handleNameEditClick = useCallback(() => { + const handleEditNameClick = useCallback(() => { onNameEdit(); onClose(); }, [onNameEdit, onClose]); @@ -178,7 +178,7 @@ const ActionsStep = React.memo( - + {t('action.editTitle', { context: 'title', })} diff --git a/client/src/components/Card/EditName.jsx b/client/src/components/Card/EditName.jsx index a7673559..84bc6b2d 100644 --- a/client/src/components/Card/EditName.jsx +++ b/client/src/components/Card/EditName.jsx @@ -69,8 +69,8 @@ const EditName = React.forwardRef(({ children, defaultValue, onUpdate }, ref) => ); const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( - isOpened, close, + isOpened, ); const handleSubmit = useCallback(() => { diff --git a/client/src/components/CardModal/Actions/EditComment.jsx b/client/src/components/CardModal/Actions/EditComment.jsx index 2d8f887a..fe255401 100755 --- a/client/src/components/CardModal/Actions/EditComment.jsx +++ b/client/src/components/CardModal/Actions/EditComment.jsx @@ -66,8 +66,8 @@ const EditComment = React.forwardRef(({ children, defaultData, onUpdate }, ref) ); const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( - isOpened, close, + isOpened, ); const handleSubmit = useCallback(() => { diff --git a/client/src/components/CardModal/CardModal.jsx b/client/src/components/CardModal/CardModal.jsx index 159fba5a..0344f766 100755 --- a/client/src/components/CardModal/CardModal.jsx +++ b/client/src/components/CardModal/CardModal.jsx @@ -117,7 +117,7 @@ const CardModal = React.memo( [onUpdate], ); - const handleToggleSubscribeClick = useCallback(() => { + const handleToggleSubscriptionClick = useCallback(() => { onUpdate({ isSubscribed: !isSubscribed, }); @@ -359,7 +359,7 @@ const CardModal = React.memo(