diff --git a/client/src/components/attachments/Attachments/ItemContent.jsx b/client/src/components/attachments/Attachments/ItemContent.jsx index b6dc5eaf..045871ab 100644 --- a/client/src/components/attachments/Attachments/ItemContent.jsx +++ b/client/src/components/attachments/Attachments/ItemContent.jsx @@ -9,6 +9,7 @@ import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Button, Icon, Label, Loader } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; @@ -161,9 +162,11 @@ const ItemContent = React.forwardRef(({ id, onOpen }, ref) => { {canEdit && ( - + + + )} diff --git a/client/src/components/base-custom-field-groups/BaseCustomFieldGroupStep/CustomField.jsx b/client/src/components/base-custom-field-groups/BaseCustomFieldGroupStep/CustomField.jsx index f12c497a..67bc893a 100755 --- a/client/src/components/base-custom-field-groups/BaseCustomFieldGroupStep/CustomField.jsx +++ b/client/src/components/base-custom-field-groups/BaseCustomFieldGroupStep/CustomField.jsx @@ -8,7 +8,9 @@ import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { Draggable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button, Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; @@ -18,6 +20,7 @@ const CustomField = React.memo(({ id, index, onEdit }) => { const selectCustomFieldById = useMemo(() => selectors.makeSelectCustomFieldById(), []); const customField = useSelector((state) => selectCustomFieldById(state, id)); + const [t] = useTranslation(); const handleEditClick = useCallback(() => { onEdit(id); @@ -36,14 +39,16 @@ const CustomField = React.memo(({ id, index, onEdit }) => { {customField.showOnFrontOfCard && } {customField.name} - {onCardPaste && clipboard && canPasteCard && ( - + + + )} diff --git a/client/src/components/boards/Board/ListView.jsx b/client/src/components/boards/Board/ListView.jsx index aa281324..712c6652 100755 --- a/client/src/components/boards/Board/ListView.jsx +++ b/client/src/components/boards/Board/ListView.jsx @@ -10,6 +10,7 @@ import { shallowEqual, useSelector } from 'react-redux'; import { useInView } from 'react-intersection-observer'; import { useTranslation } from 'react-i18next'; import { Button, Icon, Loader } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import { BoardMembershipRoles } from '../../../constants/Enums'; @@ -74,14 +75,16 @@ const ListView = React.memo( {onCardPaste && clipboard && canPasteCard && ( - + + + )} ))} diff --git a/client/src/components/boards/BoardActions/Filters.jsx b/client/src/components/boards/BoardActions/Filters.jsx index b193a7ed..6b3138f6 100644 --- a/client/src/components/boards/BoardActions/Filters.jsx +++ b/client/src/components/boards/BoardActions/Filters.jsx @@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next'; import { Icon } from 'semantic-ui-react'; import { useDidUpdate } from '../../../lib/hooks'; import { usePopup } from '../../../lib/popup'; -import { Input } from '../../../lib/custom-ui'; +import { Input, Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; @@ -162,11 +162,13 @@ const Filters = React.memo(() => { {userIds.length === 0 && withCurrentUserSelector && ( - + + + )} {userIds.map((userId) => ( diff --git a/client/src/components/boards/BoardActions/RightSide/RightSide.jsx b/client/src/components/boards/BoardActions/RightSide/RightSide.jsx index 8eb5b936..7d57dcc8 100644 --- a/client/src/components/boards/BoardActions/RightSide/RightSide.jsx +++ b/client/src/components/boards/BoardActions/RightSide/RightSide.jsx @@ -5,7 +5,9 @@ import React, { useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../../lib/custom-ui'; import { usePopup } from '../../../../lib/popup'; import selectors from '../../../../selectors'; @@ -20,6 +22,7 @@ const RightSide = React.memo(() => { const board = useSelector(selectors.selectCurrentBoard); const dispatch = useDispatch(); + const [t] = useTranslation(); const handleSelectViewClick = useCallback( ({ currentTarget: { value: view } }) => { @@ -40,24 +43,33 @@ const RightSide = React.memo(() => {
{views.map((view) => ( - + + ))}
- + + +
diff --git a/client/src/components/boards/Boards/Boards.jsx b/client/src/components/boards/Boards/Boards.jsx index 24db0c9a..ada07ebd 100755 --- a/client/src/components/boards/Boards/Boards.jsx +++ b/client/src/components/boards/Boards/Boards.jsx @@ -6,7 +6,9 @@ import React, { useCallback, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { DragDropContext, Droppable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import { closePopup, usePopup } from '../../../lib/popup'; import selectors from '../../../selectors'; @@ -32,6 +34,7 @@ const Boards = React.memo(() => { }); const dispatch = useDispatch(); + const [t] = useTranslation(); const tabsWrapperRef = useRef(null); @@ -75,7 +78,9 @@ const Boards = React.memo(() => { {placeholder} {canAdd && ( - + + + )} ) : ( diff --git a/client/src/components/cards/Card/Card.jsx b/client/src/components/cards/Card/Card.jsx index c1c7c5c7..847e4f81 100755 --- a/client/src/components/cards/Card/Card.jsx +++ b/client/src/components/cards/Card/Card.jsx @@ -7,7 +7,9 @@ import React, { useCallback, useContext, useMemo, useRef, useState } from 'react import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Button, Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import { push } from '../../../lib/redux-router'; import { closePopup, usePopup } from '../../../lib/popup'; @@ -57,6 +59,7 @@ const Card = React.memo(({ id, isInline }) => { }); const dispatch = useDispatch(); + const [t] = useTranslation(); const [isEditNameOpened, setIsEditNameOpened] = useState(false); const [, , handleCardMouseEnter, handleCardMouseLeave] = useContext(BoardShortcutsContext); @@ -151,9 +154,11 @@ const Card = React.memo(({ id, isInline }) => { {canUseActions && ( - + + + )} diff --git a/client/src/components/cards/CardModal/CardModal.jsx b/client/src/components/cards/CardModal/CardModal.jsx index 4098e82d..32d3771e 100755 --- a/client/src/components/cards/CardModal/CardModal.jsx +++ b/client/src/components/cards/CardModal/CardModal.jsx @@ -6,7 +6,9 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import { push } from '../../../lib/redux-router'; import selectors from '../../../selectors'; @@ -45,6 +47,7 @@ const CardModal = React.memo(() => { }); const dispatch = useDispatch(); + const [t] = useTranslation(); const handleClose = useCallback(() => { dispatch(push(Paths.BOARDS.replace(':id', card.boardId))); @@ -102,9 +105,11 @@ const CardModal = React.memo(() => { onClose={handleClose} > {prevCardId && ( - + + + )} {canEdit ? ( diff --git a/client/src/components/cards/CardModal/CustomFieldGroups/Item.jsx b/client/src/components/cards/CardModal/CustomFieldGroups/Item.jsx index 23e37bb0..7e85ed0d 100644 --- a/client/src/components/cards/CardModal/CustomFieldGroups/Item.jsx +++ b/client/src/components/cards/CardModal/CustomFieldGroups/Item.jsx @@ -7,7 +7,9 @@ import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Button, Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../../lib/custom-ui'; import selectors from '../../../../selectors'; import { usePopupInClosableContext } from '../../../../hooks'; @@ -23,6 +25,7 @@ const Item = React.memo(({ id, dragHandleProps }) => { const selectListById = useMemo(() => selectors.makeSelectListById(), []); const customFieldGroup = useSelector((state) => selectCustomFieldGroupById(state, id)); + const [t] = useTranslation(); const canEdit = useSelector((state) => { if (customFieldGroup.boardId) { @@ -51,9 +54,11 @@ const Item = React.memo(({ id, dragHandleProps }) => {
{customFieldGroup.isPersisted && canEdit && ( - + + + )} {customFieldGroup.name} diff --git a/client/src/components/cards/CardModal/ProjectContent.jsx b/client/src/components/cards/CardModal/ProjectContent.jsx index 99f1f033..9acf5d42 100644 --- a/client/src/components/cards/CardModal/ProjectContent.jsx +++ b/client/src/components/cards/CardModal/ProjectContent.jsx @@ -9,6 +9,7 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Button, Checkbox, Grid, Icon } from 'semantic-ui-react'; import { useDidUpdate } from '../../../lib/hooks'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; @@ -361,12 +362,14 @@ const ProjectContent = React.memo(() => { onUserSelect={handleUserSelect} onUserDeselect={handleUserDeselect} > - + + + )}
@@ -401,12 +404,14 @@ const ProjectContent = React.memo(() => { onSelect={handleLabelSelect} onDeselect={handleLabelDeselect} > - + + + )} @@ -465,17 +470,19 @@ const ProjectContent = React.memo(() => { )}
{canEditStopwatch && ( - + + + )} )} @@ -507,9 +514,11 @@ const ProjectContent = React.memo(() => { /* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
- + + + {card.description}
) : ( @@ -554,14 +563,16 @@ const ProjectContent = React.memo(() => {
{t('common.list')}
{canUseLists ? ( - + + ) : ( diff --git a/client/src/components/cards/CardModal/StoryContent.jsx b/client/src/components/cards/CardModal/StoryContent.jsx index a7150e83..5e6b7b60 100644 --- a/client/src/components/cards/CardModal/StoryContent.jsx +++ b/client/src/components/cards/CardModal/StoryContent.jsx @@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next'; import { Gallery, Item as GalleryItem } from 'react-photoswipe-gallery'; import { Button, Grid, Icon } from 'semantic-ui-react'; import { useDidUpdate } from '../../../lib/hooks'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; @@ -383,12 +384,14 @@ const StoryContent = React.memo(() => { onSelect={handleLabelSelect} onDeselect={handleLabelDeselect} > - + + + )} @@ -419,9 +422,11 @@ const StoryContent = React.memo(() => { className={classNames(styles.descriptionText, styles.cursorPointer)} onClick={handleEditDescriptionClick} > - + + + {card.description} ) : ( @@ -477,14 +482,16 @@ const StoryContent = React.memo(() => {
{t('common.list')}
{canUseLists ? ( - + + ) : ( diff --git a/client/src/components/cards/CardModal/TaskLists/Item.jsx b/client/src/components/cards/CardModal/TaskLists/Item.jsx index a93be777..1aa69195 100644 --- a/client/src/components/cards/CardModal/TaskLists/Item.jsx +++ b/client/src/components/cards/CardModal/TaskLists/Item.jsx @@ -9,8 +9,10 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; import { Draggable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button, Icon } from 'semantic-ui-react'; import { useToggle } from '../../../../lib/hooks'; +import { Tooltip } from '../../../../lib/custom-ui'; import selectors from '../../../../selectors'; import { usePopupInClosableContext } from '../../../../hooks'; @@ -24,6 +26,7 @@ const Item = React.memo(({ id, index }) => { const selectTaskListById = useMemo(() => selectors.makeSelectTaskListById(), []); const taskList = useSelector((state) => selectTaskListById(state, id)); + const [t] = useTranslation(); const canEdit = useSelector((state) => { const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); @@ -67,22 +70,30 @@ const Item = React.memo(({ id, index }) => { {taskList.isPersisted && withActions && (
{taskList.hideCompletedTasks && ( - + + )} {canEdit && ( - + + + )}
diff --git a/client/src/components/common/AdministrationModal/UsersPane/ApiKeyStep.jsx b/client/src/components/common/AdministrationModal/UsersPane/ApiKeyStep.jsx index 3a3c039a..8f70514e 100644 --- a/client/src/components/common/AdministrationModal/UsersPane/ApiKeyStep.jsx +++ b/client/src/components/common/AdministrationModal/UsersPane/ApiKeyStep.jsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Button, Icon, Input, Message } from 'semantic-ui-react'; -import { Popup } from '../../../../lib/custom-ui'; +import { Popup, Tooltip } from '../../../../lib/custom-ui'; import selectors from '../../../../selectors'; import entryActions from '../../../../entry-actions'; @@ -115,9 +115,11 @@ const ApiKeyStep = React.memo(({ userId, onBack, onClose }) => { />
- + + +
) : ( diff --git a/client/src/components/common/AdministrationModal/UsersPane/Item.jsx b/client/src/components/common/AdministrationModal/UsersPane/Item.jsx index 9ce9642e..fbb59280 100755 --- a/client/src/components/common/AdministrationModal/UsersPane/Item.jsx +++ b/client/src/components/common/AdministrationModal/UsersPane/Item.jsx @@ -10,6 +10,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Button, Icon, Table } from 'semantic-ui-react'; import { useEventCallback } from '../../../../lib/hooks'; +import { Tooltip } from '../../../../lib/custom-ui'; import selectors from '../../../../selectors'; import entryActions from '../../../../entry-actions'; @@ -84,9 +85,11 @@ const Item = React.memo(({ id }) => { - + + + diff --git a/client/src/components/common/Header/Header.jsx b/client/src/components/common/Header/Header.jsx index df0c5253..e92af462 100755 --- a/client/src/components/common/Header/Header.jsx +++ b/client/src/components/common/Header/Header.jsx @@ -7,7 +7,9 @@ import React, { useCallback } from 'react'; import classNames from 'classnames'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router'; +import { useTranslation } from 'react-i18next'; import { Button, Icon, Menu } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import { usePopup } from '../../../lib/popup'; import selectors from '../../../selectors'; @@ -72,6 +74,7 @@ const Header = React.memo(() => { }, shallowEqual); const dispatch = useDispatch(); + const [t] = useTranslation(); const handleToggleFavoritesClick = useCallback(() => { dispatch(entryActions.toggleFavorites(!isFavoritesEnabled)); @@ -102,55 +105,69 @@ const Header = React.memo(() => { {project && ( - - - + + + + + {project.name} {canEditProject && ( - + + + )} )} {withFavoritesToggler && ( - - - + + + + )} {withEditModeToggler && ( - - - + + + + )} - - - {notificationIds.length > 0 && ( - {notificationIds.length} - )} - + + + + {notificationIds.length > 0 && ( + {notificationIds.length} + )} + + diff --git a/client/src/components/common/HomeActions/RightSide/RightSide.jsx b/client/src/components/common/HomeActions/RightSide/RightSide.jsx index e8954d37..3fa56956 100644 --- a/client/src/components/common/HomeActions/RightSide/RightSide.jsx +++ b/client/src/components/common/HomeActions/RightSide/RightSide.jsx @@ -6,7 +6,9 @@ import React, { useCallback } from 'react'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../../lib/custom-ui'; import { usePopup } from '../../../../lib/popup'; import selectors from '../../../../selectors'; @@ -17,12 +19,18 @@ import SelectOrderStep from './SelectOrderStep'; import styles from './RightSide.module.scss'; +const LABEL_BY_VIEW = { + [HomeViews.GRID_PROJECTS]: 'common.gridProjects', + [HomeViews.GROUPED_PROJECTS]: 'common.groupedProjects', +}; + const RightSide = React.memo(() => { const currentView = useSelector(selectors.selectHomeView); // TODO: rename? const currentOrder = useSelector(selectors.selectProjectsOrder); // TODO: rename? const isHiddenVisible = useSelector(selectors.selectIsHiddenProjectsVisible); const dispatch = useDispatch(); + const [t] = useTranslation(); const handleSelectViewClick = useCallback( ({ currentTarget: { value: view } }) => { @@ -47,34 +55,47 @@ const RightSide = React.memo(() => { return ( <>
- + +
- + + +
{[HomeViews.GRID_PROJECTS, HomeViews.GROUPED_PROJECTS].map((view) => ( - + + ))}
diff --git a/client/src/components/custom-field-groups/CustomFieldGroupStep/CustomField.jsx b/client/src/components/custom-field-groups/CustomFieldGroupStep/CustomField.jsx index f12c497a..67bc893a 100755 --- a/client/src/components/custom-field-groups/CustomFieldGroupStep/CustomField.jsx +++ b/client/src/components/custom-field-groups/CustomFieldGroupStep/CustomField.jsx @@ -8,7 +8,9 @@ import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { Draggable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button, Icon } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; @@ -18,6 +20,7 @@ const CustomField = React.memo(({ id, index, onEdit }) => { const selectCustomFieldById = useMemo(() => selectors.makeSelectCustomFieldById(), []); const customField = useSelector((state) => selectCustomFieldById(state, id)); + const [t] = useTranslation(); const handleEditClick = useCallback(() => { onEdit(id); @@ -36,14 +39,16 @@ const CustomField = React.memo(({ id, index, onEdit }) => { {customField.showOnFrontOfCard && } {customField.name} - + + + )} diff --git a/client/src/components/labels/LabelsStep/Item.jsx b/client/src/components/labels/LabelsStep/Item.jsx index 281cda06..8d757f48 100755 --- a/client/src/components/labels/LabelsStep/Item.jsx +++ b/client/src/components/labels/LabelsStep/Item.jsx @@ -11,7 +11,9 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { useSelector } from 'react-redux'; import { Draggable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import { BoardMembershipRoles } from '../../../constants/Enums'; @@ -23,6 +25,7 @@ const Item = React.memo(({ id, index, isActive, onSelect, onDeselect, onEdit }) const selectLabelById = useMemo(() => selectors.makeSelectLabelById(), []); const label = useSelector((state) => selectLabelById(state, id)); + const [t] = useTranslation(); const canEdit = useSelector((state) => { const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); @@ -63,14 +66,16 @@ const Item = React.memo(({ id, index, isActive, onSelect, onDeselect, onEdit }) {label.name} {canEdit && ( - + + + ) : ( canArchiveCards && ( - + + + ) ))} @@ -275,14 +280,16 @@ const List = React.memo(({ id, index }) => { {clipboard && canPasteCard && ( - + + + )} )} diff --git a/client/src/components/notification-services/NotificationServices/Item.jsx b/client/src/components/notification-services/NotificationServices/Item.jsx index fa8a7ec8..acb3cab9 100644 --- a/client/src/components/notification-services/NotificationServices/Item.jsx +++ b/client/src/components/notification-services/NotificationServices/Item.jsx @@ -6,8 +6,10 @@ import React, { useCallback, useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Button, Dropdown, Form, Icon, Input } from 'semantic-ui-react'; import { useDidUpdate, usePrevious, useToggle } from '../../../lib/hooks'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; @@ -31,6 +33,7 @@ const Item = React.memo(({ id }) => { const notificationService = useSelector((state) => selectNotificationServiceById(state, id)); const dispatch = useDispatch(); + const [t] = useTranslation(); const defaultData = useMemo( () => ({ @@ -183,24 +186,32 @@ const Item = React.memo(({ id }) => { onChange={handleFieldChange} onBlur={handleUrlBlur} /> - + + + - + + + ); diff --git a/client/src/components/notification-services/NotificationServices/NotificationServices.jsx b/client/src/components/notification-services/NotificationServices/NotificationServices.jsx index edd5657c..2f9b07ec 100644 --- a/client/src/components/notification-services/NotificationServices/NotificationServices.jsx +++ b/client/src/components/notification-services/NotificationServices/NotificationServices.jsx @@ -6,9 +6,10 @@ import React, { useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { Trans } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import { Button, Dropdown, Form, Icon, Input, Message } from 'semantic-ui-react'; import { useDidUpdate, useToggle } from '../../../lib/hooks'; +import { Tooltip } from '../../../lib/custom-ui'; import { useEscapeInterceptor, useForm, useNestedRef } from '../../../hooks'; import { NotificationServiceFormats } from '../../../constants/Enums'; @@ -22,6 +23,8 @@ const DEFAULT_DATA = { }; const NotificationServices = React.memo(({ ids, onCreate }) => { + const [t] = useTranslation(); + const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA); const [focusUrlFieldState, focusUrlField] = useToggle(); @@ -117,9 +120,11 @@ const NotificationServices = React.memo(({ ids, onCreate }) => { onChange={handleFieldChange} onBlur={handleUrlBlur} /> - + + + )} diff --git a/client/src/components/project-managers/ProjectManagers/ProjectManagers.jsx b/client/src/components/project-managers/ProjectManagers/ProjectManagers.jsx index b8eb8e90..a903d135 100644 --- a/client/src/components/project-managers/ProjectManagers/ProjectManagers.jsx +++ b/client/src/components/project-managers/ProjectManagers/ProjectManagers.jsx @@ -5,7 +5,9 @@ import React from 'react'; import { useSelector } from 'react-redux'; +import { useTranslation } from 'react-i18next'; import { Button } from 'semantic-ui-react'; +import { Tooltip } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import { usePopupInClosableContext } from '../../../hooks'; @@ -18,6 +20,7 @@ import styles from './ProjectManagers.module.scss'; const ProjectManagers = React.memo(() => { const projectManagers = useSelector(selectors.selectManagersForCurrentProject); + const [t] = useTranslation(); const canAdd = useSelector((state) => { const user = selectors.selectCurrentUser(state); @@ -47,7 +50,9 @@ const ProjectManagers = React.memo(() => { ))} {canAdd && ( - + + + )} diff --git a/client/src/components/task-lists/TaskList/Task/Task.jsx b/client/src/components/task-lists/TaskList/Task/Task.jsx index 104c414f..4ec0ad3e 100755 --- a/client/src/components/task-lists/TaskList/Task/Task.jsx +++ b/client/src/components/task-lists/TaskList/Task/Task.jsx @@ -10,8 +10,10 @@ import classNames from 'classnames'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router'; import { Draggable } from 'react-beautiful-dnd'; +import { useTranslation } from 'react-i18next'; import { Button, Checkbox, Icon } from 'semantic-ui-react'; import { useDidUpdate } from '../../../../lib/hooks'; +import { Tooltip } from '../../../../lib/custom-ui'; import selectors from '../../../../selectors'; import entryActions from '../../../../entry-actions'; @@ -60,6 +62,7 @@ const Task = React.memo(({ id, index }) => { }, shallowEqual); const dispatch = useDispatch(); + const [t] = useTranslation(); const [isEditNameOpened, setIsEditNameOpened] = useState(false); const [, , setIsClosableActive] = useContext(ClosableContext); @@ -203,16 +206,20 @@ const Task = React.memo(({ id, index }) => { className={styles.assigneeUserAvatar} /> ) : ( - + + + )} )} - + + + ) : ( diff --git a/client/src/hooks/use-closable-modal.jsx b/client/src/hooks/use-closable-modal.jsx index f165fecb..ab337cde 100644 --- a/client/src/hooks/use-closable-modal.jsx +++ b/client/src/hooks/use-closable-modal.jsx @@ -5,6 +5,7 @@ import React, { useCallback, useMemo } from 'react'; import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; import { Modal } from 'semantic-ui-react'; import useClosable from './use-closable'; @@ -22,6 +23,8 @@ export default (initialClosableValue) => { const ClosableModal = useMemo(() => { // eslint-disable-next-line no-shadow const ClosableModal = React.memo(({ closeIcon, onClose, ...props }) => { + const [t] = useTranslation(); + const handleClose = useCallback( (event) => { if (isClosableActiveRef.current) { @@ -41,16 +44,32 @@ export default (initialClosableValue) => { [closeIcon, onClose], ); + const semanticCloseIcon = + closeIcon === true + ? { + name: 'close', + 'aria-label': t('action.close'), + title: t('action.close'), + } + : closeIcon; + return ( {/* eslint-disable-next-line react/jsx-props-no-spreading */} - + ); }); ClosableModal.propTypes = { - closeIcon: PropTypes.bool, + closeIcon: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.shape({ + name: PropTypes.string, + 'aria-label': PropTypes.string, + title: PropTypes.string, + }), + ]), onClose: PropTypes.func, }; diff --git a/client/src/lib/custom-ui/components/Popup/PopupHeader.jsx b/client/src/lib/custom-ui/components/Popup/PopupHeader.jsx index 7790d955..b88bfc88 100755 --- a/client/src/lib/custom-ui/components/Popup/PopupHeader.jsx +++ b/client/src/lib/custom-ui/components/Popup/PopupHeader.jsx @@ -5,16 +5,26 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; import { Button, Popup as SemanticUIPopup } from 'semantic-ui-react'; +import Tooltip from '../Tooltip'; import styles from './PopupHeader.module.css'; -const PopupHeader = React.memo(({ children, onBack }) => ( - - {onBack &&