feat: client implementation of list sorting

pull/717/head
Samuel 2 years ago
parent 03825c3bed
commit 1f62f20350

@ -89,6 +89,36 @@ const handleListDelete = (list) => ({
}, },
}); });
const sortList = (id, data) => ({
type: ActionTypes.LIST_SORT,
payload: {
id,
data,
},
});
sortList.success = (list) => ({
type: ActionTypes.LIST_SORT__SUCCESS,
payload: {
list,
},
});
sortList.failure = (id, error) => ({
type: ActionTypes.LIST_SORT__FAILURE,
payload: {
id,
error,
},
});
const handleListSort = (list) => ({
type: ActionTypes.LIST_SORT_HANDLE,
payload: {
list,
},
});
export default { export default {
createList, createList,
handleListCreate, handleListCreate,
@ -96,4 +126,6 @@ export default {
handleListUpdate, handleListUpdate,
deleteList, deleteList,
handleListDelete, handleListDelete,
sortList,
handleListSort
}; };

@ -7,10 +7,13 @@ const createList = (boardId, data, headers) =>
const updateList = (id, data, headers) => socket.patch(`/lists/${id}`, 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);
const deleteList = (id, headers) => socket.delete(`/lists/${id}`, undefined, headers); const deleteList = (id, headers) => socket.delete(`/lists/${id}`, undefined, headers);
export default { export default {
createList, createList,
updateList, updateList,
sortList,
deleteList, deleteList,
}; };

@ -8,12 +8,14 @@ import { useSteps } from '../../hooks';
import DeleteStep from '../DeleteStep'; import DeleteStep from '../DeleteStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
import SortStep from "../SortStep";
const StepTypes = { const StepTypes = {
DELETE: 'DELETE', DELETE: 'DELETE',
SORT: 'SORT',
}; };
const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => { const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onSort, onClose }) => {
const [t] = useTranslation(); const [t] = useTranslation();
const [step, openStep, handleBack] = useSteps(); const [step, openStep, handleBack] = useSteps();
@ -31,7 +33,13 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) =>
openStep(StepTypes.DELETE); openStep(StepTypes.DELETE);
}, [openStep]); }, [openStep]);
if (step && step.type === StepTypes.DELETE) { const handleSortClick = useCallback(() => {
openStep(StepTypes.SORT);
}, [openStep]);
if (step && step.type) {
switch (step.type){
case StepTypes.DELETE:
return ( return (
<DeleteStep <DeleteStep
title="common.deleteList" title="common.deleteList"
@ -41,6 +49,16 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) =>
onBack={handleBack} onBack={handleBack}
/> />
); );
case StepTypes.SORT:
return (
<SortStep
title="common.sortList"
onSort={onSort}
onBack={handleBack}
/>
);
default:
}
} }
return ( return (
@ -52,6 +70,11 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) =>
</Popup.Header> </Popup.Header>
<Popup.Content> <Popup.Content>
<Menu secondary vertical className={styles.menu}> <Menu secondary vertical className={styles.menu}>
<Menu.Item className={styles.menuItem} onClick={handleSortClick}>
{t('action.sort', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleEditNameClick}> <Menu.Item className={styles.menuItem} onClick={handleEditNameClick}>
{t('action.editTitle', { {t('action.editTitle', {
context: 'title', context: 'title',
@ -77,6 +100,7 @@ ActionsStep.propTypes = {
onNameEdit: PropTypes.func.isRequired, onNameEdit: PropTypes.func.isRequired,
onCardAdd: PropTypes.func.isRequired, onCardAdd: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired,
onSort: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
}; };

@ -16,7 +16,7 @@ import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-ic
import styles from './List.module.scss'; import styles from './List.module.scss';
const List = React.memo( 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 [t] = useTranslation();
const [isAddCardOpened, setIsAddCardOpened] = useState(false); const [isAddCardOpened, setIsAddCardOpened] = useState(false);
@ -114,6 +114,7 @@ const List = React.memo(
onNameEdit={handleNameEdit} onNameEdit={handleNameEdit}
onCardAdd={handleCardAdd} onCardAdd={handleCardAdd}
onDelete={onDelete} onDelete={onDelete}
onSort={onSort}
> >
<Button className={classNames(styles.headerButton, styles.target)}> <Button className={classNames(styles.headerButton, styles.target)}>
<Icon fitted name="pencil" size="small" /> <Icon fitted name="pencil" size="small" />
@ -160,6 +161,7 @@ List.propTypes = {
canEdit: PropTypes.bool.isRequired, canEdit: PropTypes.bool.isRequired,
onUpdate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired,
onSort: PropTypes.func.isRequired,
onCardCreate: PropTypes.func.isRequired, onCardCreate: PropTypes.func.isRequired,
}; };

@ -0,0 +1,59 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import {Button, Menu} from 'semantic-ui-react';
import { Popup } from '../../lib/custom-ui';
import styles from './SortStep.module.scss';
const SortStep = React.memo(({ title, onSort, onBack }) => {
const [t] = useTranslation();
const handeClick = (sortType) => onSort({sortType})
return (
<>
<Popup.Header onBack={onBack}>
{t(title, {
context: 'title',
})}
</Popup.Header>
<Popup.Content>
<Menu secondary vertical className={styles.menu}>
<Menu.Item className={styles.menuItem} onClick={() => handeClick('createdat_asc')}>
{t('action.sort.createdFirst', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={() => handeClick('createdat_desc')}>
{t('action.sort.createdLast', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={() => handeClick('name_asc')}>
{t('action.sort.name', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={() => handeClick('duedate_asc')}>
{t('action.sort.due', {
context: 'title',
})}
</Menu.Item>
</Menu>
</Popup.Content>
</>
);
});
SortStep.propTypes = {
title: PropTypes.string.isRequired,
onSort: PropTypes.func.isRequired,
onBack: PropTypes.func,
};
SortStep.defaultProps = {
onBack: undefined,
};
export default SortStep;

@ -0,0 +1,3 @@
import SortStep from './SortStep';
export default SortStep;

@ -173,6 +173,10 @@ export default {
LIST_UPDATE__SUCCESS: 'LIST_UPDATE__SUCCESS', LIST_UPDATE__SUCCESS: 'LIST_UPDATE__SUCCESS',
LIST_UPDATE__FAILURE: 'LIST_UPDATE__FAILURE', LIST_UPDATE__FAILURE: 'LIST_UPDATE__FAILURE',
LIST_UPDATE_HANDLE: 'LIST_UPDATE_HANDLE', LIST_UPDATE_HANDLE: 'LIST_UPDATE_HANDLE',
LIST_SORT: 'LIST_SORT',
LIST_SORT__SUCCESS: 'LIST_SORT__SUCCESS',
LIST_SORT__FAILURE: 'LIST_SORT__FAILURE',
LIST_SORT_HANDLE: 'LIST_SORT_HANDLE',
LIST_DELETE: 'LIST_DELETE', LIST_DELETE: 'LIST_DELETE',
LIST_DELETE__SUCCESS: 'LIST_DELETE__SUCCESS', LIST_DELETE__SUCCESS: 'LIST_DELETE__SUCCESS',
LIST_DELETE__FAILURE: 'LIST_DELETE__FAILURE', LIST_DELETE__FAILURE: 'LIST_DELETE__FAILURE',

@ -120,6 +120,8 @@ export default {
LIST_MOVE: `${PREFIX}/LIST_MOVE`, LIST_MOVE: `${PREFIX}/LIST_MOVE`,
LIST_DELETE: `${PREFIX}/LIST_DELETE`, LIST_DELETE: `${PREFIX}/LIST_DELETE`,
LIST_DELETE_HANDLE: `${PREFIX}/LIST_DELETE_HANDLE`, LIST_DELETE_HANDLE: `${PREFIX}/LIST_DELETE_HANDLE`,
LIST_SORT: `${PREFIX}/LIST_SORT`,
LIST_SORT_HANDLE: `${PREFIX}/LIST_SORT_HANDLE`,
/* Cards */ /* Cards */

@ -34,6 +34,7 @@ const mapDispatchToProps = (dispatch, { id }) =>
{ {
onUpdate: (data) => entryActions.updateList(id, data), onUpdate: (data) => entryActions.updateList(id, data),
onDelete: () => entryActions.deleteList(id), onDelete: () => entryActions.deleteList(id),
onSort: (data) => entryActions.sortList(id, data),
onCardCreate: (data, autoOpen) => entryActions.createCard(id, data, autoOpen), onCardCreate: (data, autoOpen) => entryActions.createCard(id, data, autoOpen),
}, },
dispatch, dispatch,

@ -51,6 +51,23 @@ const handleListDelete = (list) => ({
}, },
}); });
const sortList = (id, data) => {
return ({
type: EntryActionTypes.LIST_SORT,
payload: {
id,
data
},
})};
const handleListSort = (list) => ({
type: EntryActionTypes.LIST_SORT_HANDLE,
payload: {
list,
},
});
export default { export default {
createListInCurrentBoard, createListInCurrentBoard,
handleListCreate, handleListCreate,
@ -59,4 +76,6 @@ export default {
moveList, moveList,
deleteList, deleteList,
handleListDelete, handleListDelete,
sortList,
handleListSort,
}; };

@ -66,6 +66,9 @@ export default class extends BaseModel {
List.withId(payload.id).deleteWithRelated(); List.withId(payload.id).deleteWithRelated();
break; break;
// Possible improved flow for updating
// case ActionTypes.LIST_SORT__SUCCESS:
// case ActionTypes.LIST_SORT_HANDLE:
case ActionTypes.LIST_DELETE__SUCCESS: case ActionTypes.LIST_DELETE__SUCCESS:
case ActionTypes.LIST_DELETE_HANDLE: { case ActionTypes.LIST_DELETE_HANDLE: {
const listModel = List.withId(payload.list.id); const listModel = List.withId(payload.list.id);

@ -61,6 +61,24 @@ export function* handleListUpdate(list) {
yield put(actions.handleListUpdate(list)); yield put(actions.handleListUpdate(list));
} }
export function* sortList(id, data) {
yield put(actions.sortList(id, data));
let list;
try {
({ item: list } = yield call(request, api.sortList, id, data));
} catch (error) {
yield put(actions.sortList.failure(id, error));
return;
}
yield put(actions.sortList.success(list));
}
export function* handleListSort(list) {
yield put(actions.handleListSort(list));
}
export function* moveList(id, index) { export function* moveList(id, index) {
const { boardId } = yield select(selectors.selectListById, id); const { boardId } = yield select(selectors.selectListById, id);
const position = yield select(selectors.selectNextListPosition, boardId, index, id); const position = yield select(selectors.selectNextListPosition, boardId, index, id);
@ -94,6 +112,8 @@ export default {
handleListCreate, handleListCreate,
updateList, updateList,
handleListUpdate, handleListUpdate,
sortList,
handleListSort,
moveList, moveList,
deleteList, deleteList,
handleListDelete, handleListDelete,

@ -17,6 +17,12 @@ export default function* listsWatchers() {
takeEvery(EntryActionTypes.LIST_UPDATE_HANDLE, ({ payload: { list } }) => takeEvery(EntryActionTypes.LIST_UPDATE_HANDLE, ({ payload: { list } }) =>
services.handleListUpdate(list), services.handleListUpdate(list),
), ),
takeEvery(EntryActionTypes.LIST_SORT, ({ payload: { id, data } }) =>
services.sortList(id, data),
),
takeEvery(EntryActionTypes.LIST_SORT_HANDLE, ({ payload: { list } }) =>
services.handleListSort(list),
),
takeEvery(EntryActionTypes.LIST_MOVE, ({ payload: { id, index } }) => takeEvery(EntryActionTypes.LIST_MOVE, ({ payload: { id, index } }) =>
services.moveList(id, index), services.moveList(id, index),
), ),

Loading…
Cancel
Save