complete item editing

This commit is contained in:
muerwre 2019-03-07 11:49:40 +07:00
parent 7513f79b93
commit 0cbbc0ce8a
12 changed files with 94 additions and 34 deletions

View file

@ -13,6 +13,7 @@ const RouteSchema = new Schema(
owner: { type: Schema.Types.ObjectId, ref: 'User' }, owner: { type: Schema.Types.ObjectId, ref: 'User' },
distance: { type: Number, default: 0 }, distance: { type: Number, default: 0 },
is_public: { type: Boolean, default: false }, is_public: { type: Boolean, default: false },
is_deleted: { type: Boolean, default: false },
created_at: { type: Date, default: Date.now() }, created_at: { type: Date, default: Date.now() },
updated_at: { type: Date, default: Date.now() }, updated_at: { type: Date, default: Date.now() },
logo: { type: String, default: 'DEFAULT' }, logo: { type: String, default: 'DEFAULT' },

View file

@ -12,7 +12,7 @@ module.exports = async (req, res) => {
if (!exists) return res.send({ success: false, mode: 'not_exists' }); if (!exists) return res.send({ success: false, mode: 'not_exists' });
if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'not_yours' }); 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 }); return res.send({ success: true, address });
}; };

View file

@ -6,7 +6,7 @@ module.exports = async (req, res) => {
if (!name) return res.send({ success: false, mode: 'not_found_1' }); 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' }); if (!exists) return res.send({ success: false, mode: 'not_found_2' });
const data = exists.toObject(); const data = exists.toObject();

View file

@ -9,7 +9,7 @@ module.exports = async (req, res) => {
const user = await User.findOne({ _id: id, token }); const user = await User.findOne({ _id: id, token });
let criteria = {}; let criteria = { is_deleted: false };
if (title) { if (title) {
criteria = { criteria = {
@ -32,16 +32,14 @@ module.exports = async (req, res) => {
{ {
...criteria, ...criteria,
}, },
'_id title distance owner updated_at is_public', '_id title distance owner updated_at is_public is_deleted',
{ {
limit: 9000, limit: 9000,
sort: { updated_at: -1 }, sort: { updated_at: -1 },
} }
).populate('owner', '_id'); ).populate('owner', '_id');
list = list.filter(item => ( list = list.filter(item => !author || (item.owner && item.owner._id === author));
!author || item.owner._id === author
));
let limits = list.reduce(({ min, max }, { distance: dist }) => ({ let limits = list.reduce(({ min, max }, { distance: dist }) => ({
min: Math.ceil(Math.min(dist, min) / 25) * 25, min: Math.ceil(Math.min(dist, min) / 25) * 25,

View file

@ -12,7 +12,7 @@ module.exports = async (req, res) => {
const title = parseString(body.title, 32); const title = parseString(body.title, 32);
const is_public = !!body.is_public; 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) return res.send({ success: false, mode: 'not_exists' });
if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'not_yours' }); if (exists && exists.owner._id !== id) return res.send({ success: false, mode: 'not_yours' });

View file

@ -21,7 +21,7 @@ module.exports = async (req, res) => {
return res.send({ success: false, mode: 'empty' }); 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 && exists.owner._id !== id) return res.send({ success: false, mode: 'exists' });
if (exists && !force) return res.send({ success: false, mode: 'overwriting' }); if (exists && !force) return res.send({ success: false, mode: 'overwriting' });

View file

@ -64,6 +64,10 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
menu_target, menu_target,
}); });
hideMenu = (): void => this.setState({
menu_target: null,
});
showDropCard = (editor_target: IRouteListItem['_id']): void => this.setState({ showDropCard = (editor_target: IRouteListItem['_id']): void => this.setState({
editor_target, editor_target,
menu_target: null, menu_target: null,
@ -211,6 +215,7 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
startEditing={this.startEditing} startEditing={this.startEditing}
stopEditing={this.stopEditing} stopEditing={this.stopEditing}
showMenu={this.showMenu} showMenu={this.showMenu}
hideMenu={this.hideMenu}
showDropCard={this.showDropCard} showDropCard={this.showDropCard}
dropRoute={this.dropRoute} dropRoute={this.dropRoute}
modifyRoute={this.modifyRoute} modifyRoute={this.modifyRoute}

View file

@ -4,6 +4,7 @@ import { Icon } from '$components/panels/Icon';
import { MapListDialog } from "$components/dialogs/MapListDialog"; import { MapListDialog } from "$components/dialogs/MapListDialog";
import { Tooltip } from "$components/panels/Tooltip"; import { Tooltip } from "$components/panels/Tooltip";
import { ReactElement } from "react"; import { ReactElement } from "react";
import classnames from 'classnames';
interface Props { interface Props {
_id: string, _id: string,
@ -16,14 +17,15 @@ interface Props {
startEditing: typeof MapListDialog.startEditing, startEditing: typeof MapListDialog.startEditing,
stopEditing: typeof MapListDialog.stopEditing, stopEditing: typeof MapListDialog.stopEditing,
showMenu: typeof MapListDialog.showMenu, showMenu: typeof MapListDialog.showMenu,
hideMenu: typeof MapListDialog.hideMenu,
showDropCard: typeof MapListDialog.showDropCard, showDropCard: typeof MapListDialog.showDropCard,
} }
export const RouteRowView = ({ export const RouteRowView = ({
title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard, hideMenu,
}: Props): ReactElement<Props, null> => ( }: Props): ReactElement<Props, null> => (
<div <div
className="route-row-view" className={classnames('route-row-view', { has_menu: (tab === 'mine') })}
> >
<div <div
className="route-row" className="route-row"
@ -44,18 +46,27 @@ export const RouteRowView = ({
</span> </span>
</div> </div>
</div> </div>
<div className="route-row-edit-button pointer" onClick={() => showMenu(_id)}> {
<Icon icon="icon-more-vert" /> tab === 'mine' &&
</div> <React.Fragment>
<div className="route-row-edit-menu pointer"> <div
<div onMouseDown={() => showDropCard(_id)}> className="route-row-edit-button pointer"
<Tooltip>Удалить</Tooltip> onMouseOver={showMenu.bind(null, _id)}
<Icon icon="icon-trash-3" size={32} /> onMouseOut={hideMenu}
</div> >
<div onMouseDown={() => startEditing(_id)}> <Icon icon="icon-more-vert" />
<Tooltip>Редактировать</Tooltip> <div className="route-row-edit-menu pointer">
<Icon icon="icon-edit-1" size={32} /> <div onMouseDown={showDropCard.bind(null, _id)}>
</div> <Tooltip>Удалить</Tooltip>
</div> <Icon icon="icon-trash-3" size={32} />
</div>
<div onMouseDown={startEditing.bind(null, _id)} className="modify-button">
<Tooltip>Редактировать</Tooltip>
<Icon icon="icon-edit-1" size={32} />
</div>
</div>
</div>
</React.Fragment>
}
</div> </div>
); );

View file

@ -20,6 +20,7 @@ interface Props {
startEditing: typeof MapListDialog.startEditing, startEditing: typeof MapListDialog.startEditing,
stopEditing: typeof MapListDialog.stopEditing, stopEditing: typeof MapListDialog.stopEditing,
showMenu: typeof MapListDialog.showMenu, showMenu: typeof MapListDialog.showMenu,
hideMenu: typeof MapListDialog.hideMenu,
showDropCard: typeof MapListDialog.showDropCard, showDropCard: typeof MapListDialog.showDropCard,
dropRoute: typeof MapListDialog.dropRoute, dropRoute: typeof MapListDialog.dropRoute,
modifyRoute: typeof MapListDialog.modifyRoute, modifyRoute: typeof MapListDialog.modifyRoute,
@ -30,7 +31,7 @@ interface Props {
export const RouteRowWrapper = ({ export const RouteRowWrapper = ({
title, distance, _id, openRoute, tab, startEditing, showMenu, title, distance, _id, openRoute, tab, startEditing, showMenu,
showDropCard, is_public, is_editing_target, is_menu_target, is_editing_mode, showDropCard, is_public, is_editing_target, is_menu_target, is_editing_mode,
dropRoute, stopEditing, modifyRoute, dropRoute, stopEditing, modifyRoute, hideMenu,
}: Props): ReactElement<Props, null> => ( }: Props): ReactElement<Props, null> => (
<div <div
className={classnames('route-row-wrapper', { className={classnames('route-row-wrapper', {
@ -67,6 +68,7 @@ export const RouteRowWrapper = ({
startEditing={startEditing} startEditing={startEditing}
stopEditing={stopEditing} stopEditing={stopEditing}
showMenu={showMenu} showMenu={showMenu}
hideMenu={hideMenu}
showDropCard={showDropCard} showDropCard={showDropCard}
/> />
} }

View file

@ -649,16 +649,46 @@ function* mapsLoadMoreSaga() {
function* dropRouteSaga({ _id }: ReturnType<typeof ActionCreators.dropRoute>): SagaIterator { function* dropRouteSaga({ _id }: ReturnType<typeof ActionCreators.dropRoute>): SagaIterator {
const { id, token } = yield select(getUser); 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<typeof ActionCreators.modifyRoute>): SagaIterator { function* modifyRouteSaga({ _id, title, is_public }: ReturnType<typeof ActionCreators.modifyRoute>): SagaIterator {
const { id, token } = yield select(getUser); 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() { export function* userSaga() {

View file

@ -197,11 +197,11 @@
&.is_menu_target { &.is_menu_target {
.route-row { .route-row {
transform: translateX(-100px); transform: translateX(-120px);
} }
.route-row-edit-menu { .route-row-edit-menu {
width: 100px; width: 120px;
} }
} }
} }
@ -221,8 +221,11 @@
.route-row-view { .route-row-view {
overflow: hidden; overflow: hidden;
transition: height 500ms; transition: height 500ms;
padding-right: 32px;
position: relative; position: relative;
&.has_menu {
padding-right: 32px;
}
} }
.route-row-edit { .route-row-edit {
@ -295,15 +298,25 @@
fill: fade(white, 30%); fill: fade(white, 30%);
div { div {
width: 50px; width: 60px;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
&:first-child {
box-shadow: fade(black, 30%) 1px 0;
}
&:hover { &:hover {
background: fade(@red_secondary, 30%); background: fade(@red_secondary, 30%);
} }
&.modify-button {
&:hover {
background: fade(@green_secondary, 30%);
}
}
} }
} }

View file

@ -103,7 +103,7 @@ export const checkOSRMService = (bounds: LatLngLiteral[]): Promise<boolean> => (
); );
export const dropRoute = ({ address, id, token }: { address: string, id: string, token: string }): AxiosPromise<any> => ( export const dropRoute = ({ address, id, token }: { address: string, id: string, token: string }): AxiosPromise<any> => (
axios.delete(API.DROP_ROUTE, { data: { address: '1123123123123', id, token } }) axios.delete(API.DROP_ROUTE, { data: { address, id, token } })
); );
export const modifyRoute = ( export const modifyRoute = (