diff --git a/backend/models/Route.js b/backend/models/Route.js index 8bef460..9be11cf 100644 --- a/backend/models/Route.js +++ b/backend/models/Route.js @@ -13,6 +13,7 @@ const RouteSchema = new Schema( owner: { type: Schema.Types.ObjectId, ref: 'User' }, distance: { type: Number, default: 0 }, is_public: { type: Boolean, default: false }, + is_deleted: { type: Boolean, default: false }, created_at: { type: Date, default: Date.now() }, updated_at: { type: Date, default: Date.now() }, logo: { type: String, default: 'DEFAULT' }, diff --git a/backend/routes/route/drop.js b/backend/routes/route/drop.js index d875361..ae51e06 100644 --- a/backend/routes/route/drop.js +++ b/backend/routes/route/drop.js @@ -12,7 +12,7 @@ module.exports = async (req, res) => { if (!exists) return res.send({ success: false, mode: 'not_exists' }); if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'not_yours' }); - exists.delete(); + await exists.set({ is_deleted: true }).save(); return res.send({ success: true, address }); }; diff --git a/backend/routes/route/get.js b/backend/routes/route/get.js index fc14681..7421a86 100644 --- a/backend/routes/route/get.js +++ b/backend/routes/route/get.js @@ -6,7 +6,7 @@ module.exports = async (req, res) => { if (!name) return res.send({ success: false, mode: 'not_found_1' }); - const exists = await Route.findOne({ _id: name }).populate('owner', '_id'); + const exists = await Route.findOne({ _id: name, is_deleted: false }).populate('owner', '_id'); if (!exists) return res.send({ success: false, mode: 'not_found_2' }); const data = exists.toObject(); diff --git a/backend/routes/route/list.js b/backend/routes/route/list.js index 0a4f880..12f559e 100644 --- a/backend/routes/route/list.js +++ b/backend/routes/route/list.js @@ -9,7 +9,7 @@ module.exports = async (req, res) => { const user = await User.findOne({ _id: id, token }); - let criteria = {}; + let criteria = { is_deleted: false }; if (title) { criteria = { @@ -32,16 +32,14 @@ module.exports = async (req, res) => { { ...criteria, }, - '_id title distance owner updated_at is_public', + '_id title distance owner updated_at is_public is_deleted', { limit: 9000, sort: { updated_at: -1 }, } ).populate('owner', '_id'); - list = list.filter(item => ( - !author || item.owner._id === author - )); + list = list.filter(item => !author || (item.owner && item.owner._id === author)); let limits = list.reduce(({ min, max }, { distance: dist }) => ({ min: Math.ceil(Math.min(dist, min) / 25) * 25, diff --git a/backend/routes/route/patch.js b/backend/routes/route/patch.js index 756627a..38bd4ca 100644 --- a/backend/routes/route/patch.js +++ b/backend/routes/route/patch.js @@ -12,7 +12,7 @@ module.exports = async (req, res) => { const title = parseString(body.title, 32); const is_public = !!body.is_public; - const exists = await Route.findOne({ _id: address }).populate('owner', '_id'); + const exists = await Route.findOne({ _id: address, is_deleted: false }).populate('owner', '_id'); if (!exists) return res.send({ success: false, mode: 'not_exists' }); if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'not_yours' }); diff --git a/backend/routes/route/post.js b/backend/routes/route/post.js index 94e0704..7e3ca9c 100644 --- a/backend/routes/route/post.js +++ b/backend/routes/route/post.js @@ -21,7 +21,7 @@ module.exports = async (req, res) => { return res.send({ success: false, mode: 'empty' }); } - const exists = await Route.findOne({ _id: address }).populate('owner', '_id'); + const exists = await Route.findOne({ _id: address, is_deleted: false }).populate('owner', '_id'); if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'exists' }); if (exists && !force) return res.send({ success: false, mode: 'overwriting' }); diff --git a/src/components/dialogs/MapListDialog.tsx b/src/components/dialogs/MapListDialog.tsx index 13f68e9..7a0344f 100644 --- a/src/components/dialogs/MapListDialog.tsx +++ b/src/components/dialogs/MapListDialog.tsx @@ -64,6 +64,10 @@ class Component extends React.Component this.setState({ + menu_target: null, + }); + showDropCard = (editor_target: IRouteListItem['_id']): void => this.setState({ editor_target, menu_target: null, @@ -211,6 +215,7 @@ class Component extends React.Component => (
-
showMenu(_id)}> - -
-
-
showDropCard(_id)}> - Удалить - -
-
startEditing(_id)}> - Редактировать - -
-
+ { + tab === 'mine' && + +
+ +
+
+ Удалить + +
+
+ Редактировать + +
+
+
+
+ } ); diff --git a/src/components/maps/RouteRowWrapper.tsx b/src/components/maps/RouteRowWrapper.tsx index 77580ff..a2cc981 100644 --- a/src/components/maps/RouteRowWrapper.tsx +++ b/src/components/maps/RouteRowWrapper.tsx @@ -20,6 +20,7 @@ interface Props { startEditing: typeof MapListDialog.startEditing, stopEditing: typeof MapListDialog.stopEditing, showMenu: typeof MapListDialog.showMenu, + hideMenu: typeof MapListDialog.hideMenu, showDropCard: typeof MapListDialog.showDropCard, dropRoute: typeof MapListDialog.dropRoute, modifyRoute: typeof MapListDialog.modifyRoute, @@ -30,7 +31,7 @@ interface Props { export const RouteRowWrapper = ({ title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard, is_public, is_editing_target, is_menu_target, is_editing_mode, - dropRoute, stopEditing, modifyRoute, + dropRoute, stopEditing, modifyRoute, hideMenu, }: Props): ReactElement => (
} diff --git a/src/redux/user/sagas.ts b/src/redux/user/sagas.ts index 5e04735..a02c05e 100644 --- a/src/redux/user/sagas.ts +++ b/src/redux/user/sagas.ts @@ -649,16 +649,46 @@ function* mapsLoadMoreSaga() { function* dropRouteSaga({ _id }: ReturnType): SagaIterator { const { id, token } = yield select(getUser); - const result = yield call(dropRoute, { address: _id, id, token }); + const { + routes: { list, step, shift, limit, filter: { min, max } } + } = yield select(getState); - console.log('result', result); + const index = list.findIndex(el => el._id === _id); + + if (index >= 0) { + yield put(searchPutRoutes({ + list: list.filter(el => el._id !== _id), + min, + max, + step, + shift: (shift > 0) ? shift - 1 : 0, + limit: (limit > 0) ? limit - 1 : limit, + })); + } + + return yield call(dropRoute, { address: _id, id, token }); } function* modifyRouteSaga({ _id, title, is_public }: ReturnType): SagaIterator { const { id, token } = yield select(getUser); - const result = yield call(modifyRoute, { address: _id, id, token, title, is_public }); + const { + routes: { list, step, shift, limit, filter: { min, max } } + } = yield select(getState); - console.log('result', result); + const index = list.findIndex(el => el._id === _id); + + if (index >= 0) { + yield put(searchPutRoutes({ + list: list.map(el => (el._id !== _id ? el : { ...el, title, is_public })), + min, + max, + step, + shift: (shift > 0) ? shift - 1 : 0, + limit: (limit > 0) ? limit - 1 : limit, + })); + } + + return yield call(modifyRoute, { address: _id, id, token, title, is_public }); } export function* userSaga() { diff --git a/src/styles/dialogs.less b/src/styles/dialogs.less index c585555..6fbbd17 100644 --- a/src/styles/dialogs.less +++ b/src/styles/dialogs.less @@ -197,11 +197,11 @@ &.is_menu_target { .route-row { - transform: translateX(-100px); + transform: translateX(-120px); } .route-row-edit-menu { - width: 100px; + width: 120px; } } } @@ -221,8 +221,11 @@ .route-row-view { overflow: hidden; transition: height 500ms; - padding-right: 32px; position: relative; + + &.has_menu { + padding-right: 32px; + } } .route-row-edit { @@ -295,15 +298,25 @@ fill: fade(white, 30%); div { - width: 50px; + width: 60px; height: 100%; display: flex; justify-content: center; align-items: center; + &:first-child { + box-shadow: fade(black, 30%) 1px 0; + } + &:hover { background: fade(@red_secondary, 30%); } + + &.modify-button { + &:hover { + background: fade(@green_secondary, 30%); + } + } } } diff --git a/src/utils/api.ts b/src/utils/api.ts index 702a525..8f2f53f 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -103,7 +103,7 @@ export const checkOSRMService = (bounds: LatLngLiteral[]): Promise => ( ); export const dropRoute = ({ address, id, token }: { address: string, id: string, token: string }): AxiosPromise => ( - axios.delete(API.DROP_ROUTE, { data: { address: '1123123123123', id, token } }) + axios.delete(API.DROP_ROUTE, { data: { address, id, token } }) ); export const modifyRoute = (