diff --git a/client/package-lock.json b/client/package-lock.json index ba590d32..19dbf347 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -49,7 +49,7 @@ "javascript-time-ago": "^2.5.11", "js-cookie": "^3.0.5", "jwt-decode": "^4.0.0", - "linkify-react": "^4.3.1", + "linkify-react": "^4.3.2", "linkifyjs": "^4.3.2", "lodash": "^4.17.21", "lowlight": "^3.3.0", @@ -11079,9 +11079,9 @@ } }, "node_modules/linkify-react": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.3.1.tgz", - "integrity": "sha512-w8ahBdCwF9C/doS4V3nE93QF1oyORmosvi8UEUbpHYws077eGzhkxUzJQcE2/SU5Q2K7SD80M4ybwwZGHErx5Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.3.2.tgz", + "integrity": "sha512-mi744h1hf+WDsr+paJgSBBgYNLMWNSHyM9V9LVUo03RidNGdw1VpI7Twnt+K3pEh3nIzB4xiiAgZxpd61ItKpQ==", "license": "MIT", "peerDependencies": { "linkifyjs": "^4.0.0", diff --git a/client/package.json b/client/package.json index a36321fb..36f0349f 100644 --- a/client/package.json +++ b/client/package.json @@ -120,7 +120,7 @@ "javascript-time-ago": "^2.5.11", "js-cookie": "^3.0.5", "jwt-decode": "^4.0.0", - "linkify-react": "^4.3.1", + "linkify-react": "^4.3.2", "linkifyjs": "^4.3.2", "lodash": "^4.17.21", "lowlight": "^3.3.0", diff --git a/client/src/components/cards/CardModal/CardModal.jsx b/client/src/components/cards/CardModal/CardModal.jsx index 3d86c94c..4098e82d 100755 --- a/client/src/components/cards/CardModal/CardModal.jsx +++ b/client/src/components/cards/CardModal/CardModal.jsx @@ -6,6 +6,7 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; +import { Icon } from 'semantic-ui-react'; import { push } from '../../../lib/redux-router'; import selectors from '../../../selectors'; @@ -30,6 +31,7 @@ const CardModal = React.memo(() => { const selectListById = useMemo(() => selectors.makeSelectListById(), []); const card = useSelector(selectors.selectCurrentCard); + const prevCardId = useSelector(selectors.selectPrevCardId); const canEdit = useSelector((state) => { const list = selectListById(state, card.listId); @@ -48,6 +50,10 @@ const CardModal = React.memo(() => { dispatch(push(Paths.BOARDS.replace(':id', card.boardId))); }, [card.boardId, dispatch]); + const handlePrevClick = useCallback(() => { + dispatch(push(Paths.CARDS.replace(':id', prevCardId))); + }, [prevCardId, dispatch]); + const [ClosableModal, isClosableActiveRef] = useClosableModal(); useEffect(() => { @@ -95,6 +101,11 @@ const CardModal = React.memo(() => { className={classNames(styles.wrapper, card.type === CardTypes.STORY && styles.wrapperStory)} onClose={handleClose} > + {prevCardId && ( + + )} {canEdit ? ( diff --git a/client/src/components/cards/CardModal/CardModal.module.scss b/client/src/components/cards/CardModal/CardModal.module.scss index 88988448..789dc5b0 100644 --- a/client/src/components/cards/CardModal/CardModal.module.scss +++ b/client/src/components/cards/CardModal/CardModal.module.scss @@ -9,6 +9,34 @@ width: 95%; } + .prevButton { + background: rgba(255, 255, 255, 0.036); + border: none; + border-radius: 4px; + cursor: pointer; + display: flex; + height: 100%; + justify-content: center; + left: -120px; + padding: 18px 0; + position: absolute; + width: 100px; + + &:hover { + background: rgba(255, 255, 255, 0.072); + + .prevkButtonIcon { + color: rgba(255, 255, 255, 0.72); + } + } + } + + .prevButtonIcon { + color: rgba(255, 255, 255, 0.36); + position: sticky; + top: 5px; + } + .wrapper { margin: 2rem auto; width: 880px; @@ -24,5 +52,13 @@ @media (width < 1026px) { @include smallScreen; } + + .prevButton { + padding: 20px 0; + } + + .prevButtonIcon { + top: 7px; + } } } diff --git a/client/src/reducers/core.js b/client/src/reducers/core.js index ff71188c..aab57e4b 100755 --- a/client/src/reducers/core.js +++ b/client/src/reducers/core.js @@ -16,7 +16,9 @@ const initialState = { isEditModeEnabled: false, modal: null, boardId: null, + cardId: null, recentCardId: null, + prevCardIds: [], homeView: HomeViews.GROUPED_PROJECTS, projectsSearch: '', projectsOrder: ProjectOrders.BY_DEFAULT, @@ -37,6 +39,7 @@ export default (state = initialState, { type, payload }) => { ...state, isContentFetching: false, boardId: payload.currentBoardId, + cardId: payload.currentCardId, }; if (payload.currentCardId) { @@ -45,6 +48,17 @@ export default (state = initialState, { type, payload }) => { nextState.recentCardId = null; } + if (payload.currentCardId) { + if (state.cardId) { + nextState.prevCardIds = + payload.currentCardId === nextState.prevCardIds.at(-1) + ? [...nextState.prevCardIds.slice(0, -1)] + : [...nextState.prevCardIds, state.cardId]; + } + } else if (nextState.prevCardIds.length > 0) { + nextState.prevCardIds = []; + } + if (payload.isEditModeEnabled !== undefined) { nextState.isEditModeEnabled = payload.isEditModeEnabled; } diff --git a/client/src/selectors/core.js b/client/src/selectors/core.js index d7a37c1e..39189a25 100644 --- a/client/src/selectors/core.js +++ b/client/src/selectors/core.js @@ -13,6 +13,8 @@ export const selectIsEditModeEnabled = ({ core: { isEditModeEnabled } }) => isEd export const selectRecentCardId = ({ core: { recentCardId } }) => recentCardId; +export const selectPrevCardId = ({ core: { prevCardIds } }) => prevCardIds.at(-1); + export const selectHomeView = ({ core: { homeView } }) => homeView; export const selectProjectsSearch = ({ core: { projectsSearch } }) => projectsSearch; @@ -28,6 +30,7 @@ export default { selectIsFavoritesEnabled, selectIsEditModeEnabled, selectRecentCardId, + selectPrevCardId, selectHomeView, selectProjectsSearch, selectProjectsOrder,