map dialog optimizations

This commit is contained in:
Fedor Katurov 2020-01-16 11:04:43 +07:00
parent 23b8f5dea6
commit b6bf317649
3 changed files with 146 additions and 110 deletions

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { RouteRowWrapper } from '~/components/maps/RouteRowWrapper'; import { RouteRowWrapper } from '~/components/maps/RouteRowWrapper';
import { Scroll } from '~/components/Scroll'; import { Scroll } from '~/components/Scroll';
@ -17,14 +17,13 @@ import { editorSetDialogActive } from '~/redux/editor/actions';
import { isMobile } from '~/utils/window'; import { isMobile } from '~/utils/window';
import classnames from 'classnames'; import classnames from 'classnames';
import Range from 'rc-slider/lib/Range';
import { TABS, TABS_TITLES } from '~/constants/dialogs'; import { TABS, TABS_TITLES } from '~/constants/dialogs';
import { Icon } from '~/components/panels/Icon'; import { Icon } from '~/components/panels/Icon';
import { pushPath } from '~/utils/history'; import { pushPath } from '~/utils/history';
import { IRouteListItem } from '~/redux/user'; import { IRouteListItem } from '~/redux/user';
import { ROLES } from '~/constants/auth'; import { ROLES } from '~/constants/auth';
import { IState } from '~/redux/store'; import { IState } from '~/redux/store';
import { MapListDialogHead } from '~/components/search/MapListDialogHead';
const mapStateToProps = ({ const mapStateToProps = ({
editor: { editing }, editor: { editing },
@ -37,7 +36,6 @@ const mapStateToProps = ({
return { return {
routes, routes,
editing, editing,
marks: {},
ready: false, ready: false,
role, role,
}; };
@ -48,16 +46,6 @@ const mapStateToProps = ({
routes, routes,
editing, editing,
ready: true, ready: true,
marks: [...new Array(Math.floor((routes.filter.max - routes.filter.min) / 25) + 1)].reduce(
(obj, el, i) => ({
...obj,
[routes.filter.min + i * 25]: ` ${routes.filter.min + i * 25}${
routes.filter.min + i * 25 >= 200 ? '+' : ''
}
`,
}),
{}
),
}; };
}; };
@ -72,7 +60,7 @@ const mapDispatchToProps = {
toggleRouteStarred, toggleRouteStarred,
}; };
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {} type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
export interface State { export interface State {
menu_target: IRouteListItem['address']; menu_target: IRouteListItem['address'];
@ -82,7 +70,7 @@ export interface State {
is_dropping: boolean; is_dropping: boolean;
} }
class MapListDialogUnconnected extends React.Component<Props, State> { class MapListDialogUnconnected extends PureComponent<Props, State> {
state = { state = {
menu_target: null, menu_target: null,
editor_target: null, editor_target: null,
@ -178,8 +166,8 @@ class MapListDialogUnconnected extends React.Component<Props, State> {
loading, loading,
filter: { min, max, title, distance, tab }, filter: { min, max, title, distance, tab },
}, },
marks, }: // marks,
}: Props = this.props; Props = this.props;
const { editor_target, menu_target, is_editing, is_dropping } = this.state; const { editor_target, menu_target, is_editing, is_dropping } = this.state;
@ -192,6 +180,7 @@ class MapListDialogUnconnected extends React.Component<Props, State> {
</div> </div>
</div> </div>
)} )}
{ready && !loading && list.length === 0 && ( {ready && !loading && list.length === 0 && (
<div className="dialog-maplist-loader"> <div className="dialog-maplist-loader">
<div className="dialog-maplist-icon"> <div className="dialog-maplist-icon">
@ -200,6 +189,7 @@ class MapListDialogUnconnected extends React.Component<Props, State> {
ТУТ ПУСТО <br />И ОДИНОКО ТУТ ПУСТО <br />И ОДИНОКО
</div> </div>
)} )}
<div className="dialog-tabs"> <div className="dialog-tabs">
{Object.values(TABS).map( {Object.values(TABS).map(
item => item =>
@ -214,32 +204,16 @@ class MapListDialogUnconnected extends React.Component<Props, State> {
) )
)} )}
</div> </div>
<div className="dialog-head">
<div> <MapListDialogHead
<input
type="text"
placeholder="Поиск по названию"
value={title}
onChange={this.setTitle}
/>
<br />
{ready && Object.keys(marks).length > 2 ? (
<Range
min={min} min={min}
max={max} max={max}
marks={marks} distance={distance}
step={25} onDistanceChange={this.props.searchSetDistance}
onChange={this.props.searchSetDistance} ready={ready}
defaultValue={[0, 10000]} search={title}
value={distance} onSearchChange={this.setTitle}
pushable={25}
disabled={min >= max}
/> />
) : (
<div className="range-placeholder" />
)}
</div>
</div>
<Scroll className="dialog-shader" onScroll={this.onScroll}> <Scroll className="dialog-shader" onScroll={this.onScroll}>
<div className="dialog-maplist"> <div className="dialog-maplist">
@ -276,7 +250,6 @@ class MapListDialogUnconnected extends React.Component<Props, State> {
} }
} }
const MapListDialog = connect(mapStateToProps, mapDispatchToProps)(MapListDialogUnconnected); const MapListDialog = connect(mapStateToProps, mapDispatchToProps)(MapListDialogUnconnected);
export { MapListDialog }; export { MapListDialog };

View file

@ -1,10 +1,10 @@
import React from "react"; import React, { FC, memo } from 'react';
import classnames from "classnames"; import classnames from 'classnames';
import { MapListDialog } from "~/components/dialogs/MapListDialog"; import { MapListDialog } from '~/components/dialogs/MapListDialog';
import { RouteRowView } from "~/components/maps/RouteRowView"; import { RouteRowView } from '~/components/maps/RouteRowView';
import { RouteRowEditor } from "~/components/maps/RouteRowEditor"; import { RouteRowEditor } from '~/components/maps/RouteRowEditor';
import { RouteRowDrop } from "~/components/maps/RouteRowDrop"; import { RouteRowDrop } from '~/components/maps/RouteRowDrop';
import { ReactElement } from "react"; import { ReactElement } from 'react';
interface Props { interface Props {
address: string; address: string;
@ -28,10 +28,11 @@ interface Props {
modifyRoute: typeof MapListDialog.modifyRoute; modifyRoute: typeof MapListDialog.modifyRoute;
toggleStarred: typeof MapListDialog.toggleStarred; toggleStarred: typeof MapListDialog.toggleStarred;
is_editing_mode: "edit" | "drop"; is_editing_mode: 'edit' | 'drop';
} }
export const RouteRowWrapper = ({ export const RouteRowWrapper: FC<Props> = memo(
({
title, title,
distance, distance,
address, address,
@ -50,15 +51,15 @@ export const RouteRowWrapper = ({
hideMenu, hideMenu,
is_admin, is_admin,
is_published, is_published,
toggleStarred toggleStarred,
}: Props): ReactElement<Props, null> => ( }) => (
<div <div
className={classnames("route-row-wrapper", { className={classnames('route-row-wrapper', {
is_menu_target, is_menu_target,
is_editing_target is_editing_target,
})} })}
> >
{is_editing_target && is_editing_mode === "edit" && ( {is_editing_target && is_editing_mode === 'edit' && (
<RouteRowEditor <RouteRowEditor
title={title} title={title}
address={address} address={address}
@ -66,7 +67,7 @@ export const RouteRowWrapper = ({
modifyRoute={modifyRoute} modifyRoute={modifyRoute}
/> />
)} )}
{is_editing_target && is_editing_mode === "drop" && ( {is_editing_target && is_editing_mode === 'drop' && (
<RouteRowDrop address={address} dropRoute={dropRoute} stopEditing={stopEditing} /> <RouteRowDrop address={address} dropRoute={dropRoute} stopEditing={stopEditing} />
)} )}
{!is_editing_target && ( {!is_editing_target && (
@ -88,4 +89,5 @@ export const RouteRowWrapper = ({
/> />
)} )}
</div> </div>
)
); );

View file

@ -0,0 +1,61 @@
import React, { FC, memo, useMemo, ChangeEvent, ChangeEventHandler } from 'react';
import Range from 'rc-slider/lib/Range';
interface Props {
ready: boolean;
min: number;
max: number;
search: string;
distance: [number, number];
onDistanceChange: (val: [number, number]) => void;
onSearchChange: ChangeEventHandler<HTMLInputElement>;
}
const MapListDialogHead: FC<Props> = memo(
({ min, max, ready, distance, search, onSearchChange, onDistanceChange }) => {
const marks = useMemo(
() =>
[...new Array(Math.floor((max - min) / 25) + 1)].reduce(
(obj, el, i) => ({
...obj,
[min + i * 25]: min + i * 25 < 200 ? ` ${min + i * 25}` : ` ${min + i * 25}+`,
}),
{}
),
[]
);
return (
<div className="dialog-head">
<div>
<input
type="text"
placeholder="Поиск по названию"
value={search}
onChange={onSearchChange}
/>
<div />
{ready && Object.keys(marks).length > 2 ? (
<Range
min={min}
max={max}
marks={marks}
step={25}
onChange={onDistanceChange}
defaultValue={[0, 10000]}
value={distance}
pushable={25}
disabled={min >= max}
/>
) : (
<div className="range-placeholder" />
)}
</div>
</div>
);
}
);
export { MapListDialogHead };