dialog-editor: drop and edit items

This commit is contained in:
muerwre 2019-03-01 10:46:18 +07:00
parent a2607b257d
commit 970d0967c8
10 changed files with 279 additions and 150 deletions

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { RouteRow } from '$components/maps/RouteRow';
import { RouteRowWrapper } from '$components/maps/RouteRowWrapper';
import { Scroll } from '$components/Scroll';
import {
searchSetDistance,
@ -21,6 +21,8 @@ import { IRootState, IRouteListItem } from '$redux/user/reducer';
export interface IMapListDialogProps extends IRootState {
marks: { [x: number]: string },
routes_sorted: Array<IRouteListItem>,
routes: IRootState['routes'],
ready: IRootState['ready'],
mapsLoadMore: typeof mapsLoadMore,
searchSetDistance: typeof searchSetDistance,
@ -30,32 +32,44 @@ export interface IMapListDialogProps extends IRootState {
}
export interface IMapListDialogState {
selected_item: IRouteListItem['_id'],
selected_item_mode: 'menu' | 'edit' | 'drop' | null,
menu_target: IRouteListItem['_id'],
editor_target: IRouteListItem['_id'],
is_editing: boolean,
is_dropping: boolean,
}
class Component extends React.Component<IMapListDialogProps, IMapListDialogState> {
state = {
selected_item: null,
selected_item_mode: null,
menu_target: null,
editor_target: null,
is_editing: false,
is_dropping: false,
};
startEditing = (selected_item: IRouteListItem['_id']): void => this.setState({
selected_item: ((this.state.selected_item !== selected_item && selected_item) || null),
selected_item_mode: 'edit',
startEditing = (editor_target: IRouteListItem['_id']): void => this.setState({
editor_target,
menu_target: null,
is_editing: true,
is_dropping: false,
});
showMenu = (selected_item: IRouteListItem['_id']): void => this.setState({
selected_item: ((this.state.selected_item !== selected_item && selected_item) || null),
selected_item_mode: 'menu',
showMenu = (menu_target: IRouteListItem['_id']): void => this.setState({
menu_target,
});
showDropCard = (selected_item: IRouteListItem['_id']): void => this.setState({
selected_item: ((this.state.selected_item !== selected_item && selected_item) || null),
selected_item_mode: 'drop',
showDropCard = (editor_target: IRouteListItem['_id']): void => this.setState({
editor_target,
menu_target: null,
is_editing: false,
is_dropping: true,
});
stopEditing = (): void => this.setState({ selected_item: null });
stopEditing = (): void => {
console.log('stop it!');
this.setState({ editor_target: null });
};
setTitle = ({ target: { value } }: { target: { value: string }}): void => {
this.props.searchSetTitle(value);
@ -64,6 +78,8 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
openRoute = (_id: string): void => {
if (isMobile()) this.props.setDialogActive(false);
this.stopEditing();
pushPath(`/${_id}/${this.props.editing ? 'edit' : ''}`);
};
@ -80,6 +96,8 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
}
};
dropRoute = (): void => null;
render() {
const {
ready,
@ -97,7 +115,7 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
marks,
}: IMapListDialogProps = this.props;
const { selected_item, selected_item_mode } = this.state;
const { editor_target, menu_target, is_editing, is_dropping } = this.state;
return (
<div className="dialog-content">
@ -166,19 +184,21 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
<div className="dialog-maplist">
{
list.map(route => (
<RouteRow
<RouteRowWrapper
title={route.title}
distance={route.distance}
_id={route._id}
is_public={route.is_public}
tab={tab}
selected={(selected_item === route._id)}
mode={selected_item_mode}
is_editing_mode={is_dropping ? 'drop' : 'edit'}
is_editing_target={editor_target === route._id}
is_menu_target={menu_target === route._id}
openRoute={this.openRoute}
startEditing={this.startEditing}
stopEditing={this.stopEditing}
showMenu={this.showMenu}
showDropCard={this.showDropCard}
dropRoute={this.dropRoute}
key={route._id}
/>
))

View file

@ -1,69 +0,0 @@
// @flow
import * as React from 'react';
import { Icon } from '$components/panels/Icon';
import classnames from 'classnames';
import { IMapListDialogState, MapListDialog } from "$components/dialogs/MapListDialog";
import { Tooltip } from "$components/panels/Tooltip";
interface Props {
_id: string,
tab: string,
selected: boolean,
title: string,
distance: number,
is_public: boolean,
mode: IMapListDialogState['selected_item_mode'],
openRoute: typeof MapListDialog.openRoute,
startEditing: typeof MapListDialog.startEditing,
stopEditing: typeof MapListDialog.stopEditing,
showMenu: typeof MapListDialog.showMenu,
showDropCard: typeof MapListDialog.showDropCard,
key: string,
}
export const RouteRow = ({
title, distance, _id, openRoute, tab, selected, startEditing, showMenu, showDropCard, mode
}: Props) => (
<div
className={classnames('route-row-wrapper', {
selected,
has_menu: selected && mode === 'menu',
has_drop: selected && mode === 'drop',
has_edit: selected && mode === 'edit',
})}
>
<div
className="route-row"
>
<div onClick={() => openRoute(_id)}>
<div className="route-title">
<span>{(title || _id)}</span>
</div>
<div className="route-description">
<span>
<Icon icon="icon-link-1" />
{_id}
</span>
<span>
<Icon icon="icon-cycle-1" />
{(distance && `${distance} km`) || '0 km'}
</span>
</div>
</div>
</div>
<div className="route-row-edit-button pointer" onClick={() => showMenu(_id)}>
<Icon icon="icon-more-vert" />
<div className="route-row-edit-menu">
<div onClick={() => showDropCard(_id)}>
<Tooltip>Удалить</Tooltip>
<Icon icon="icon-trash-3" size={32} />
</div>
<div onClick={() => startEditing(_id)}>
<Tooltip>Редактировать</Tooltip>
<Icon icon="icon-edit-1" size={32} />
</div>
</div>
</div>
</div>
);

View file

@ -0,0 +1,29 @@
// @flow
import * as React from 'react';
import { Icon } from '$components/panels/Icon';
import { MapListDialog } from "$components/dialogs/MapListDialog";
import { Tooltip } from "$components/panels/Tooltip";
import { ReactElement } from "react";
interface Props {
_id: string,
stopEditing: typeof MapListDialog.stopEditing,
dropRoute: typeof MapListDialog.dropRoute,
}
export const RouteRowDrop = ({
_id, stopEditing, dropRoute,
}: Props): ReactElement<Props, null> => (
<div
className="route-row-drop"
>
<div
className="route-row"
>
<div className="button-group">
<div className="button" onClick={() => dropRoute(_id)}>Удалить</div>
<div className="button primary" onClick={stopEditing}>Отмена</div>
</div>
</div>
</div>
);

View file

@ -5,9 +5,8 @@ import { Switch } from '$components/Switch';
interface Props {
title: string;
is_editing: boolean;
distance: number;
_id: string;
is_public: boolean,
}
interface State {
@ -32,46 +31,34 @@ export class RouteRowEditor extends React.Component<Props, State> {
render() {
const {
state: { title, is_public },
props: { distance, _id }
props: { _id }
} = this;
return (
<div
className="route-row"
>
<div className="route-title">
<input
type="text"
value={title}
onChange={this.setTitle}
placeholder="Введите название"
autoFocus
/>
</div>
<div className="route-description">
<span>
<Icon icon="icon-link-1" />
{_id}
</span>
<span>
<Icon icon="icon-cycle-1" />
{(distance && `${distance} km`) || '0 km'}
</span>
</div>
<div className="route-row-editor">
<div className="route-row-buttons">
<div className="flex_1" onClick={this.setPublic}>
<Switch
active={is_public}
/>
{
is_public
? ' В каталоге карт'
: ' Только по ссылке'
}
</div>
<div className="button primary" onClick={this.stopEditing}>
OK
<div className="route-row-edit">
<div className="route-row">
<div className="route-title">
<input
type="text"
value={title}
onChange={this.setTitle}
placeholder="Введите название"
autoFocus
/>
</div>
<div className="route-row-editor">
<div className="route-row-buttons">
<div className="flex_1" onClick={this.setPublic}>
<Switch active={is_public} />
{
is_public
? ' В каталоге карт'
: ' Только по ссылке'
}
</div>
<div className="button primary" onClick={this.stopEditing}>
OK
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,61 @@
// @flow
import * as React from 'react';
import { Icon } from '$components/panels/Icon';
import { MapListDialog } from "$components/dialogs/MapListDialog";
import { Tooltip } from "$components/panels/Tooltip";
import { ReactElement } from "react";
interface Props {
_id: string,
tab: string,
title: string,
distance: number,
is_public: boolean,
openRoute: typeof MapListDialog.openRoute,
startEditing: typeof MapListDialog.startEditing,
stopEditing: typeof MapListDialog.stopEditing,
showMenu: typeof MapListDialog.showMenu,
showDropCard: typeof MapListDialog.showDropCard,
}
export const RouteRowView = ({
title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard
}: Props): ReactElement<Props, null> => (
<div
className="route-row-view"
>
<div
className="route-row"
onClick={() => openRoute(_id)}
>
<div className="route-title">
<span>{(title || _id)}</span>
</div>
<div className="route-description">
<span>
<Icon icon="icon-link-1" />
{_id}
</span>
<span>
<Icon icon="icon-cycle-1" />
{(distance && `${distance} km`) || '0 km'}
</span>
</div>
</div>
<div className="route-row-edit-button pointer" onClick={() => showMenu(_id)}>
<Icon icon="icon-more-vert" />
</div>
<div className="route-row-edit-menu pointer">
<div onMouseDown={() => showDropCard(_id)}>
<Tooltip>Удалить</Tooltip>
<Icon icon="icon-trash-3" size={32} />
</div>
<div onMouseDown={() => startEditing(_id)}>
<Tooltip>Редактировать</Tooltip>
<Icon icon="icon-edit-1" size={32} />
</div>
</div>
</div>
);

View file

@ -0,0 +1,72 @@
import * as React from 'react';
import classnames from 'classnames';
import { MapListDialog } from "$components/dialogs/MapListDialog";
import { RouteRowView } from "$components/maps/RouteRowView";
import { RouteRowEditor } from "$components/maps/RouteRowEditor";
import { RouteRowDrop } from "$components/maps/RouteRowDrop";
import { ReactElement } from "react";
interface Props {
_id: string,
tab: string,
title: string,
distance: number,
is_public: boolean,
is_editing_target: boolean,
is_menu_target: boolean,
openRoute: typeof MapListDialog.openRoute,
startEditing: typeof MapListDialog.startEditing,
stopEditing: typeof MapListDialog.stopEditing,
showMenu: typeof MapListDialog.showMenu,
showDropCard: typeof MapListDialog.showDropCard,
dropRoute: typeof MapListDialog.dropRoute,
is_editing_mode: 'edit' | 'drop',
}
export const RouteRowWrapper = ({
title, distance, _id, openRoute, tab, startEditing, showMenu,
showDropCard, is_public, is_editing_target, is_menu_target, is_editing_mode,
dropRoute, stopEditing,
}: Props): ReactElement<Props, null> => (
<div
className={classnames('route-row-wrapper', {
is_menu_target,
is_editing_target,
})}
>
{
is_editing_target && is_editing_mode === 'edit' &&
<RouteRowEditor
title={title}
_id={_id}
is_public={is_public}
/>
}
{
is_editing_target && is_editing_mode === 'drop' &&
<RouteRowDrop
_id={_id}
dropRoute={dropRoute}
stopEditing={stopEditing}
/>
}
{
!is_editing_target &&
<RouteRowView
_id={_id}
tab={tab}
title={title}
distance={distance}
is_public={is_public}
openRoute={openRoute}
startEditing={startEditing}
stopEditing={stopEditing}
showMenu={showMenu}
showDropCard={showDropCard}
/>
}
</div>
);