mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 19:16:41 +07:00
map dialog optimizations
This commit is contained in:
parent
23b8f5dea6
commit
b6bf317649
3 changed files with 146 additions and 110 deletions
|
@ -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 };
|
||||||
|
|
|
@ -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>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
61
src/components/search/MapListDialogHead.tsx
Normal file
61
src/components/search/MapListDialogHead.tsx
Normal 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 };
|
Loading…
Add table
Add a link
Reference in a new issue