From 712567ac572e7087c19fb8c2dce4ebc8a0e52cd0 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Thu, 30 Apr 2020 05:27:46 +0500 Subject: [PATCH] Change user size on card, save card description on click outside, prevent list deletion if any filter is active --- client/src/components/Board/Filter.jsx | 2 +- .../src/components/Boards/Boards.module.css | 2 +- client/src/components/Card/Card.jsx | 2 +- .../components/CardModal/EditDescription.jsx | 18 ++++++--------- client/src/components/List/ActionsPopup.jsx | 18 ++++++++++----- client/src/components/List/List.jsx | 6 ++++- client/src/components/User/User.jsx | 16 +++++++------- client/src/containers/ListContainer.js | 16 ++++++++++++-- client/src/sagas/app/services/socket.js | 6 ++--- client/src/selectors/boolean.js | 22 +++++++++++++++++-- server/db/init.js | 4 ++-- 11 files changed, 74 insertions(+), 38 deletions(-) diff --git a/client/src/components/Board/Filter.jsx b/client/src/components/Board/Filter.jsx index 0e3ec547..c5bc5f28 100644 --- a/client/src/components/Board/Filter.jsx +++ b/client/src/components/Board/Filter.jsx @@ -61,7 +61,7 @@ const Filter = React.memo( handleUserRemoveClick(user.id)} /> diff --git a/client/src/components/Boards/Boards.module.css b/client/src/components/Boards/Boards.module.css index cc177a29..122cdc95 100644 --- a/client/src/components/Boards/Boards.module.css +++ b/client/src/components/Boards/Boards.module.css @@ -73,7 +73,7 @@ .tab { border-radius: 3px 3px 0 0; - min-width: 160px; + min-width: 100px; position: relative; transition: all 0.1s ease; } diff --git a/client/src/components/Card/Card.jsx b/client/src/components/Card/Card.jsx index f6516fc9..f4b8b961 100755 --- a/client/src/components/Card/Card.jsx +++ b/client/src/components/Card/Card.jsx @@ -112,7 +112,7 @@ const Card = React.memo( key={user.id} className={classNames(styles.attachment, styles.attachmentRight)} > - + ))} diff --git a/client/src/components/CardModal/EditDescription.jsx b/client/src/components/CardModal/EditDescription.jsx index f3475f9b..c833421c 100755 --- a/client/src/components/CardModal/EditDescription.jsx +++ b/client/src/components/CardModal/EditDescription.jsx @@ -21,19 +21,15 @@ const EditDescription = React.forwardRef(({ children, defaultValue, onUpdate }, }, [defaultValue, setValue]); const close = useCallback(() => { - setIsOpened(false); - setValue(null); - }, [setValue]); - - const submit = useCallback(() => { const cleanValue = value.trim() || null; if (cleanValue !== defaultValue) { onUpdate(cleanValue); } - close(); - }, [defaultValue, onUpdate, value, close]); + setIsOpened(false); + setValue(null); + }, [defaultValue, onUpdate, value, setValue]); useImperativeHandle( ref, @@ -53,10 +49,10 @@ const EditDescription = React.forwardRef(({ children, defaultValue, onUpdate }, const handleFieldKeyDown = useCallback( (event) => { if (event.ctrlKey && event.key === 'Enter') { - submit(); + close(); } }, - [submit], + [close], ); const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( @@ -65,8 +61,8 @@ const EditDescription = React.forwardRef(({ children, defaultValue, onUpdate }, ); const handleSubmit = useCallback(() => { - submit(); - }, [submit]); + close(); + }, [close]); useEffect(() => { if (isOpened) { diff --git a/client/src/components/List/ActionsPopup.jsx b/client/src/components/List/ActionsPopup.jsx index 75e0bd12..b1f40921 100755 --- a/client/src/components/List/ActionsPopup.jsx +++ b/client/src/components/List/ActionsPopup.jsx @@ -65,11 +65,13 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => context: 'title', })} - - {t('action.deleteList', { - context: 'title', - })} - + {onDelete && ( + + {t('action.deleteList', { + context: 'title', + })} + + )} @@ -79,8 +81,12 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => ActionsStep.propTypes = { onNameEdit: PropTypes.func.isRequired, onCardAdd: PropTypes.func.isRequired, - onDelete: PropTypes.func.isRequired, + onDelete: PropTypes.func, onClose: PropTypes.func.isRequired, }; +ActionsStep.defaultProps = { + onDelete: undefined, +}; + export default withPopup(ActionsStep); diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index a1091e83..0eac9ce6 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -114,8 +114,12 @@ List.propTypes = { isPersisted: PropTypes.bool.isRequired, cardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types onUpdate: PropTypes.func.isRequired, - onDelete: PropTypes.func.isRequired, + onDelete: PropTypes.func, onCardCreate: PropTypes.func.isRequired, }; +List.defaultProps = { + onDelete: undefined, +}; + export default List; diff --git a/client/src/components/User/User.jsx b/client/src/components/User/User.jsx index e41a3a35..183479dd 100755 --- a/client/src/components/User/User.jsx +++ b/client/src/components/User/User.jsx @@ -16,20 +16,20 @@ const SIZES = { // TODO: move to styles const STYLES = { tiny: { - fontSize: '10px', - fontWeight: '400', - height: '20px', - padding: '5.5px 0px 4.5px', - width: '20px', - }, - small: { fontSize: '12px', fontWeight: '400', height: '24px', lineHeight: '20px', - padding: '2px 0px', + padding: '2px 0', width: '24px', }, + small: { + fontSize: '12px', + fontWeight: '400', + height: '28px', + padding: '8px 0', + width: '28px', + }, medium: { fontSize: '14px', fontWeight: '500', diff --git a/client/src/containers/ListContainer.js b/client/src/containers/ListContainer.js index a8d5071f..fcf26d80 100755 --- a/client/src/containers/ListContainer.js +++ b/client/src/containers/ListContainer.js @@ -1,7 +1,12 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import omit from 'lodash/omit'; -import { makeCardIdsByListIdSelector, makeListByIdSelector } from '../selectors'; +import { + isAnyFilterActiveForCurrentBoardSelector, + makeCardIdsByListIdSelector, + makeListByIdSelector, +} from '../selectors'; import { createCard, deleteList, updateList } from '../actions/entry'; import List from '../components/List'; @@ -12,6 +17,7 @@ const makeMapStateToProps = () => { return (state, { id, index }) => { const { name, isPersisted } = listByIdSelector(state, id); const cardIds = cardIdsByListIdSelector(state, id); + const isAnyFilterActive = isAnyFilterActiveForCurrentBoardSelector(state); return { id, @@ -19,6 +25,7 @@ const makeMapStateToProps = () => { name, isPersisted, cardIds, + isDeletable: !isAnyFilterActive, }; }; }; @@ -33,4 +40,9 @@ const mapDispatchToProps = (dispatch, { id }) => dispatch, ); -export default connect(makeMapStateToProps, mapDispatchToProps)(List); +const mergeProps = (stateProps, dispatchProps) => ({ + ...omit(stateProps, 'isDeletable'), + ...(stateProps.isDeletable ? dispatchProps : omit(dispatchProps, 'onDelete')), +}); + +export default connect(makeMapStateToProps, mapDispatchToProps, mergeProps)(List); diff --git a/client/src/sagas/app/services/socket.js b/client/src/sagas/app/services/socket.js index b770d966..a60cffed 100644 --- a/client/src/sagas/app/services/socket.js +++ b/client/src/sagas/app/services/socket.js @@ -5,10 +5,10 @@ import { logoutService } from './login'; import { closeModalService } from './modal'; import { deleteNotificationsRequest, fetchUsersRequest } from '../requests'; import { - attachmentWithIdExistsSelector, currentModalSelector, currentUserIdSelector, currentUserSelector, + isAttachmentWithIdExistsSelector, pathSelector, } from '../../../selectors'; import { @@ -210,9 +210,9 @@ export function* deleteTaskReceivedService(task) { } export function* createAttachmentReceivedService(attachment, requestId) { - const exists = yield select(attachmentWithIdExistsSelector, requestId); + const isExists = yield select(isAttachmentWithIdExistsSelector, requestId); - if (!exists) { + if (!isExists) { yield put(createAttachmentReceived(attachment)); } } diff --git a/client/src/selectors/boolean.js b/client/src/selectors/boolean.js index 469a545a..488ef1ae 100644 --- a/client/src/selectors/boolean.js +++ b/client/src/selectors/boolean.js @@ -1,9 +1,27 @@ import { createSelector } from 'redux-orm'; import orm from '../orm'; +import { pathSelector } from './path'; -// eslint-disable-next-line import/prefer-default-export -export const attachmentWithIdExistsSelector = () => +export const isAnyFilterActiveForCurrentBoardSelector = createSelector( + orm, + (state) => pathSelector(state).boardId, + ({ Board }, id) => { + if (!id) { + return false; + } + + const boardModel = Board.withId(id); + + if (!boardModel) { + return false; + } + + return boardModel.filterUsers.exists() || boardModel.filterLabels.exists(); + }, +); + +export const isAttachmentWithIdExistsSelector = () => createSelector( orm, (_, id) => id, diff --git a/server/db/init.js b/server/db/init.js index 2dc930ac..053020f5 100644 --- a/server/db/init.js +++ b/server/db/init.js @@ -4,9 +4,9 @@ const knex = require('knex')(config); // eslint-disable-line import/order (async () => { try { - const exists = await knex.schema.hasTable(config.migrations.tableName); + const isExists = await knex.schema.hasTable(config.migrations.tableName); - if (!exists) { + if (!isExists) { await knex.migrate.latest(); await knex.seed.run(); }