From 934dcdf39bd210949b130fb43d64db130453c80a Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 22 Apr 2024 21:56:07 +0200 Subject: [PATCH] feat: Sort cards within list (#717) Closes #390 --- client/src/actions/lists.js | 34 +++++++++ client/src/api/lists.js | 24 +++++++ client/src/components/List/ActionsStep.jsx | 51 +++++++++++--- client/src/components/List/List.jsx | 15 +++- .../components/ListSortStep/ListSortStep.jsx | 61 ++++++++++++++++ .../ListSortStep/ListSortStep.module.scss | 11 +++ client/src/components/ListSortStep/index.js | 3 + client/src/constants/ActionTypes.js | 4 ++ client/src/constants/EntryActionTypes.js | 2 + client/src/constants/Enums.js | 7 ++ client/src/containers/ListContainer.js | 1 + client/src/entry-actions/lists.js | 20 ++++++ client/src/locales/en/core.js | 5 ++ client/src/models/Card.js | 14 ++-- client/src/models/List.js | 2 + client/src/sagas/core/services/lists.js | 26 +++++++ client/src/sagas/core/watchers/lists.js | 6 ++ client/src/sagas/core/watchers/socket.js | 6 ++ server/api/controllers/lists/sort.js | 65 +++++++++++++++++ server/api/helpers/lists/sort-one.js | 70 +++++++++++++++++++ server/api/models/List.js | 9 +++ server/config/routes.js | 1 + 22 files changed, 419 insertions(+), 18 deletions(-) create mode 100644 client/src/components/ListSortStep/ListSortStep.jsx create mode 100644 client/src/components/ListSortStep/ListSortStep.module.scss create mode 100644 client/src/components/ListSortStep/index.js create mode 100644 server/api/controllers/lists/sort.js create mode 100644 server/api/helpers/lists/sort-one.js diff --git a/client/src/actions/lists.js b/client/src/actions/lists.js index 59f944f4..4f85864c 100644 --- a/client/src/actions/lists.js +++ b/client/src/actions/lists.js @@ -60,6 +60,38 @@ const handleListUpdate = (list) => ({ }, }); +const sortList = (id, data) => ({ + type: ActionTypes.LIST_SORT, + payload: { + id, + data, + }, +}); + +sortList.success = (list, cards) => ({ + type: ActionTypes.LIST_SORT__SUCCESS, + payload: { + list, + cards, + }, +}); + +sortList.failure = (id, error) => ({ + type: ActionTypes.LIST_SORT__FAILURE, + payload: { + id, + error, + }, +}); + +const handleListSort = (list, cards) => ({ + type: ActionTypes.LIST_SORT_HANDLE, + payload: { + list, + cards, + }, +}); + const deleteList = (id) => ({ type: ActionTypes.LIST_DELETE, payload: { @@ -94,6 +126,8 @@ export default { handleListCreate, updateList, handleListUpdate, + sortList, + handleListSort, deleteList, handleListDelete, }; diff --git a/client/src/api/lists.js b/client/src/api/lists.js index 6c1ee6a2..2ed11c59 100755 --- a/client/src/api/lists.js +++ b/client/src/api/lists.js @@ -1,4 +1,5 @@ import socket from './socket'; +import { transformCard } from './cards'; /* Actions */ @@ -7,10 +8,33 @@ const createList = (boardId, data, headers) => const updateList = (id, data, headers) => socket.patch(`/lists/${id}`, data, headers); +const sortList = (id, data, headers) => + socket.post(`/lists/${id}/sort`, data, headers).then((body) => ({ + ...body, + included: { + ...body.included, + cards: body.included.cards.map(transformCard), + }, + })); + const deleteList = (id, headers) => socket.delete(`/lists/${id}`, undefined, headers); +/* Event handlers */ + +const makeHandleListSort = (next) => (body) => { + next({ + ...body, + included: { + ...body.included, + cards: body.included.cards.map(transformCard), + }, + }); +}; + export default { createList, updateList, + sortList, deleteList, + makeHandleListSort, }; diff --git a/client/src/components/List/ActionsStep.jsx b/client/src/components/List/ActionsStep.jsx index 1e94d5a7..bc04826c 100755 --- a/client/src/components/List/ActionsStep.jsx +++ b/client/src/components/List/ActionsStep.jsx @@ -5,15 +5,17 @@ import { Menu } from 'semantic-ui-react'; import { Popup } from '../../lib/custom-ui'; import { useSteps } from '../../hooks'; +import ListSortStep from '../ListSortStep'; import DeleteStep from '../DeleteStep'; import styles from './ActionsStep.module.scss'; const StepTypes = { DELETE: 'DELETE', + SORT: 'SORT', }; -const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => { +const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onSort, onDelete, onClose }) => { const [t] = useTranslation(); const [step, openStep, handleBack] = useSteps(); @@ -27,20 +29,41 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => onClose(); }, [onCardAdd, onClose]); + const handleSortClick = useCallback(() => { + openStep(StepTypes.SORT); + }, [openStep]); + const handleDeleteClick = useCallback(() => { openStep(StepTypes.DELETE); }, [openStep]); - if (step && step.type === StepTypes.DELETE) { - return ( - - ); + const handleSortTypeSelect = useCallback( + (type) => { + onSort({ + type, + }); + + onClose(); + }, + [onSort, onClose], + ); + + if (step && step.type) { + switch (step.type) { + case StepTypes.SORT: + return ; + case StepTypes.DELETE: + return ( + + ); + default: + } } return ( @@ -62,6 +85,11 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => context: 'title', })} + + {t('action.sortList', { + context: 'title', + })} + {t('action.deleteList', { context: 'title', @@ -77,6 +105,7 @@ ActionsStep.propTypes = { onNameEdit: PropTypes.func.isRequired, onCardAdd: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, + onSort: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, }; diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index f09116c8..25c85e58 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -16,7 +16,18 @@ import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-ic import styles from './List.module.scss'; const List = React.memo( - ({ id, index, name, isPersisted, cardIds, canEdit, onUpdate, onDelete, onCardCreate }) => { + ({ + id, + index, + name, + isPersisted, + cardIds, + canEdit, + onUpdate, + onDelete, + onSort, + onCardCreate, + }) => { const [t] = useTranslation(); const [isAddCardOpened, setIsAddCardOpened] = useState(false); @@ -114,6 +125,7 @@ const List = React.memo( onNameEdit={handleNameEdit} onCardAdd={handleCardAdd} onDelete={onDelete} + onSort={onSort} >