diff --git a/client/src/actions/actions.js b/client/src/actions/actions.js index b6678e75..527be153 100644 --- a/client/src/actions/actions.js +++ b/client/src/actions/actions.js @@ -1,6 +1,5 @@ import ActionTypes from '../constants/ActionTypes'; -// eslint-disable-next-line import/prefer-default-export export const fetchActions = (cardId) => ({ type: ActionTypes.ACTIONS_FETCH, payload: { @@ -24,3 +23,28 @@ fetchActions.failure = (cardId, error) => ({ error, }, }); + +export const toggleActionsDetails = (cardId, isVisible) => ({ + type: ActionTypes.ACTIONS_DETAILS_TOGGLE, + payload: { + cardId, + isVisible, + }, +}); + +toggleActionsDetails.success = (cardId, actions, users) => ({ + type: ActionTypes.ACTIONS_DETAILS_TOGGLE__SUCCESS, + payload: { + cardId, + actions, + users, + }, +}); + +toggleActionsDetails.failure = (cardId, error) => ({ + type: ActionTypes.ACTIONS_DETAILS_TOGGLE__FAILURE, + payload: { + cardId, + error, + }, +}); diff --git a/client/src/actions/entry/actions.js b/client/src/actions/entry/actions.js index fbcb5619..a83a544e 100755 --- a/client/src/actions/entry/actions.js +++ b/client/src/actions/entry/actions.js @@ -1,7 +1,13 @@ import EntryActionTypes from '../../constants/EntryActionTypes'; -// eslint-disable-next-line import/prefer-default-export export const fetchActionsInCurrentCard = () => ({ type: EntryActionTypes.ACTIONS_IN_CURRENT_CARD_FETCH, payload: {}, }); + +export const toggleActionsDetailsInCurrentCard = (isVisible) => ({ + type: EntryActionTypes.ACTIONS_DETAILS_IN_CURRENT_CARD_TOGGLE, + payload: { + isVisible, + }, +}); diff --git a/client/src/components/CardModal/Actions/Actions.jsx b/client/src/components/CardModal/Actions/Actions.jsx index 7ba66bf8..62813213 100755 --- a/client/src/components/CardModal/Actions/Actions.jsx +++ b/client/src/components/CardModal/Actions/Actions.jsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; -import { Comment, Icon, Loader, Visibility } from 'semantic-ui-react'; +import { Button, Comment, Icon, Loader, Visibility } from 'semantic-ui-react'; import { ActionTypes } from '../../../constants/Enums'; import CommentAdd from './CommentAdd'; @@ -14,15 +14,22 @@ const Actions = React.memo( items, isFetching, isAllFetched, + isDetailsVisible, + isDetailsFetching, canEdit, canEditAllComments, onFetch, + onDetailsToggle, onCommentCreate, onCommentUpdate, onCommentDelete, }) => { const [t] = useTranslation(); + const handleToggleDetailsClick = useCallback(() => { + onDetailsToggle(!isDetailsVisible); + }, [isDetailsVisible, onDetailsToggle]); + const handleCommentUpdate = useCallback( (id, data) => { onCommentUpdate(id, data); @@ -38,54 +45,51 @@ const Actions = React.memo( ); return ( - <> - {canEdit && ( -
-
- -
{t('common.addComment')}
- -
+
+
+ +
+ {t('common.actions')} +
- )} -
-
- -
{t('common.actions')}
-
- - {items.map((item) => - item.type === ActionTypes.COMMENT_CARD ? ( - handleCommentUpdate(item.id, data)} - onDelete={() => handleCommentDelete(item.id)} - /> - ) : ( - - ), - )} - -
- {isFetching ? ( - - ) : ( - !isAllFetched && - )} + {canEdit && } +
+ + {items.map((item) => + item.type === ActionTypes.COMMENT_CARD ? ( + handleCommentUpdate(item.id, data)} + onDelete={() => handleCommentDelete(item.id)} + /> + ) : ( + + ), + )} +
+ {isFetching || isDetailsFetching ? ( + + ) : ( + !isAllFetched && + )}
- +
); }, ); @@ -94,9 +98,12 @@ Actions.propTypes = { items: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types isFetching: PropTypes.bool.isRequired, isAllFetched: PropTypes.bool.isRequired, + isDetailsVisible: PropTypes.bool.isRequired, + isDetailsFetching: PropTypes.bool.isRequired, canEdit: PropTypes.bool.isRequired, canEditAllComments: PropTypes.bool.isRequired, onFetch: PropTypes.func.isRequired, + onDetailsToggle: PropTypes.func.isRequired, onCommentCreate: PropTypes.func.isRequired, onCommentUpdate: PropTypes.func.isRequired, onCommentDelete: PropTypes.func.isRequired, diff --git a/client/src/components/CardModal/Actions/Actions.module.scss b/client/src/components/CardModal/Actions/Actions.module.scss index 6b165f60..cc76dbdf 100644 --- a/client/src/components/CardModal/Actions/Actions.module.scss +++ b/client/src/components/CardModal/Actions/Actions.module.scss @@ -8,12 +8,14 @@ } .moduleHeader { + align-items: center; color: #17394d; + display: flex; font-size: 16px; font-weight: bold; - line-height: 20px; + height: 36px; + justify-content: space-between; margin: 0 0 4px; - padding: 8px 0; } .moduleIcon { @@ -33,6 +35,24 @@ position: relative; } + .toggleButton { + background: transparent; + box-shadow: none; + color: #6b808c; + float: right; + font-weight: normal; + margin-right: 0; + padding: 6px 11px; + text-align: left; + text-decoration: underline; + transition: none; + + &:hover { + background: rgba(9, 30, 66, 0.08); + color: #092d42; + } + } + .wrapper { margin-left: -40px; margin-top: 12px; diff --git a/client/src/components/CardModal/Actions/CommentAdd.jsx b/client/src/components/CardModal/Actions/CommentAdd.jsx index c8c09e56..f502cfe6 100755 --- a/client/src/components/CardModal/Actions/CommentAdd.jsx +++ b/client/src/components/CardModal/Actions/CommentAdd.jsx @@ -1,10 +1,11 @@ -import React, { useCallback, useRef } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; import TextareaAutosize from 'react-textarea-autosize'; import { Button, Form, TextArea } from 'semantic-ui-react'; +import { useDidUpdate, useToggle } from '../../../lib/hooks'; -import { useForm } from '../../../hooks'; +import { useClosableForm, useForm } from '../../../hooks'; import styles from './CommentAdd.module.scss'; @@ -14,10 +15,16 @@ const DEFAULT_DATA = { const CommentAdd = React.memo(({ onCreate }) => { const [t] = useTranslation(); + const [isOpened, setIsOpened] = useState(false); const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA); + const [selectTextFieldState, selectTextField] = useToggle(); const textField = useRef(null); + const close = useCallback(() => { + setIsOpened(false); + }, []); + const submit = useCallback(() => { const cleanData = { ...data, @@ -32,7 +39,12 @@ const CommentAdd = React.memo(({ onCreate }) => { onCreate(cleanData); setData(DEFAULT_DATA); - }, [onCreate, data, setData]); + selectTextField(); + }, [onCreate, data, setData, selectTextField]); + + const handleFieldFocus = useCallback(() => { + setIsOpened(true); + }, []); const handleFieldKeyDown = useCallback( (event) => { @@ -43,10 +55,16 @@ const CommentAdd = React.memo(({ onCreate }) => { [submit], ); + const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm(close); + const handleSubmit = useCallback(() => { submit(); }, [submit]); + useDidUpdate(() => { + textField.current.ref.current.focus(); + }, [selectTextFieldState]); + return (