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

View file

@ -1,10 +1,10 @@
import 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";
import React, { FC, memo } 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 {
address: string;
@ -28,64 +28,66 @@ interface Props {
modifyRoute: typeof MapListDialog.modifyRoute;
toggleStarred: typeof MapListDialog.toggleStarred;
is_editing_mode: "edit" | "drop";
is_editing_mode: 'edit' | 'drop';
}
export const RouteRowWrapper = ({
title,
distance,
address,
openRoute,
tab,
startEditing,
showMenu,
showDropCard,
is_public,
is_editing_target,
is_menu_target,
is_editing_mode,
dropRoute,
stopEditing,
modifyRoute,
hideMenu,
is_admin,
is_published,
toggleStarred
}: 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}
address={address}
is_public={is_public}
modifyRoute={modifyRoute}
/>
)}
{is_editing_target && is_editing_mode === "drop" && (
<RouteRowDrop address={address} dropRoute={dropRoute} stopEditing={stopEditing} />
)}
{!is_editing_target && (
<RouteRowView
address={address}
tab={tab}
title={title}
distance={distance}
is_public={is_public}
is_published={is_published}
openRoute={openRoute}
startEditing={startEditing}
stopEditing={stopEditing}
showMenu={showMenu}
hideMenu={hideMenu}
showDropCard={showDropCard}
is_admin={is_admin}
toggleStarred={toggleStarred}
/>
)}
</div>
export const RouteRowWrapper: FC<Props> = memo(
({
title,
distance,
address,
openRoute,
tab,
startEditing,
showMenu,
showDropCard,
is_public,
is_editing_target,
is_menu_target,
is_editing_mode,
dropRoute,
stopEditing,
modifyRoute,
hideMenu,
is_admin,
is_published,
toggleStarred,
}) => (
<div
className={classnames('route-row-wrapper', {
is_menu_target,
is_editing_target,
})}
>
{is_editing_target && is_editing_mode === 'edit' && (
<RouteRowEditor
title={title}
address={address}
is_public={is_public}
modifyRoute={modifyRoute}
/>
)}
{is_editing_target && is_editing_mode === 'drop' && (
<RouteRowDrop address={address} dropRoute={dropRoute} stopEditing={stopEditing} />
)}
{!is_editing_target && (
<RouteRowView
address={address}
tab={tab}
title={title}
distance={distance}
is_public={is_public}
is_published={is_published}
openRoute={openRoute}
startEditing={startEditing}
stopEditing={stopEditing}
showMenu={showMenu}
hideMenu={hideMenu}
showDropCard={showDropCard}
is_admin={is_admin}
toggleStarred={toggleStarred}
/>
)}
</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 };