mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
moved editor to separate reducer
This commit is contained in:
parent
e950d98b73
commit
87670770b0
38 changed files with 1425 additions and 1069 deletions
|
@ -1,17 +1,18 @@
|
|||
import React from 'react';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { IStickerPack, STICKERS } from '~/constants/stickers';
|
||||
import { STICKERS } from '~/constants/stickers';
|
||||
import { StickerIcon } from '~/components/StickerIcon';
|
||||
import { IRootReducer } from '~/redux/user';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectEditor } from '~/redux/editor/selectors'
|
||||
|
||||
interface Props {
|
||||
mode: IRootReducer['mode'],
|
||||
sticker: string,
|
||||
set: keyof IStickerPack,
|
||||
}
|
||||
const mapStateToProps = state => ({
|
||||
editor: selectEditor
|
||||
});
|
||||
|
||||
export class Cursor extends React.PureComponent<Props, {}> {
|
||||
const mapDispatchToProps = {};
|
||||
|
||||
class CursorUnconnected extends React.PureComponent<Props, {}> {
|
||||
componentDidMount() {
|
||||
window.addEventListener('mousemove', this.moveCursor);
|
||||
}
|
||||
|
@ -27,15 +28,27 @@ export class Cursor extends React.PureComponent<Props, {}> {
|
|||
cursor: HTMLElement = null;
|
||||
|
||||
render() {
|
||||
const { mode, set, sticker } = this.props;
|
||||
const activeSticker = (sticker && set && STICKERS[set] && STICKERS[set].layers[sticker]);
|
||||
const {
|
||||
editor: { mode, set, sticker },
|
||||
} = this.props;
|
||||
|
||||
const activeSticker = sticker && set && STICKERS[set] && STICKERS[set].layers[sticker];
|
||||
|
||||
return (
|
||||
<div className="cursor-tooltip desktop-only" ref={el => { this.cursor = el; }}>
|
||||
{ mode === MODES.ROUTER && <Icon icon="icon-router" />}
|
||||
{ mode === MODES.POLY && <Icon icon="icon-poly" />}
|
||||
{ mode === MODES.STICKERS && activeSticker && <StickerIcon sticker={sticker} set={set} /> }
|
||||
<div
|
||||
className="cursor-tooltip desktop-only"
|
||||
ref={el => {
|
||||
this.cursor = el;
|
||||
}}
|
||||
>
|
||||
{mode === MODES.ROUTER && <Icon icon="icon-router" />}
|
||||
{mode === MODES.POLY && <Icon icon="icon-poly" />}
|
||||
{mode === MODES.STICKERS && activeSticker && <StickerIcon sticker={sticker} set={set} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const Cursor = connect()(CursorUnconnected);
|
||||
|
||||
export { Cursor }
|
|
@ -2,21 +2,23 @@ import React from 'react';
|
|||
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import { setMode, stopEditing } from "~/redux/user/actions";
|
||||
import { editorSetMode, editorStopEditing } from '~/redux/editor/actions';
|
||||
|
||||
type Props = {
|
||||
stopEditing: typeof stopEditing,
|
||||
setMode: typeof setMode,
|
||||
width: number,
|
||||
const mapStateToProps = () => ({});
|
||||
const mapDispatchToProps = {
|
||||
editorSetMode,
|
||||
editorStopEditing,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { width?: number };
|
||||
|
||||
export class CancelDialog extends React.Component<Props, void> {
|
||||
cancel = () => {
|
||||
this.props.stopEditing();
|
||||
this.props.editorStopEditing();
|
||||
};
|
||||
|
||||
proceed = () => {
|
||||
this.props.setMode(MODES.NONE);
|
||||
this.props.editorSetMode(MODES.NONE);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
|
@ -6,12 +6,14 @@ import {
|
|||
searchSetDistance,
|
||||
searchSetTitle,
|
||||
searchSetTab,
|
||||
setDialogActive,
|
||||
mapsLoadMore,
|
||||
dropRoute,
|
||||
modifyRoute,
|
||||
toggleRouteStarred,
|
||||
} from '~/redux/user/actions';
|
||||
|
||||
import { editorSetDialogActive } from '~/redux/editor/actions';
|
||||
|
||||
import { isMobile } from '~/utils/window';
|
||||
import classnames from 'classnames';
|
||||
|
||||
|
@ -19,28 +21,60 @@ 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 { IRootState, IRouteListItem } from '~/redux/user';
|
||||
import { IRouteListItem } from '~/redux/user';
|
||||
import { ROLES } from '~/constants/auth';
|
||||
import { IState } from '~/redux/store';
|
||||
|
||||
export interface IMapListDialogProps extends IRootState {
|
||||
marks: { [x: number]: string };
|
||||
routes_sorted: Array<IRouteListItem>;
|
||||
routes: IRootState['routes'];
|
||||
ready: IRootState['ready'];
|
||||
role: IRootState['user']['role'];
|
||||
|
||||
mapsLoadMore: typeof mapsLoadMore;
|
||||
searchSetDistance: typeof searchSetDistance;
|
||||
searchSetTitle: typeof searchSetTitle;
|
||||
searchSetTab: typeof searchSetTab;
|
||||
setDialogActive: typeof setDialogActive;
|
||||
dropRoute: typeof dropRoute;
|
||||
modifyRoute: typeof modifyRoute;
|
||||
toggleRouteStarred: typeof toggleRouteStarred;
|
||||
}
|
||||
const mapStateToProps = ({
|
||||
editor: { editing },
|
||||
user: {
|
||||
routes,
|
||||
user: { role },
|
||||
},
|
||||
}: IState) => {
|
||||
if (routes.filter.max >= 9999) {
|
||||
return {
|
||||
routes,
|
||||
editing,
|
||||
marks: {},
|
||||
ready: false,
|
||||
role,
|
||||
};
|
||||
}
|
||||
|
||||
export interface IMapListDialogState {
|
||||
return {
|
||||
role,
|
||||
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 ? '+' : ''
|
||||
}
|
||||
`,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
searchSetDistance,
|
||||
searchSetTitle,
|
||||
searchSetTab,
|
||||
editorSetDialogActive,
|
||||
mapsLoadMore,
|
||||
dropRoute,
|
||||
modifyRoute,
|
||||
toggleRouteStarred,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {}
|
||||
|
||||
export interface State {
|
||||
menu_target: IRouteListItem['address'];
|
||||
editor_target: IRouteListItem['address'];
|
||||
|
||||
|
@ -48,7 +82,7 @@ export interface IMapListDialogState {
|
|||
is_dropping: boolean;
|
||||
}
|
||||
|
||||
class MapListDialogUnconnected extends React.Component<IMapListDialogProps, IMapListDialogState> {
|
||||
class MapListDialogUnconnected extends React.Component<Props, State> {
|
||||
state = {
|
||||
menu_target: null,
|
||||
editor_target: null,
|
||||
|
@ -92,14 +126,11 @@ class MapListDialogUnconnected extends React.Component<IMapListDialogProps, IMap
|
|||
};
|
||||
|
||||
openRoute = (_id: string): void => {
|
||||
if (isMobile()) this.props.setDialogActive(false);
|
||||
if (isMobile()) this.props.editorSetDialogActive(false);
|
||||
|
||||
// pushPath(`/${_id}/${this.props.editing ? 'edit' : ''}`);
|
||||
this.stopEditing();
|
||||
|
||||
pushPath(`/${_id}`);
|
||||
|
||||
// pushPath(`/${_id}/${this.props.editing ? 'edit' : ''}`);
|
||||
};
|
||||
|
||||
onScroll = (e: {
|
||||
|
@ -148,7 +179,7 @@ class MapListDialogUnconnected extends React.Component<IMapListDialogProps, IMap
|
|||
filter: { min, max, title, distance, tab },
|
||||
},
|
||||
marks,
|
||||
}: IMapListDialogProps = this.props;
|
||||
}: Props = this.props;
|
||||
|
||||
const { editor_target, menu_target, is_editing, is_dropping } = this.state;
|
||||
|
||||
|
@ -245,51 +276,6 @@ class MapListDialogUnconnected extends React.Component<IMapListDialogProps, IMap
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({
|
||||
user: {
|
||||
editing,
|
||||
routes,
|
||||
user: { role },
|
||||
},
|
||||
}: IState) => {
|
||||
if (routes.filter.max >= 9999) {
|
||||
return {
|
||||
routes,
|
||||
editing,
|
||||
marks: {},
|
||||
ready: false,
|
||||
role,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
role,
|
||||
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 ? '+' : ''
|
||||
}
|
||||
`,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
searchSetDistance,
|
||||
searchSetTitle,
|
||||
searchSetTab,
|
||||
setDialogActive,
|
||||
mapsLoadMore,
|
||||
dropRoute,
|
||||
modifyRoute,
|
||||
toggleRouteStarred,
|
||||
};
|
||||
|
||||
const MapListDialog = connect(mapStateToProps, mapDispatchToProps)(MapListDialogUnconnected);
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import {
|
||||
routerCancel as routerCancelAction,
|
||||
routerSubmit as routerSubmitAction,
|
||||
} from "~/redux/user/actions";
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions'
|
||||
import classnames from "classnames";
|
||||
|
||||
type Props = {
|
||||
|
@ -11,11 +8,11 @@ type Props = {
|
|||
width: number,
|
||||
is_routing: boolean,
|
||||
|
||||
routerCancel: typeof routerCancelAction,
|
||||
routerSubmit: typeof routerSubmitAction,
|
||||
editorRouterCancel: typeof EDITOR_ACTIONS.editorRouterCancel,
|
||||
editorRouterSubmit: typeof EDITOR_ACTIONS.editorRouterSubmit,
|
||||
}
|
||||
|
||||
const noPoints = ({ routerCancel }: { routerCancel: typeof routerCancelAction }) => (
|
||||
const noPoints = ({ editorRouterCancel }: { editorRouterCancel: typeof EDITOR_ACTIONS.editorRouterCancel }) => (
|
||||
<React.Fragment>
|
||||
<div className="helper router-helper">
|
||||
<div className="helper__text">
|
||||
|
@ -28,7 +25,7 @@ const noPoints = ({ routerCancel }: { routerCancel: typeof routerCancelAction })
|
|||
<div className="helper router-helper">
|
||||
<div className="helper__buttons flex_1">
|
||||
<div className="flex_1" />
|
||||
<div className="button router-helper__button" onClick={routerCancel}>
|
||||
<div className="button router-helper__button" onClick={editorRouterCancel}>
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,7 +33,7 @@ const noPoints = ({ routerCancel }: { routerCancel: typeof routerCancelAction })
|
|||
</React.Fragment>
|
||||
);
|
||||
|
||||
const firstPoint = ({ routerCancel }: { routerCancel: typeof routerCancelAction }) => (
|
||||
const firstPoint = ({ editorRouterCancel }: { editorRouterCancel: typeof EDITOR_ACTIONS.editorRouterCancel }) => (
|
||||
<React.Fragment>
|
||||
<div className="helper router-helper">
|
||||
<div className="helper__text">
|
||||
|
@ -47,7 +44,7 @@ const firstPoint = ({ routerCancel }: { routerCancel: typeof routerCancelAction
|
|||
<div className="helper router-helper">
|
||||
<div className="helper__buttons flex_1">
|
||||
<div className="flex_1" />
|
||||
<div className="button router-helper__button" onClick={routerCancel}>
|
||||
<div className="button router-helper__button" onClick={editorRouterCancel}>
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
|
@ -56,10 +53,10 @@ const firstPoint = ({ routerCancel }: { routerCancel: typeof routerCancelAction
|
|||
);
|
||||
|
||||
const draggablePoints = ({
|
||||
routerCancel, routerSubmit
|
||||
editorRouterCancel, editorRouterSubmit
|
||||
}: {
|
||||
routerCancel: typeof routerCancelAction,
|
||||
routerSubmit: typeof routerSubmitAction,
|
||||
editorRouterCancel: typeof EDITOR_ACTIONS.editorRouterCancel,
|
||||
editorRouterSubmit: typeof EDITOR_ACTIONS.editorRouterSubmit,
|
||||
}) => (
|
||||
<React.Fragment>
|
||||
<div className="helper">
|
||||
|
@ -71,10 +68,10 @@ const draggablePoints = ({
|
|||
<div className="helper router-helper">
|
||||
<div className="helper__buttons button-group flex_1">
|
||||
<div className="flex_1" />
|
||||
<div className="button button_red router-helper__button" onClick={routerCancel}>
|
||||
<div className="button button_red router-helper__button" onClick={editorRouterCancel}>
|
||||
Отмена
|
||||
</div>
|
||||
<div className="button primary router-helper__button" onClick={routerSubmit}>
|
||||
<div className="button primary router-helper__button" onClick={editorRouterSubmit}>
|
||||
Применить
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,13 +80,13 @@ const draggablePoints = ({
|
|||
);
|
||||
|
||||
export const RouterDialog = ({
|
||||
routerPoints, routerCancel, routerSubmit, width, is_routing,
|
||||
routerPoints, editorRouterCancel, editorRouterSubmit, width, is_routing,
|
||||
}: Props) => (
|
||||
<div className="control-dialog" style={{ width }}>
|
||||
<div className={classnames('save-loader', { active: is_routing })} />
|
||||
|
||||
{!routerPoints && noPoints({ routerCancel })}
|
||||
{routerPoints === 1 && firstPoint({ routerCancel })}
|
||||
{routerPoints >= 2 && draggablePoints({ routerCancel, routerSubmit })}
|
||||
{!routerPoints && noPoints({ editorRouterCancel })}
|
||||
{routerPoints === 1 && firstPoint({ editorRouterCancel })}
|
||||
{routerPoints >= 2 && draggablePoints({ editorRouterCancel, editorRouterSubmit })}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -10,17 +10,17 @@ import classnames from 'classnames';
|
|||
import ExpandableTextarea from 'react-expandable-textarea';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectMap } from '~/redux/map/selectors';
|
||||
import { selectUser } from '~/redux/user/selectors';
|
||||
import * as USER_ACTIONS from '~/redux/user/actions';
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
map: selectMap(state),
|
||||
user: selectUser(state),
|
||||
editor: selectEditor(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setMode: USER_ACTIONS.setMode,
|
||||
sendSaveRequest: USER_ACTIONS.sendSaveRequest,
|
||||
editorSetMode: EDITOR_ACTIONS.editorSetMode,
|
||||
editorSendSaveRequest: EDITOR_ACTIONS.editorSendSaveRequest,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { width: number };
|
||||
|
@ -33,14 +33,14 @@ interface State {
|
|||
}
|
||||
|
||||
class SaveDialogUnconnected extends React.Component<Props, State> {
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
address: props.address || '',
|
||||
title: props.title || '',
|
||||
is_public: props.is_public || false,
|
||||
description: props.description || '',
|
||||
address: props.map.address || '',
|
||||
title: props.map.title || '',
|
||||
is_public: props.map.is_public || false,
|
||||
description: props.map.description || '',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -57,16 +57,18 @@ class SaveDialogUnconnected extends React.Component<Props, State> {
|
|||
|
||||
setTitle = ({ target: { value } }) =>
|
||||
this.setState({ title: (value && value.substr(0, 64)) || '' });
|
||||
|
||||
setAddress = ({ target: { value } }) =>
|
||||
this.setState({ address: (value && value.substr(0, 32)) || '' });
|
||||
|
||||
setDescription = ({ target: { value } }) =>
|
||||
this.setState({ description: (value && value.substr(0, 256)) || '' });
|
||||
|
||||
sendSaveRequest = (e, force = false) => {
|
||||
editorSendSaveRequest = (e, force = false) => {
|
||||
const { title, is_public, description } = this.state;
|
||||
const address = this.getAddress();
|
||||
|
||||
this.props.sendSaveRequest({
|
||||
this.props.editorSendSaveRequest({
|
||||
title,
|
||||
address,
|
||||
force,
|
||||
|
@ -74,9 +76,10 @@ class SaveDialogUnconnected extends React.Component<Props, State> {
|
|||
description,
|
||||
});
|
||||
};
|
||||
forceSaveRequest = e => this.sendSaveRequest(e, true);
|
||||
|
||||
cancelSaving = () => this.props.setMode(MODES.NONE);
|
||||
forceSaveRequest = e => this.editorSendSaveRequest(e, true);
|
||||
|
||||
cancelSaving = () => this.props.editorSetMode(MODES.NONE);
|
||||
|
||||
onCopy = e => {
|
||||
e.preventDefault();
|
||||
|
@ -91,7 +94,7 @@ class SaveDialogUnconnected extends React.Component<Props, State> {
|
|||
render() {
|
||||
const { title, is_public, description } = this.state;
|
||||
const {
|
||||
user: { save_error, save_finished, save_overwriting, save_loading },
|
||||
editor: { save_error, save_finished, save_overwriting, save_loading },
|
||||
width,
|
||||
} = this.props;
|
||||
const { host, protocol } = getUrlData();
|
||||
|
@ -157,7 +160,7 @@ class SaveDialogUnconnected extends React.Component<Props, State> {
|
|||
</div>
|
||||
)}
|
||||
{!save_finished && !save_overwriting && (
|
||||
<div className="button primary" onClick={this.sendSaveRequest}>
|
||||
<div className="button primary" onClick={this.editorSendSaveRequest}>
|
||||
Сохранить
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUserRenderer } from '~/redux/user/selectors';
|
||||
import { selectEditorRenderer } from '~/redux/editor/selectors';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
renderer: selectUserRenderer(state),
|
||||
renderer: selectEditorRenderer(state),
|
||||
});
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & {};
|
||||
|
|
|
@ -1,39 +1,44 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
import { STICKERS } from '~/constants/stickers';
|
||||
import { setActiveSticker as setActiveStickerAction } from "~/redux/user/actions";
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
interface Props {
|
||||
setActiveSticker: typeof setActiveStickerAction,
|
||||
width: number,
|
||||
}
|
||||
const mapStateToProps = () => ({});
|
||||
const mapDispatchToProps = {
|
||||
editorSetActiveSticker: EDITOR_ACTIONS.editorSetActiveSticker,
|
||||
};
|
||||
|
||||
export const StickersDialog = ({ setActiveSticker, width }: Props) => (
|
||||
type Props = ReturnType<typeof mapStateToProps> &
|
||||
typeof mapDispatchToProps & {
|
||||
width: number;
|
||||
};
|
||||
|
||||
const StickersDialogUnconnected = ({ editorSetActiveSticker, width }: Props) => (
|
||||
<div className="control-dialog control-dialog-big" style={{ width }}>
|
||||
<div className="helper stickers-helper">
|
||||
{
|
||||
Object.keys(STICKERS).map(set => (
|
||||
<div key={set}>
|
||||
<div className="stickers-set-title">{STICKERS[set].title || null}</div>
|
||||
<div className="stickers-grid">
|
||||
{
|
||||
Object.keys(STICKERS[set].layers).map(sticker => (
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(${STICKERS[set].url})`,
|
||||
backgroundPosition: `${-STICKERS[set].layers[sticker].off * 48}px 50%`,
|
||||
}}
|
||||
className="sticker-preview"
|
||||
key={`${set}-${sticker}`}
|
||||
onClick={() => setActiveSticker({ set, sticker })}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
{Object.keys(STICKERS).map(set => (
|
||||
<div key={set}>
|
||||
<div className="stickers-set-title">{STICKERS[set].title || null}</div>
|
||||
<div className="stickers-grid">
|
||||
{Object.keys(STICKERS[set].layers).map(sticker => (
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(${STICKERS[set].url})`,
|
||||
backgroundPosition: `${-STICKERS[set].layers[sticker].off * 48}px 50%`,
|
||||
}}
|
||||
className="sticker-preview"
|
||||
key={`${set}-${sticker}`}
|
||||
onClick={() => editorSetActiveSticker({ set, sticker })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const StickersDialog = connect(mapStateToProps, mapDispatchToProps)(StickersDialogUnconnected);
|
||||
|
||||
export { StickersDialog };
|
|
@ -5,11 +5,11 @@ import classnames from 'classnames';
|
|||
import { getStyle } from '~/utils/dom';
|
||||
import { nearestInt } from '~/utils/geom';
|
||||
import { parseDesc } from '~/utils/format';
|
||||
import { selectUser } from '~/redux/user/selectors';
|
||||
import { selectMap } from '~/redux/map/selectors';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
user: selectUser(state),
|
||||
editor: selectEditor(state),
|
||||
map: selectMap(state),
|
||||
});
|
||||
|
||||
|
@ -80,7 +80,7 @@ export class TitleDialogUnconnected extends React.PureComponent<Props, State> {
|
|||
|
||||
render() {
|
||||
const {
|
||||
user: { editing },
|
||||
editor: { editing },
|
||||
map: { title, description },
|
||||
} = this.props;
|
||||
const { raised, height, height_raised } = this.state;
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
// flow
|
||||
import React from 'react';
|
||||
import { toHours } from '~/utils/format';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import { connect } from 'react-redux';
|
||||
// import Slider from 'rc-slider';
|
||||
import Slider from 'rc-slider/lib/Slider';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { setSpeed } from '~/redux/user/actions';
|
||||
import { IRootState } from "~/redux/user";
|
||||
import { editorSetSpeed } from '~/redux/editor/actions';
|
||||
import { Tooltip } from "~/components/panels/Tooltip";
|
||||
import { isMobile } from "~/utils/window";
|
||||
import { IState } from '~/redux/store';
|
||||
|
||||
interface Props extends IRootState {
|
||||
setSpeed: typeof setSpeed,
|
||||
function mapStateToProps(state) {
|
||||
const {
|
||||
editor: { distance, estimated, speed },
|
||||
}: IState = state;
|
||||
|
||||
return { distance, estimated, speed };
|
||||
}
|
||||
|
||||
const mapDispatchToProps = { editorSetSpeed };
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||
|
||||
interface State {
|
||||
dialogOpened: boolean,
|
||||
}
|
||||
|
@ -68,7 +73,7 @@ class Component extends React.PureComponent<Props, State> {
|
|||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={this.props.setSpeed}
|
||||
onChange={this.props.editorSetSpeed}
|
||||
defaultValue={15}
|
||||
value={speed}
|
||||
marks={marks}
|
||||
|
@ -81,18 +86,6 @@ class Component extends React.PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const {
|
||||
user: { distance, estimated, speed },
|
||||
} = state;
|
||||
|
||||
return { distance, estimated, speed };
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
setSpeed,
|
||||
}, dispatch);
|
||||
|
||||
export const DistanceBar = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
|
|
|
@ -12,29 +12,13 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { ProviderDialog } from '~/components/dialogs/ProviderDialog';
|
||||
import { ShotPrefetchDialog } from '~/components/dialogs/ShotPrefetchDialog';
|
||||
import { selectUserMode } from '~/redux/user/selectors';
|
||||
import { selectEditorMode } from '~/redux/editor/selectors';
|
||||
|
||||
const mapStateToProps = state => ({ mode: selectUserMode(state) });
|
||||
|
||||
// const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
// routerCancel: USER_ACTIONS.routerCancel,
|
||||
// routerSubmit: USER_ACTIONS.routerSubmit,
|
||||
// setActiveSticker: USER_ACTIONS.setActiveSticker,
|
||||
// clearStickers: USER_ACTIONS.clearStickers,
|
||||
// clearPoly: USER_ACTIONS.clearPoly,
|
||||
// clearAll: USER_ACTIONS.clearAll,
|
||||
// clearCancel: USER_ACTIONS.clearCancel,
|
||||
// stopEditing: USER_ACTIONS.stopEditing,
|
||||
// setEditing: USER_ACTIONS.setEditing,
|
||||
// setMode: USER_ACTIONS.setMode,
|
||||
// sendSaveRequest: USER_ACTIONS.sendSaveRequest,
|
||||
// changeProvider: USER_ACTIONS.changeProvider,
|
||||
// mapSetLogo: MAP_ACTIONS.mapSetLogo,
|
||||
// }, dispatch);
|
||||
const mapStateToProps = state => ({ mode: selectEditorMode(state) });
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & {
|
||||
width: number;
|
||||
};
|
||||
width: number;
|
||||
};
|
||||
|
||||
const DIALOG_CONTENTS: { [x: string]: any } = {
|
||||
[MODES.ROUTER]: RouterDialog,
|
||||
|
@ -47,12 +31,9 @@ const DIALOG_CONTENTS: { [x: string]: any } = {
|
|||
[MODES.SHOT_PREFETCH]: ShotPrefetchDialog,
|
||||
};
|
||||
|
||||
export const Component = (props: Props) =>
|
||||
props.mode && DIALOG_CONTENTS[props.mode]
|
||||
? createElement(DIALOG_CONTENTS[props.mode])
|
||||
: null;
|
||||
const EditorDialogUnconnected = (props: Props) =>
|
||||
props.mode && DIALOG_CONTENTS[props.mode] ? createElement(DIALOG_CONTENTS[props.mode]) : null;
|
||||
|
||||
export const EditorDialog = connect(
|
||||
mapStateToProps
|
||||
// mapDispatchToProps
|
||||
)(Component);
|
||||
const EditorDialog = connect(mapStateToProps)(EditorDialogUnconnected);
|
||||
|
||||
export { EditorDialog };
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import classnames from 'classnames';
|
||||
|
||||
|
@ -6,21 +6,34 @@ import { Icon } from '~/components/panels/Icon';
|
|||
import { EditorDialog } from '~/components/panels/EditorDialog';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { setMode, startEditing, stopEditing, takeAShot, keyPressed } from '~/redux/user/actions';
|
||||
import { IRootState } from "~/redux/user";
|
||||
import { Tooltip } from "~/components/panels/Tooltip";
|
||||
import {
|
||||
editorSetMode,
|
||||
editorStartEditing,
|
||||
editorStopEditing,
|
||||
editorTakeAShot,
|
||||
editorKeyPressed,
|
||||
} from '~/redux/editor/actions';
|
||||
import { Tooltip } from '~/components/panels/Tooltip';
|
||||
import { IState } from '~/redux/store';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
|
||||
interface Props extends IRootState {
|
||||
routing: IRootState['features']['routing'],
|
||||
setMode: typeof setMode,
|
||||
startEditing: typeof startEditing,
|
||||
stopEditing: typeof stopEditing,
|
||||
keyPressed: EventListenerOrEventListenerObject,
|
||||
}
|
||||
const mapStateToProps = (state: IState) => ({
|
||||
editor: selectEditor(state),
|
||||
});
|
||||
|
||||
class Component extends React.PureComponent<Props, void> {
|
||||
const mapDispatchToProps = {
|
||||
editorSetMode,
|
||||
editorStartEditing,
|
||||
editorStopEditing,
|
||||
editorTakeAShot,
|
||||
editorKeyPressed,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||
|
||||
class EditorPanelUnconnected extends PureComponent<Props, void> {
|
||||
componentDidMount() {
|
||||
window.addEventListener('keydown', this.props.keyPressed);
|
||||
window.addEventListener('keydown', this.props.editorKeyPressed as any);
|
||||
|
||||
const obj = document.getElementById('control-dialog');
|
||||
const { width } = this.panel.getBoundingClientRect();
|
||||
|
@ -33,29 +46,38 @@ class Component extends React.PureComponent<Props, void> {
|
|||
panel: HTMLElement = null;
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('keydown', this.props.keyPressed);
|
||||
window.removeEventListener('keydown', this.props.editorKeyPressed as any);
|
||||
}
|
||||
|
||||
startPolyMode = () => this.props.setMode(MODES.POLY);
|
||||
startStickerMode = () => this.props.setMode(MODES.STICKERS_SELECT);
|
||||
startRouterMode = () => this.props.setMode(MODES.ROUTER);
|
||||
startTrashMode = () => this.props.setMode(MODES.TRASH);
|
||||
startPolyMode = () => this.props.editorSetMode(MODES.POLY);
|
||||
startStickerMode = () => this.props.editorSetMode(MODES.STICKERS_SELECT);
|
||||
startRouterMode = () => this.props.editorSetMode(MODES.ROUTER);
|
||||
startTrashMode = () => this.props.editorSetMode(MODES.TRASH);
|
||||
startSaveMode = () => {
|
||||
// if (!this.props.changed) return;
|
||||
this.props.setMode(MODES.SAVE);
|
||||
this.props.editorSetMode(MODES.SAVE);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
mode, changed, editing, routing,
|
||||
editor: {
|
||||
mode,
|
||||
changed,
|
||||
editing,
|
||||
features: { routing },
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classnames('panel right', { active: editing })} ref={el => { this.panel = el; }}>
|
||||
<div
|
||||
className={classnames('panel right', { active: editing })}
|
||||
ref={el => {
|
||||
this.panel = el;
|
||||
}}
|
||||
>
|
||||
<div className="control-bar control-bar-padded">
|
||||
{
|
||||
routing &&
|
||||
{routing && (
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.ROUTER })}
|
||||
onClick={this.startRouterMode}
|
||||
|
@ -63,8 +85,7 @@ class Component extends React.PureComponent<Props, void> {
|
|||
<Tooltip>Автоматический маршрут</Tooltip>
|
||||
<Icon icon="icon-route-2" />
|
||||
</button>
|
||||
}
|
||||
|
||||
)}
|
||||
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.POLY })}
|
||||
|
@ -75,13 +96,14 @@ class Component extends React.PureComponent<Props, void> {
|
|||
</button>
|
||||
|
||||
<button
|
||||
className={classnames({ active: (mode === MODES.STICKERS || mode === MODES.STICKERS_SELECT) })}
|
||||
className={classnames({
|
||||
active: mode === MODES.STICKERS || mode === MODES.STICKERS_SELECT,
|
||||
})}
|
||||
onClick={this.startStickerMode}
|
||||
>
|
||||
<Tooltip>Точки маршрута</Tooltip>
|
||||
<Icon icon="icon-sticker-3" />
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="control-sep" />
|
||||
|
@ -99,10 +121,7 @@ class Component extends React.PureComponent<Props, void> {
|
|||
<div className="control-sep" />
|
||||
|
||||
<div className="control-bar">
|
||||
<button
|
||||
className="highlighted cancel"
|
||||
onClick={this.props.stopEditing}
|
||||
>
|
||||
<button className="highlighted cancel" onClick={this.props.editorStopEditing}>
|
||||
<Icon icon="icon-cancel-1" />
|
||||
</button>
|
||||
|
||||
|
@ -114,59 +133,21 @@ class Component extends React.PureComponent<Props, void> {
|
|||
<Icon icon="icon-check-1" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={classnames('panel right', { active: !editing })}>
|
||||
<div className="control-bar">
|
||||
<button className="primary single" onClick={this.props.startEditing}>
|
||||
<button className="primary single" onClick={this.props.editorStartEditing}>
|
||||
<Icon icon="icon-route-2" />
|
||||
<span>
|
||||
РЕДАКТИРОВАТЬ
|
||||
</span>
|
||||
<span>РЕДАКТИРОВАТЬ</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorDialog
|
||||
width={((this.panel && this.panel.getBoundingClientRect().width) || 0)}
|
||||
/>
|
||||
|
||||
<EditorDialog width={(this.panel && this.panel.getBoundingClientRect().width) || 0} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const {
|
||||
user: {
|
||||
editing,
|
||||
mode,
|
||||
changed,
|
||||
features: {
|
||||
routing,
|
||||
}
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
editing,
|
||||
mode,
|
||||
changed,
|
||||
routing,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
setMode,
|
||||
// setLogo,
|
||||
startEditing,
|
||||
stopEditing,
|
||||
takeAShot,
|
||||
keyPressed,
|
||||
}, dispatch);
|
||||
|
||||
export const EditorPanel = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Component);
|
||||
export const EditorPanel = connect(mapStateToProps, mapDispatchToProps)(EditorPanelUnconnected);
|
||||
|
|
|
@ -1,36 +1,34 @@
|
|||
// flow
|
||||
import React, { useCallback } from 'react';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import { PROVIDERS } from '~/constants/providers';
|
||||
import { LOGOS } from '~/constants/logos';
|
||||
import * as USER_ACTIONS from '~/redux/user/actions';
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { IRootState } from '~/redux/user';
|
||||
|
||||
import { Tooltip } from '~/components/panels/Tooltip';
|
||||
import { selectMap } from '~/redux/map/selectors';
|
||||
import { selectUser } from '~/redux/user/selectors';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
map: selectMap(state),
|
||||
user: selectUser(state),
|
||||
editor: selectEditor(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setMode: USER_ACTIONS.setMode,
|
||||
editorSetMode: EDITOR_ACTIONS.editorSetMode,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||
|
||||
const TopRightPanelUnconnected = ({
|
||||
map: { provider, logo },
|
||||
user: { markers_shown, editing },
|
||||
setMode,
|
||||
editor: { markers_shown, editing },
|
||||
editorSetMode,
|
||||
}: Props) => {
|
||||
const startProviderMode = useCallback(() => setMode(MODES.PROVIDER), [setMode]);
|
||||
const startLogoMode = useCallback(() => setMode(MODES.LOGO), [setMode]);
|
||||
const clearMode = useCallback(() => setMode(MODES.NONE), [setMode]);
|
||||
const startProviderMode = useCallback(() => editorSetMode(MODES.PROVIDER), [editorSetMode]);
|
||||
const startLogoMode = useCallback(() => editorSetMode(MODES.LOGO), [editorSetMode]);
|
||||
const clearMode = useCallback(() => editorSetMode(MODES.NONE), [editorSetMode]);
|
||||
|
||||
return (
|
||||
<div className="status-panel top right">
|
||||
|
|
|
@ -4,35 +4,41 @@ import { GuestButton } from '~/components/user/GuestButton';
|
|||
import { DEFAULT_USER, ROLES } from '~/constants/auth';
|
||||
import { UserButton } from '~/components/user/UserButton';
|
||||
import { UserMenu } from '~/components/user/UserMenu';
|
||||
import { setUser, userLogout, gotVkUser, openMapDialog } from '~/redux/user/actions';
|
||||
import {
|
||||
setUser,
|
||||
userLogout,
|
||||
takeAShot,
|
||||
setDialog,
|
||||
gotVkUser,
|
||||
setDialogActive,
|
||||
openMapDialog,
|
||||
getGPXTrack,
|
||||
} from '~/redux/user/actions';
|
||||
editorTakeAShot,
|
||||
editorSetDialog,
|
||||
editorSetDialogActive,
|
||||
editorGetGPXTrack,
|
||||
} from '~/redux/editor/actions';
|
||||
import { connect } from 'react-redux';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { CLIENT } from '~/config/frontend';
|
||||
import { DIALOGS, TABS } from '~/constants/dialogs';
|
||||
import { IRootState } from '~/redux/user';
|
||||
import { Tooltip } from '~/components/panels/Tooltip';
|
||||
import { TitleDialog } from '~/components/dialogs/TitleDialog';
|
||||
|
||||
interface Props extends IRootState {
|
||||
userLogout: typeof userLogout;
|
||||
setDialog: typeof setDialog;
|
||||
setDialogActive: typeof setDialogActive;
|
||||
gotVkUser: typeof gotVkUser;
|
||||
takeAShot: typeof takeAShot;
|
||||
openMapDialog: typeof openMapDialog;
|
||||
getGPXTrack: typeof getGPXTrack;
|
||||
}
|
||||
const mapStateToProps = ({ user: { user }, editor: { dialog, dialog_active, is_empty } }) => ({
|
||||
dialog,
|
||||
dialog_active,
|
||||
user,
|
||||
is_empty,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setUser,
|
||||
userLogout,
|
||||
editorTakeAShot,
|
||||
editorSetDialog,
|
||||
gotVkUser,
|
||||
editorSetDialogActive,
|
||||
openMapDialog,
|
||||
editorGetGPXTrack,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||
|
||||
interface State {
|
||||
menuOpened: boolean;
|
||||
|
@ -84,8 +90,8 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
|
|||
|
||||
openAppInfoDialog = () => {
|
||||
this.setMenuOpened();
|
||||
this.props.setDialog(DIALOGS.APP_INFO);
|
||||
this.props.setDialogActive(this.props.dialog !== DIALOGS.APP_INFO);
|
||||
this.props.editorSetDialog(DIALOGS.APP_INFO);
|
||||
this.props.editorSetDialogActive(this.props.dialog !== DIALOGS.APP_INFO);
|
||||
};
|
||||
|
||||
openOauthFrame = () => {
|
||||
|
@ -143,7 +149,7 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
|
|||
<div className="control-sep" />
|
||||
|
||||
<div className="control-bar">
|
||||
<button className={classnames({ active: false })} onClick={this.props.takeAShot}>
|
||||
<button className={classnames({ active: false })} onClick={this.props.editorTakeAShot}>
|
||||
<Tooltip>Снимок карты</Tooltip>
|
||||
<Icon icon="icon-shot-4" />
|
||||
</button>
|
||||
|
@ -153,7 +159,10 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
|
|||
<div className="control-sep" />
|
||||
|
||||
<div className="control-bar">
|
||||
<button className={classnames({ active: false })} onClick={this.props.getGPXTrack}>
|
||||
<button
|
||||
className={classnames({ active: false })}
|
||||
onClick={this.props.editorGetGPXTrack}
|
||||
>
|
||||
<Tooltip>Экспорт GPX</Tooltip>
|
||||
<Icon icon="icon-gpx-1" />
|
||||
</button>
|
||||
|
@ -166,24 +175,6 @@ export class UserPanelUnconnected extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ user: { dialog, dialog_active, user, is_empty } }) => ({
|
||||
dialog,
|
||||
dialog_active,
|
||||
user,
|
||||
is_empty,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setUser,
|
||||
userLogout,
|
||||
takeAShot,
|
||||
setDialog,
|
||||
gotVkUser,
|
||||
setDialogActive,
|
||||
openMapDialog,
|
||||
getGPXTrack,
|
||||
};
|
||||
|
||||
const UserPanel = connect(mapStateToProps, mapDispatchToProps)(UserPanelUnconnected);
|
||||
|
||||
export { UserPanel };
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
import React from 'react';
|
||||
|
||||
import { hideRenderer, cropAShot } from '~/redux/user/actions';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import Croppr from 'croppr';
|
||||
import 'croppr/dist/croppr.css';
|
||||
import { LOGOS } from '~/constants/logos';
|
||||
import { RendererPanel } from '~/components/panels/RendererPanel';
|
||||
import { IRootState } from "~/redux/user";
|
||||
import { IRoute } from '~/redux/map/types';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||
import { selectMap } from '~/redux/map/selectors';
|
||||
|
||||
type Props = {
|
||||
data: IRootState['renderer']['data'],
|
||||
logo: IRoute['logo'],
|
||||
hideRenderer: typeof hideRenderer,
|
||||
cropAShot: typeof cropAShot,
|
||||
const mapStateToProps = state => ({
|
||||
editor: selectEditor(state),
|
||||
map: selectMap(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
editorHideRenderer: EDITOR_ACTIONS.editorHideRenderer,
|
||||
editorCropAShot: EDITOR_ACTIONS.editorCropAShot,
|
||||
};
|
||||
|
||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||
|
||||
type State = {
|
||||
opacity: number,
|
||||
};
|
||||
|
@ -47,7 +51,7 @@ class Component extends React.Component<Props, State> {
|
|||
this.logo.style.transform = `scale(${scale})`;
|
||||
|
||||
this.logoImg = document.createElement('img');
|
||||
if (this.props.logo && LOGOS[this.props.logo][1]) this.logoImg.src = LOGOS[this.props.logo][1];
|
||||
if (this.props.map.logo && LOGOS[this.props.map.logo][1]) this.logoImg.src = LOGOS[this.props.map.logo][1];
|
||||
|
||||
this.logo.append(this.logoImg);
|
||||
regionEl.append(this.logo);
|
||||
|
@ -58,10 +62,10 @@ class Component extends React.Component<Props, State> {
|
|||
image: HTMLImageElement;
|
||||
logoImg: HTMLImageElement;
|
||||
|
||||
getImage = () => this.props.cropAShot(this.croppr.getValue());
|
||||
getImage = () => this.props.editorCropAShot(this.croppr.getValue());
|
||||
|
||||
render() {
|
||||
const { data } = this.props;
|
||||
const { data } = this.props.editor.renderer;
|
||||
const { opacity } = this.state;
|
||||
const { innerWidth, innerHeight } = window;
|
||||
const padding = 30;
|
||||
|
@ -95,7 +99,7 @@ class Component extends React.Component<Props, State> {
|
|||
</div>
|
||||
|
||||
<RendererPanel
|
||||
onCancel={this.props.hideRenderer}
|
||||
onCancel={this.props.editorHideRenderer}
|
||||
onSubmit={this.getImage}
|
||||
/>
|
||||
</div>
|
||||
|
@ -103,12 +107,4 @@ class Component extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
const mapStateToProps = state => ({ ...state.user.renderer, logo: state.user.logo });
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({
|
||||
hideRenderer,
|
||||
cropAShot,
|
||||
}, dispatch);
|
||||
|
||||
export const Renderer = connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||
|
|
|
@ -11,7 +11,7 @@ export interface IUser {
|
|||
role: IRoles[keyof IRoles];
|
||||
routes: {};
|
||||
success: boolean;
|
||||
id?: number;
|
||||
id?: string;
|
||||
uid: string;
|
||||
token?: string;
|
||||
photo: string;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
import { EditorPanel } from '~/components/panels/EditorPanel';
|
||||
|
@ -9,8 +8,7 @@ import { bindActionCreators } from 'redux';
|
|||
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { Renderer } from '~/components/renderer/Renderer';
|
||||
import { hideRenderer, setDialogActive } from '~/redux/user/actions';
|
||||
import { Cursor } from '~/components/Cursor';
|
||||
import { editorHideRenderer, editorSetDialogActive } from '~/redux/editor/actions';
|
||||
import { LeftDialog } from '~/containers/LeftDialog';
|
||||
import { TopLeftPanel } from '~/components/panels/TopLeftPanel';
|
||||
import { TopRightPanel } from '~/components/panels/TopRightPanel';
|
||||
|
@ -19,18 +17,19 @@ import { IStickerPack } from '~/constants/stickers';
|
|||
import { IDialogs } from '~/constants/dialogs';
|
||||
|
||||
import { Map } from '~/containers/map/Map';
|
||||
import { IRootReducer } from '~/redux/user';
|
||||
import { IEditorState } from '~/redux/editor';
|
||||
import { IState } from '~/redux/store';
|
||||
|
||||
type Props = {
|
||||
sticker: string;
|
||||
renderer_active: boolean;
|
||||
|
||||
mode: IRootReducer['mode'];
|
||||
mode: IEditorState['mode'];
|
||||
dialog: keyof IDialogs;
|
||||
dialog_active: boolean;
|
||||
set: keyof IStickerPack;
|
||||
hideRenderer: typeof hideRenderer;
|
||||
setDialogActive: typeof setDialogActive;
|
||||
editorHideRenderer: typeof editorHideRenderer;
|
||||
editorSetDialogActive: typeof editorSetDialogActive;
|
||||
};
|
||||
|
||||
const Component = (props: Props) => (
|
||||
|
@ -45,26 +44,26 @@ const Component = (props: Props) => (
|
|||
<LeftDialog
|
||||
dialog={props.dialog}
|
||||
dialog_active={props.dialog_active}
|
||||
setDialogActive={props.setDialogActive}
|
||||
editorSetDialogActive={props.editorSetDialogActive}
|
||||
/>
|
||||
|
||||
<LogoPreview />
|
||||
|
||||
<Map />
|
||||
|
||||
{props.renderer_active && <Renderer onClick={props.hideRenderer} />}
|
||||
{props.renderer_active && <Renderer onClick={props.editorHideRenderer} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
const mapStateToProps = ({
|
||||
user: {
|
||||
editor: {
|
||||
mode,
|
||||
dialog,
|
||||
dialog_active,
|
||||
renderer,
|
||||
activeSticker: { sticker = null, set = null },
|
||||
},
|
||||
}) => ({
|
||||
}: IState) => ({
|
||||
renderer_active: renderer.renderer_active,
|
||||
mode,
|
||||
dialog,
|
||||
|
@ -74,5 +73,5 @@ const mapStateToProps = ({
|
|||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators({ hideRenderer, setDialogActive }, dispatch);
|
||||
bindActionCreators({ editorHideRenderer, editorSetDialogActive }, dispatch);
|
||||
export const App = connect(mapStateToProps, mapDispatchToProps)(hot(module)(Component));
|
||||
|
|
|
@ -4,12 +4,12 @@ import classnames from 'classnames';
|
|||
import { AppInfoDialog } from '~/components/dialogs/AppInfoDialog';
|
||||
import { Icon } from '~/components/panels/Icon';
|
||||
import { MapListDialog } from '~/components/dialogs/MapListDialog';
|
||||
import * as USER_ACTIONS from '~/redux/user/actions';
|
||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||
|
||||
interface Props {
|
||||
dialog: keyof IDialogs;
|
||||
dialog_active: Boolean;
|
||||
setDialogActive: typeof USER_ACTIONS.setDialogActive;
|
||||
editorSetDialogActive: typeof EDITOR_ACTIONS.editorSetDialogActive;
|
||||
}
|
||||
|
||||
const LEFT_DIALOGS = {
|
||||
|
@ -17,7 +17,7 @@ const LEFT_DIALOGS = {
|
|||
[DIALOGS.APP_INFO]: AppInfoDialog,
|
||||
};
|
||||
|
||||
const LeftDialog = ({ dialog, dialog_active, setDialogActive }: Props) => (
|
||||
const LeftDialog = ({ dialog, dialog_active, editorSetDialogActive }: Props) => (
|
||||
<React.Fragment>
|
||||
{Object.keys(LEFT_DIALOGS).map(item => (
|
||||
<div
|
||||
|
@ -26,11 +26,11 @@ const LeftDialog = ({ dialog, dialog_active, setDialogActive }: Props) => (
|
|||
>
|
||||
{dialog && LEFT_DIALOGS[item] && createElement(LEFT_DIALOGS[item], {})}
|
||||
|
||||
<div className="dialog-close-button desktop-only" onClick={() => setDialogActive(false)}>
|
||||
<div className="dialog-close-button desktop-only" onClick={() => editorSetDialogActive(false)}>
|
||||
<Icon icon="icon-cancel-1" />
|
||||
</div>
|
||||
|
||||
<div className="dialog-close-button mobile-only" onClick={() => setDialogActive(false)}>
|
||||
<div className="dialog-close-button mobile-only" onClick={() => editorSetDialogActive(false)}>
|
||||
<Icon icon="icon-chevron-down" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,15 +12,15 @@ import * as MAP_ACTIONS from "~/redux/map/actions";
|
|||
import { Route } from "~/containers/map/Route";
|
||||
import { TileLayer } from "~/containers/map/TileLayer";
|
||||
import { Stickers } from "~/containers/map/Stickers";
|
||||
import { selectUserEditing } from '~/redux/user/selectors'
|
||||
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import { selectEditorEditing } from "~/redux/editor/selectors";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
provider: selectMapProvider(state),
|
||||
route: selectMapRoute(state),
|
||||
stickers: selectMapStickers(state),
|
||||
editing: selectUserEditing(state),
|
||||
editing: selectEditorEditing(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
|
120
src/redux/editor/actions.ts
Normal file
120
src/redux/editor/actions.ts
Normal file
|
@ -0,0 +1,120 @@
|
|||
import { EDITOR_ACTIONS } from './constants';
|
||||
import { IEditorState } from '.';
|
||||
import { IRoute } from '../map/types';
|
||||
import { KeyboardEvent } from 'react';
|
||||
|
||||
export const editorSetEditing = (editing: IEditorState['editing']) => ({
|
||||
type: EDITOR_ACTIONS.SET_EDITING,
|
||||
editing,
|
||||
});
|
||||
export const editorSetMode = (mode: IEditorState['mode']) => ({
|
||||
type: EDITOR_ACTIONS.SET_MODE,
|
||||
mode,
|
||||
});
|
||||
export const editorSetDistance = (distance: IEditorState['distance']) => ({
|
||||
type: EDITOR_ACTIONS.SET_DISTANCE,
|
||||
distance,
|
||||
});
|
||||
export const editorSetChanged = (changed: IEditorState['changed']) => ({
|
||||
type: EDITOR_ACTIONS.SET_CHANGED,
|
||||
changed,
|
||||
});
|
||||
export const editorSetSpeed = speed => ({ type: EDITOR_ACTIONS.SET_SPEED, speed });
|
||||
|
||||
export const editorStartEditing = () => ({ type: EDITOR_ACTIONS.START_EDITING });
|
||||
export const editorStopEditing = () => ({ type: EDITOR_ACTIONS.STOP_EDITING });
|
||||
|
||||
export const editorRouterCancel = () => ({ type: EDITOR_ACTIONS.ROUTER_CANCEL });
|
||||
export const editorRouterSubmit = () => ({ type: EDITOR_ACTIONS.ROUTER_SUBMIT });
|
||||
|
||||
export const editorClearPoly = () => ({ type: EDITOR_ACTIONS.CLEAR_POLY });
|
||||
export const editorClearStickers = () => ({ type: EDITOR_ACTIONS.CLEAR_STICKERS });
|
||||
export const editorClearAll = () => ({ type: EDITOR_ACTIONS.CLEAR_ALL });
|
||||
export const editorClearCancel = () => ({ type: EDITOR_ACTIONS.CLEAR_CANCEL });
|
||||
|
||||
export const editorSendSaveRequest = (payload: {
|
||||
title: IRoute['title'];
|
||||
address: IRoute['address'];
|
||||
is_public: IRoute['is_public'];
|
||||
description: IRoute['description'];
|
||||
force: boolean;
|
||||
}) => ({
|
||||
type: EDITOR_ACTIONS.SEND_SAVE_REQUEST,
|
||||
...payload,
|
||||
});
|
||||
|
||||
export const editorResetSaveDialog = () => ({ type: EDITOR_ACTIONS.RESET_SAVE_DIALOG });
|
||||
|
||||
export const editorSetSaveLoading = (save_loading: IEditorState['save_loading']) => ({
|
||||
type: EDITOR_ACTIONS.SET_SAVE_LOADING,
|
||||
save_loading,
|
||||
});
|
||||
|
||||
export const editorSetSaveSuccess = (payload: {
|
||||
address: IRoute['address'];
|
||||
title: IRoute['address'];
|
||||
is_public: IRoute['is_public'];
|
||||
description: IRoute['description'];
|
||||
|
||||
save_error: string;
|
||||
}) => ({ type: EDITOR_ACTIONS.SET_SAVE_SUCCESS, ...payload });
|
||||
|
||||
export const editorSetSaveError = (save_error: IEditorState['save_error']) => ({
|
||||
type: EDITOR_ACTIONS.SET_SAVE_ERROR,
|
||||
save_error,
|
||||
});
|
||||
export const editorSetSaveOverwrite = () => ({ type: EDITOR_ACTIONS.SET_SAVE_OVERWRITE });
|
||||
|
||||
export const editorHideRenderer = () => ({ type: EDITOR_ACTIONS.HIDE_RENDERER });
|
||||
export const editorSetRenderer = payload => ({ type: EDITOR_ACTIONS.SET_RENDERER, payload });
|
||||
export const editorTakeAShot = () => ({ type: EDITOR_ACTIONS.TAKE_A_SHOT });
|
||||
export const editorCropAShot = payload => ({ type: EDITOR_ACTIONS.CROP_A_SHOT, ...payload });
|
||||
export const editorSetDialog = dialog => ({ type: EDITOR_ACTIONS.SET_DIALOG, dialog });
|
||||
export const editorSetDialogActive = dialog_active => ({
|
||||
type: EDITOR_ACTIONS.SET_DIALOG_ACTIVE,
|
||||
dialog_active,
|
||||
});
|
||||
export const editorSetReady = ready => ({ type: EDITOR_ACTIONS.SET_READY, ready });
|
||||
|
||||
export const editorGetGPXTrack = () => ({ type: EDITOR_ACTIONS.GET_GPX_TRACK });
|
||||
export const editorSetMarkersShown = markers_shown => ({
|
||||
type: EDITOR_ACTIONS.SET_MARKERS_SHOWN,
|
||||
markers_shown,
|
||||
});
|
||||
export const editorSetIsEmpty = is_empty => ({ type: EDITOR_ACTIONS.SET_IS_EMPTY, is_empty });
|
||||
export const editorSetFeature = (features: { [x: string]: boolean }) => ({
|
||||
type: EDITOR_ACTIONS.SET_FEATURE,
|
||||
features,
|
||||
});
|
||||
|
||||
export const editorSetIsRouting = (is_routing: boolean) => ({
|
||||
type: EDITOR_ACTIONS.SET_IS_ROUTING,
|
||||
is_routing,
|
||||
});
|
||||
|
||||
export const editorSetRouterPoints = (routerPoints: IEditorState['routerPoints']) => ({
|
||||
type: EDITOR_ACTIONS.SET_ROUTER_POINTS,
|
||||
routerPoints,
|
||||
});
|
||||
|
||||
export const editorSetActiveSticker = (activeSticker: IEditorState['activeSticker']) => ({
|
||||
type: EDITOR_ACTIONS.SET_ACTIVE_STICKER,
|
||||
activeSticker,
|
||||
});
|
||||
|
||||
export const editorLocationChanged = location => ({
|
||||
type: EDITOR_ACTIONS.LOCATION_CHANGED,
|
||||
location,
|
||||
});
|
||||
|
||||
export const editorKeyPressed = ({
|
||||
key,
|
||||
target: { tagName },
|
||||
}: {
|
||||
key: string;
|
||||
target: { tagName: string };
|
||||
}) => ({
|
||||
type: EDITOR_ACTIONS.KEY_PRESSED,
|
||||
key,
|
||||
target: tagName,
|
||||
});
|
47
src/redux/editor/constants.ts
Normal file
47
src/redux/editor/constants.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
const P = 'EDITOR';
|
||||
|
||||
export const EDITOR_ACTIONS = {
|
||||
SET_EDITING: `${P}-SET_EDITING`,
|
||||
SET_MODE: `${P}-SET_MODE`,
|
||||
SET_DISTANCE: `${P}-SET_DISTANCE`,
|
||||
SET_CHANGED: `${P}-SET_CHANGED`,
|
||||
SET_SPEED: `${P}-SET_SPEED`,
|
||||
SET_ROUTER_POINTS: `${P}-SET_ROUTER_POINTS`,
|
||||
SET_ACTIVE_STICKER: `${P}-SET_ACTIVE_STICKER`,
|
||||
START_EDITING: `${P}-START_EDITING`,
|
||||
STOP_EDITING: `${P}-STOP_EDITING`,
|
||||
ROUTER_CANCEL: `${P}-ROUTER_CANCEL`,
|
||||
ROUTER_SUBMIT: `${P}-ROUTER_SUBMIT`,
|
||||
|
||||
CLEAR_POLY: `${P}-CLEAR_POLY`,
|
||||
CLEAR_STICKERS: `${P}-CLEAR_STICKERS`,
|
||||
CLEAR_ALL: `${P}-CLEAR_ALL`,
|
||||
CLEAR_CANCEL: `${P}-CLEAR_CANCEL`,
|
||||
|
||||
SEND_SAVE_REQUEST: `${P}-SEND_SAVE_REQUEST`,
|
||||
SET_SAVE_LOADING: `${P}-SET_SAVE_LOADING`,
|
||||
CANCEL_SAVE_REQUEST: `${P}-CANCEL_SAVE_REQUEST`,
|
||||
RESET_SAVE_DIALOG: `${P}-RESET_SAVE_DIALOG`,
|
||||
|
||||
SET_SAVE_SUCCESS: `${P}-SET_SAVE_SUCCESS`,
|
||||
SET_SAVE_ERROR: `${P}-SET_SAVE_ERROR`,
|
||||
SET_SAVE_OVERWRITE: `${P}-SET_SAVE_OVERWRITE`,
|
||||
|
||||
SHOW_RENDERER: `${P}-SHOW_RENDERER`,
|
||||
HIDE_RENDERER: `${P}-HIDE_RENDERER`,
|
||||
SET_RENDERER: `${P}-SET_RENDERER`,
|
||||
TAKE_A_SHOT: `${P}-TAKE_A_SHOT`,
|
||||
CROP_A_SHOT: `${P}-CROP_A_SHOT`,
|
||||
|
||||
SET_DIALOG: `${P}-SET_DIALOG`,
|
||||
SET_DIALOG_ACTIVE: `${P}-SET_DIALOG_ACTIVE`,
|
||||
LOCATION_CHANGED: `${P}-LOCATION_CHANGED`,
|
||||
SET_READY: `${P}-SET_READY`,
|
||||
|
||||
SET_MARKERS_SHOWN: `${P}-SET_MARKERS_SHOWN`,
|
||||
GET_GPX_TRACK: `${P}-GET_GPX_TRACK`,
|
||||
SET_IS_EMPTY: `${P}-SET_IS_EMPTY`,
|
||||
SET_FEATURE: `${P}-SET_FEATURE`,
|
||||
SET_IS_ROUTING: `${P}-SET_IS_ROUTING`,
|
||||
KEY_PRESSED: `${P}-KEY_PRESSED`,
|
||||
};
|
200
src/redux/editor/handlers.ts
Normal file
200
src/redux/editor/handlers.ts
Normal file
|
@ -0,0 +1,200 @@
|
|||
import { getEstimated } from '~/utils/format';
|
||||
import * as ACTIONS from '~/redux/editor/actions';
|
||||
import { EDITOR_ACTIONS } from '~/redux/editor/constants';
|
||||
import { IEditorState } from '~/redux/editor';
|
||||
import { TIPS } from '~/constants/tips';
|
||||
|
||||
const setEditing = (
|
||||
state,
|
||||
{ editing }: ReturnType<typeof ACTIONS.editorSetEditing>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
editing,
|
||||
});
|
||||
|
||||
const setChanged = (
|
||||
state,
|
||||
{ changed }: ReturnType<typeof ACTIONS.editorSetChanged>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
changed,
|
||||
});
|
||||
|
||||
const setMode = (state, { mode }: ReturnType<typeof ACTIONS.editorSetMode>): IEditorState => ({
|
||||
...state,
|
||||
mode,
|
||||
});
|
||||
|
||||
const setDistance = (
|
||||
state,
|
||||
{ distance }: ReturnType<typeof ACTIONS.editorSetDistance>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
distance,
|
||||
estimated: getEstimated(distance, state.speed),
|
||||
});
|
||||
|
||||
const setRouterPoints = (
|
||||
state,
|
||||
{ routerPoints }: ReturnType<typeof ACTIONS.editorSetRouterPoints>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
routerPoints,
|
||||
});
|
||||
|
||||
const setActiveSticker = (
|
||||
state,
|
||||
{ activeSticker }: ReturnType<typeof ACTIONS.editorSetActiveSticker>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
activeSticker: activeSticker || { set: null, sticker: null },
|
||||
});
|
||||
|
||||
const hideRenderer = (state): IEditorState => ({
|
||||
...state,
|
||||
renderer: { ...state.renderer, renderer_active: false },
|
||||
});
|
||||
|
||||
const setRenderer = (
|
||||
state,
|
||||
{ payload }: ReturnType<typeof ACTIONS.editorSetRenderer>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
renderer: { ...state.renderer, ...payload },
|
||||
});
|
||||
|
||||
const sendSaveRequest = (state): IEditorState => ({
|
||||
...state,
|
||||
save_processing: true,
|
||||
});
|
||||
|
||||
const setSaveError = (
|
||||
state,
|
||||
{ save_error }: ReturnType<typeof ACTIONS.editorSetSaveError>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
save_error,
|
||||
save_finished: false,
|
||||
save_processing: false,
|
||||
});
|
||||
|
||||
const setSaveLoading = (
|
||||
state,
|
||||
{ save_loading }: ReturnType<typeof ACTIONS.editorSetSaveLoading>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
save_loading,
|
||||
});
|
||||
|
||||
const setSaveOverwrite = (state): IEditorState => ({
|
||||
...state,
|
||||
save_overwriting: true,
|
||||
save_finished: false,
|
||||
save_processing: false,
|
||||
save_error: TIPS.SAVE_OVERWRITE,
|
||||
});
|
||||
|
||||
const setSaveSuccess = (
|
||||
state,
|
||||
{ save_error }: ReturnType<typeof ACTIONS.editorSetSaveSuccess>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
save_overwriting: false,
|
||||
save_finished: true,
|
||||
save_processing: false,
|
||||
save_error,
|
||||
});
|
||||
|
||||
const resetSaveDialog = (state): IEditorState => ({
|
||||
...state,
|
||||
save_overwriting: false,
|
||||
save_finished: false,
|
||||
save_processing: false,
|
||||
save_error: '',
|
||||
});
|
||||
|
||||
const setDialog = (state, { dialog }: ReturnType<typeof ACTIONS.editorSetDialog>): IEditorState => ({
|
||||
...state,
|
||||
dialog,
|
||||
});
|
||||
|
||||
const setDialogActive = (
|
||||
state,
|
||||
{ dialog_active }: ReturnType<typeof ACTIONS.editorSetDialogActive>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
dialog_active: dialog_active || !state.dialog_active,
|
||||
});
|
||||
|
||||
const setReady = (state, { ready = true }: ReturnType<typeof ACTIONS.editorSetReady>): IEditorState => ({
|
||||
...state,
|
||||
ready,
|
||||
});
|
||||
|
||||
const setSpeed = (
|
||||
state,
|
||||
{ speed = 15 }: ReturnType<typeof ACTIONS.editorSetSpeed>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
speed,
|
||||
estimated: getEstimated(state.distance, speed),
|
||||
});
|
||||
|
||||
const setMarkersShown = (
|
||||
state,
|
||||
{ markers_shown = true }: ReturnType<typeof ACTIONS.editorSetMarkersShown>
|
||||
): IEditorState => ({ ...state, markers_shown });
|
||||
|
||||
const setIsEmpty = (
|
||||
state,
|
||||
{ is_empty = true }: ReturnType<typeof ACTIONS.editorSetIsEmpty>
|
||||
): IEditorState => ({ ...state, is_empty });
|
||||
|
||||
const setFeature = (
|
||||
state,
|
||||
{ features }: ReturnType<typeof ACTIONS.editorSetFeature>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
features: {
|
||||
...state.features,
|
||||
...features,
|
||||
},
|
||||
});
|
||||
|
||||
const setIsRouting = (
|
||||
state,
|
||||
{ is_routing }: ReturnType<typeof ACTIONS.editorSetIsRouting>
|
||||
): IEditorState => ({
|
||||
...state,
|
||||
is_routing,
|
||||
});
|
||||
|
||||
export const EDITOR_HANDLERS = {
|
||||
[EDITOR_ACTIONS.SET_EDITING]: setEditing,
|
||||
[EDITOR_ACTIONS.SET_CHANGED]: setChanged,
|
||||
[EDITOR_ACTIONS.SET_MODE]: setMode,
|
||||
[EDITOR_ACTIONS.SET_DISTANCE]: setDistance,
|
||||
[EDITOR_ACTIONS.SET_ROUTER_POINTS]: setRouterPoints,
|
||||
[EDITOR_ACTIONS.SET_ACTIVE_STICKER]: setActiveSticker,
|
||||
|
||||
[EDITOR_ACTIONS.SET_SAVE_ERROR]: setSaveError,
|
||||
[EDITOR_ACTIONS.SET_SAVE_LOADING]: setSaveLoading,
|
||||
[EDITOR_ACTIONS.SET_SAVE_OVERWRITE]: setSaveOverwrite,
|
||||
[EDITOR_ACTIONS.SET_SAVE_SUCCESS]: setSaveSuccess,
|
||||
[EDITOR_ACTIONS.SEND_SAVE_REQUEST]: sendSaveRequest,
|
||||
[EDITOR_ACTIONS.RESET_SAVE_DIALOG]: resetSaveDialog,
|
||||
|
||||
[EDITOR_ACTIONS.HIDE_RENDERER]: hideRenderer,
|
||||
[EDITOR_ACTIONS.SET_RENDERER]: setRenderer,
|
||||
|
||||
[EDITOR_ACTIONS.SET_DIALOG]: setDialog,
|
||||
[EDITOR_ACTIONS.SET_DIALOG_ACTIVE]: setDialogActive,
|
||||
[EDITOR_ACTIONS.SET_READY]: setReady,
|
||||
|
||||
[EDITOR_ACTIONS.SET_SPEED]: setSpeed,
|
||||
[EDITOR_ACTIONS.SET_MARKERS_SHOWN]: setMarkersShown,
|
||||
[EDITOR_ACTIONS.SET_IS_EMPTY]: setIsEmpty,
|
||||
|
||||
[EDITOR_ACTIONS.SET_FEATURE]: setFeature,
|
||||
[EDITOR_ACTIONS.SET_IS_ROUTING]: setIsRouting,
|
||||
};
|
85
src/redux/editor/index.ts
Normal file
85
src/redux/editor/index.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import { IDialogs } from '~/constants/dialogs';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { createReducer } from 'reduxsauce';
|
||||
import { EDITOR_HANDLERS } from './handlers';
|
||||
|
||||
export interface IEditorState {
|
||||
changed: boolean,
|
||||
editing: boolean,
|
||||
ready: boolean,
|
||||
markers_shown: boolean;
|
||||
|
||||
mode: typeof MODES[keyof typeof MODES],
|
||||
|
||||
dialog: IDialogs[keyof IDialogs],
|
||||
dialog_active: boolean,
|
||||
|
||||
routerPoints: number,
|
||||
distance: number,
|
||||
estimated: number,
|
||||
speed: number,
|
||||
activeSticker: { set?: string, sticker?: string },
|
||||
is_empty: boolean,
|
||||
is_published: boolean,
|
||||
is_routing: boolean,
|
||||
save_error: string,
|
||||
save_finished: boolean,
|
||||
save_overwriting: boolean,
|
||||
save_processing: boolean,
|
||||
save_loading: boolean,
|
||||
|
||||
features: {
|
||||
routing: boolean,
|
||||
},
|
||||
|
||||
renderer: {
|
||||
data: string,
|
||||
width: number,
|
||||
height: number
|
||||
renderer_active: boolean,
|
||||
info: string,
|
||||
progress: number,
|
||||
},
|
||||
}
|
||||
|
||||
const EDITOR_INITIAL_STATE = {
|
||||
changed: false,
|
||||
editing: false,
|
||||
ready: false,
|
||||
markers_shown: false,
|
||||
|
||||
mode: MODES.NONE,
|
||||
dialog: null,
|
||||
dialog_active: false,
|
||||
|
||||
routerPoints: 0,
|
||||
distance: 0,
|
||||
estimated: 0,
|
||||
speed: 15,
|
||||
activeSticker: { set: null, sticker: null },
|
||||
|
||||
is_published: false,
|
||||
is_empty: true,
|
||||
is_routing: false,
|
||||
|
||||
save_error: '',
|
||||
save_finished: false,
|
||||
save_overwriting: false,
|
||||
save_processing: false,
|
||||
save_loading: false,
|
||||
|
||||
features: {
|
||||
routing: false,
|
||||
},
|
||||
|
||||
renderer: {
|
||||
data: '',
|
||||
width: 0,
|
||||
height: 0,
|
||||
renderer_active: false,
|
||||
info: '',
|
||||
progress: 0,
|
||||
},
|
||||
}
|
||||
|
||||
export const editor = createReducer(EDITOR_INITIAL_STATE, EDITOR_HANDLERS);
|
256
src/redux/editor/sagas.ts
Normal file
256
src/redux/editor/sagas.ts
Normal file
|
@ -0,0 +1,256 @@
|
|||
import { call, put, takeEvery, takeLatest, select, race } from 'redux-saga/effects';
|
||||
import { delay, SagaIterator } from 'redux-saga';
|
||||
import { selectEditor } from '~/redux/editor/selectors';
|
||||
|
||||
import {
|
||||
editorHideRenderer,
|
||||
editorSetChanged,
|
||||
editorSetEditing,
|
||||
editorSetMode,
|
||||
editorSetReady,
|
||||
editorSetRenderer,
|
||||
editorSetDialog,
|
||||
editorSetDialogActive,
|
||||
editorClearAll,
|
||||
editorSetFeature,
|
||||
editorLocationChanged,
|
||||
editorKeyPressed,
|
||||
} from '~/redux/editor/actions';
|
||||
import { getUrlData, pushPath } from '~/utils/history';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { checkOSRMService } from '~/utils/api';
|
||||
import { LatLng } from 'leaflet';
|
||||
import { searchSetTab } from '../user/actions';
|
||||
import { TABS } from '~/constants/dialogs';
|
||||
import { EDITOR_ACTIONS } from './constants';
|
||||
import { getGPXString, downloadGPXTrack } from '~/utils/gpx';
|
||||
import {
|
||||
getTilePlacement,
|
||||
getPolyPlacement,
|
||||
getStickersPlacement,
|
||||
fetchImages,
|
||||
composeArrows,
|
||||
composeDistMark,
|
||||
composeImages,
|
||||
composePoly,
|
||||
composeStickers,
|
||||
imageFetcher,
|
||||
downloadCanvas,
|
||||
} from '~/utils/renderer';
|
||||
import { selectMap } from '../map/selectors';
|
||||
import { selectUser } from '../user/selectors';
|
||||
import { LOGOS } from '~/constants/logos';
|
||||
import { loadMapSaga, replaceAddressIfItsBusy } from '../map/sagas';
|
||||
import { mapSetAddressOrigin } from '../map/actions';
|
||||
|
||||
const hideLoader = () => {
|
||||
document.getElementById('loader').style.opacity = String(0);
|
||||
document.getElementById('loader').style.pointerEvents = 'none';
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
function* stopEditingSaga() {
|
||||
const { changed, editing, mode }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
const { address_origin }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
const { path } = getUrlData();
|
||||
|
||||
if (!editing) return;
|
||||
if (changed && mode !== MODES.CONFIRM_CANCEL) {
|
||||
yield put(editorSetMode(MODES.CONFIRM_CANCEL));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(editorSetMode(MODES.NONE));
|
||||
yield put(editorSetChanged(false));
|
||||
|
||||
yield pushPath(`/${address_origin || path}/`);
|
||||
}
|
||||
|
||||
function* checkOSRMServiceSaga() {
|
||||
const routing = yield call(checkOSRMService, [new LatLng(1, 1), new LatLng(2, 2)]);
|
||||
|
||||
yield put(editorSetFeature({ routing }));
|
||||
}
|
||||
|
||||
export function* setReadySaga() {
|
||||
yield put(editorSetReady(true));
|
||||
hideLoader();
|
||||
|
||||
yield call(checkOSRMServiceSaga);
|
||||
yield put(searchSetTab(TABS.MY));
|
||||
}
|
||||
|
||||
function* getRenderData() {
|
||||
yield put(editorSetRenderer({ info: 'Загрузка тайлов', progress: 0.1 }));
|
||||
|
||||
const { route, stickers, provider }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
|
||||
const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const geometry = getTilePlacement();
|
||||
const points = getPolyPlacement(route);
|
||||
const sticker_points = getStickersPlacement(stickers);
|
||||
// TODO: get distance:
|
||||
const distance = 0;
|
||||
// const distance = editor.poly.poly.distance;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const images = yield fetchImages(ctx, geometry, provider);
|
||||
|
||||
yield put(editorSetRenderer({ info: 'Отрисовка', progress: 0.5 }));
|
||||
|
||||
yield composeImages({ geometry, images, ctx });
|
||||
yield composePoly({ points, ctx });
|
||||
yield composeArrows({ points, ctx });
|
||||
yield composeDistMark({ ctx, points, distance });
|
||||
yield composeStickers({ stickers: sticker_points, ctx });
|
||||
|
||||
yield put(editorSetRenderer({ info: 'Готово', progress: 1 }));
|
||||
|
||||
return yield canvas.toDataURL('image/jpeg');
|
||||
}
|
||||
|
||||
function* takeAShotSaga() {
|
||||
const worker = call(getRenderData);
|
||||
|
||||
const { result, timeout } = yield race({
|
||||
result: worker,
|
||||
timeout: delay(500),
|
||||
});
|
||||
|
||||
if (timeout) yield put(editorSetMode(MODES.SHOT_PREFETCH));
|
||||
|
||||
const data = yield result || worker;
|
||||
|
||||
yield put(editorSetMode(MODES.NONE));
|
||||
yield put(
|
||||
editorSetRenderer({
|
||||
data,
|
||||
renderer_active: true,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function* getCropData({ x, y, width, height }) {
|
||||
const { logo }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
const {
|
||||
renderer: { data },
|
||||
}: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const image = yield imageFetcher(data);
|
||||
|
||||
ctx.drawImage(image, -x, -y);
|
||||
|
||||
if (logo && LOGOS[logo][1]) {
|
||||
const logoImage = yield imageFetcher(LOGOS[logo][1]);
|
||||
ctx.drawImage(logoImage, width - logoImage.width, height - logoImage.height);
|
||||
}
|
||||
|
||||
return yield canvas.toDataURL('image/jpeg');
|
||||
}
|
||||
|
||||
function* cropAShotSaga(params) {
|
||||
const { title, address }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
|
||||
yield call(getCropData, params);
|
||||
const canvas = document.getElementById('renderer') as HTMLCanvasElement;
|
||||
|
||||
downloadCanvas(canvas, (title || address).replace(/\./gi, ' '));
|
||||
|
||||
return yield put(editorHideRenderer());
|
||||
}
|
||||
|
||||
function* locationChangeSaga({ location }: ReturnType<typeof editorLocationChanged>) {
|
||||
const {
|
||||
user: { id, random_url },
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const { ready }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
const { owner, address }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
|
||||
if (!ready) return;
|
||||
|
||||
const { path, mode } = getUrlData(location);
|
||||
|
||||
if (address !== path) {
|
||||
const map = yield call(loadMapSaga, path);
|
||||
|
||||
if (map && map.route && map.route.owner && mode === 'edit' && map.route.owner !== id) {
|
||||
return yield call(replaceAddressIfItsBusy, map.random_url, map.address);
|
||||
}
|
||||
} else if (mode === 'edit' && owner.id !== id) {
|
||||
return yield call(replaceAddressIfItsBusy, random_url, address);
|
||||
} else {
|
||||
yield put(mapSetAddressOrigin(''));
|
||||
}
|
||||
|
||||
if (mode !== 'edit') {
|
||||
yield put(editorSetEditing(false));
|
||||
// editor.stopEditing();
|
||||
} else {
|
||||
yield put(editorSetEditing(true));
|
||||
// editor.startEditing();
|
||||
}
|
||||
}
|
||||
|
||||
function* keyPressedSaga({ key, target }: ReturnType<typeof editorKeyPressed>): any {
|
||||
if (target === 'INPUT' || target === 'TEXTAREA') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === 'Escape') {
|
||||
const {
|
||||
dialog_active,
|
||||
mode,
|
||||
renderer: { renderer_active },
|
||||
}: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
if (renderer_active) return yield put(editorHideRenderer());
|
||||
if (dialog_active) return yield put(editorSetDialogActive(false));
|
||||
if (mode !== MODES.NONE) return yield put(editorSetMode(MODES.NONE));
|
||||
} else if (key === 'Delete') {
|
||||
const { editing } = yield select(selectEditor);
|
||||
|
||||
if (!editing) return;
|
||||
|
||||
const { mode } = yield select(selectUser);
|
||||
|
||||
if (mode === MODES.TRASH) {
|
||||
yield put(editorClearAll());
|
||||
} else {
|
||||
yield put(editorSetMode(MODES.TRASH));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* getGPXTrackSaga(): SagaIterator {
|
||||
const { route, stickers, title, address }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
// const { title, address }: = yield select(selectUser);
|
||||
|
||||
if (!route || route.length <= 0) return;
|
||||
|
||||
const track = getGPXString({ route, stickers, title: title || address });
|
||||
|
||||
return downloadGPXTrack({ track, title });
|
||||
}
|
||||
|
||||
export function* editorSaga() {
|
||||
yield takeEvery(EDITOR_ACTIONS.STOP_EDITING, stopEditingSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.TAKE_A_SHOT, takeAShotSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.CROP_A_SHOT, cropAShotSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.LOCATION_CHANGED, locationChangeSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.KEY_PRESSED, keyPressedSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.GET_GPX_TRACK, getGPXTrackSaga);
|
||||
}
|
7
src/redux/editor/selectors.ts
Normal file
7
src/redux/editor/selectors.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { IState } from "../store";
|
||||
|
||||
export const selectEditor = (state: IState) => state.editor;
|
||||
export const selectEditorEditing = (state: IState) => state.editor.editing;
|
||||
export const selectEditorMode = (state: IState) => state.editor.mode;
|
||||
export const selectEditorActiveSticker = (state: IState) => state.editor.activeSticker;
|
||||
export const selectEditorRenderer = (state: IState) => state.editor.renderer;
|
|
@ -68,3 +68,8 @@ export const mapSetLogo = (logo: IMapReducer['logo']) => ({
|
|||
type: MAP_ACTIONS.SET_LOGO,
|
||||
logo,
|
||||
});
|
||||
|
||||
export const mapSetAddressOrigin = (address_origin: IMapReducer['address_origin']) => ({
|
||||
type: MAP_ACTIONS.SET_ADDRESS_ORIGIN,
|
||||
address_origin,
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ export const MAP_ACTIONS = {
|
|||
SET_TITLE: `${P}-SET_TILE`,
|
||||
SET_DESCRIPTION: `${P}-SETDESCRIPTION`,
|
||||
SET_ADDRESS: `${P}-SET_ADDRESS`,
|
||||
SET_ADDRESS_ORIGIN: `${P}-SET_ADDRESS_ORIGIN`,
|
||||
SET_OWNER: `${P}-SET_OWNER`,
|
||||
SET_PUBLIC: `${P}-SET_PUBLIC`,
|
||||
SET_LOGO: `${P}-SET_LOGO`,
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
mapSetOwner,
|
||||
mapSetPublic,
|
||||
mapSetLogo,
|
||||
mapSetAddressOrigin,
|
||||
} from './actions';
|
||||
|
||||
const setMap = (state: IMapReducer, { map }: ReturnType<typeof mapSet>): IMapReducer => ({
|
||||
|
@ -86,6 +87,11 @@ const setLogo = (state: IMapReducer, { logo }: ReturnType<typeof mapSetLogo>): I
|
|||
logo,
|
||||
});
|
||||
|
||||
const setAddressOrigin = (state, { address_origin }: ReturnType<typeof mapSetAddressOrigin>): IMapReducer => ({
|
||||
...state,
|
||||
address_origin
|
||||
});
|
||||
|
||||
export const MAP_HANDLERS = {
|
||||
[MAP_ACTIONS.SET_MAP]: setMap,
|
||||
[MAP_ACTIONS.SET_PROVIDER]: setProvider,
|
||||
|
@ -99,4 +105,5 @@ export const MAP_HANDLERS = {
|
|||
[MAP_ACTIONS.SET_OWNER]: setOwner,
|
||||
[MAP_ACTIONS.SET_PUBLIC]: setPublic,
|
||||
[MAP_ACTIONS.SET_LOGO]: setLogo,
|
||||
[MAP_ACTIONS.SET_ADDRESS_ORIGIN]: setAddressOrigin,
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ export interface IMapReducer {
|
|||
title: string;
|
||||
logo: string;
|
||||
address: string;
|
||||
address_origin: string;
|
||||
description: string;
|
||||
owner: { id: string };
|
||||
is_public: boolean;
|
||||
|
@ -24,6 +25,7 @@ export const MAP_INITIAL_STATE: IMapReducer = {
|
|||
stickers: [],
|
||||
title: '',
|
||||
address: '',
|
||||
address_origin: '',
|
||||
description: '',
|
||||
owner: { id: null },
|
||||
is_public: false,
|
||||
|
|
|
@ -1,39 +1,58 @@
|
|||
import { takeEvery, select, put, call, TakeEffect, race, take, takeLatest } from 'redux-saga/effects';
|
||||
import {
|
||||
takeEvery,
|
||||
select,
|
||||
put,
|
||||
call,
|
||||
TakeEffect,
|
||||
race,
|
||||
take,
|
||||
takeLatest,
|
||||
} from 'redux-saga/effects';
|
||||
import { MAP_ACTIONS } from './constants';
|
||||
import { mapClicked, mapAddSticker, mapSetProvider, mapSet, mapSetTitle, mapSetAddress, mapSetDescription, mapSetOwner, mapSetPublic } from './actions';
|
||||
import { selectUserMode, selectUserActiveSticker, selectUser, selectUserUser } from '~/redux/user/selectors';
|
||||
import {
|
||||
mapClicked,
|
||||
mapAddSticker,
|
||||
mapSetProvider,
|
||||
mapSet,
|
||||
mapSetTitle,
|
||||
mapSetAddressOrigin,
|
||||
} from './actions';
|
||||
import { selectUser, selectUserUser } from '~/redux/user/selectors';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import {
|
||||
setMode,
|
||||
setChanged,
|
||||
setAddressOrigin,
|
||||
setEditing,
|
||||
setReady,
|
||||
setActiveSticker,
|
||||
setSaveError,
|
||||
setSaveLoading,
|
||||
sendSaveRequest,
|
||||
setSaveSuccess,
|
||||
setSaveOverwrite,
|
||||
} from '~/redux/user/actions';
|
||||
editorSetMode,
|
||||
editorSetChanged,
|
||||
editorSetEditing,
|
||||
editorSetReady,
|
||||
editorSetActiveSticker,
|
||||
editorSetSaveError,
|
||||
editorSetSaveLoading,
|
||||
editorSendSaveRequest,
|
||||
editorSetSaveSuccess,
|
||||
editorSetSaveOverwrite,
|
||||
} from '~/redux/editor/actions';
|
||||
import { pushLoaderState, getUrlData, pushPath, replacePath } from '~/utils/history';
|
||||
import { setReadySaga, searchSetSagaWorker } from '~/redux/user/sagas';
|
||||
import { searchSetSagaWorker } from '~/redux/user/sagas';
|
||||
import { getStoredMap, postMap } from '~/utils/api';
|
||||
import { Unwrap } from '~/utils/middleware';
|
||||
import { DEFAULT_PROVIDER } from '~/constants/providers';
|
||||
import { USER_ACTIONS } from '~/redux/user/constants';
|
||||
import { selectMap } from './selectors';
|
||||
import { selectMap, selectMapProvider } from './selectors';
|
||||
import { TIPS } from '~/constants/tips';
|
||||
import { delay } from 'redux-saga';
|
||||
import { setReadySaga } from '../editor/sagas';
|
||||
import { selectEditor } from '../editor/selectors';
|
||||
import { EDITOR_ACTIONS } from '../editor/constants';
|
||||
|
||||
function* onMapClick({ latlng }: ReturnType<typeof mapClicked>) {
|
||||
const mode = yield select(selectUserMode);
|
||||
const { set, sticker } = yield select(selectUserActiveSticker);
|
||||
const {
|
||||
mode,
|
||||
activeSticker: { set, sticker },
|
||||
}: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
switch (mode) {
|
||||
case MODES.STICKERS:
|
||||
yield put(mapAddSticker({ latlng, set, sticker, text: '', angle: 0 }));
|
||||
yield put(setMode(MODES.NONE));
|
||||
yield put(editorSetMode(MODES.NONE));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -64,7 +83,7 @@ function* onMapClick({ latlng }: ReturnType<typeof mapClicked>) {
|
|||
|
||||
export function* replaceAddressIfItsBusy(destination, original) {
|
||||
if (original) {
|
||||
yield put(setAddressOrigin(original));
|
||||
yield put(mapSetAddressOrigin(original));
|
||||
}
|
||||
|
||||
pushPath(`/${destination}/edit`);
|
||||
|
@ -97,14 +116,15 @@ export function* loadMapSaga(path) {
|
|||
function* startEmptyEditorSaga() {
|
||||
const {
|
||||
user: { id, random_url },
|
||||
provider = DEFAULT_PROVIDER,
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const provider: ReturnType<typeof selectMapProvider> = yield select(selectMapProvider);
|
||||
|
||||
// TODO: set owner { id }
|
||||
pushPath(`/${random_url}/edit`);
|
||||
|
||||
yield put(setChanged(false));
|
||||
yield put(setEditing(true));
|
||||
yield put(editorSetChanged(false));
|
||||
yield put(editorSetEditing(true));
|
||||
|
||||
return yield call(setReadySaga);
|
||||
}
|
||||
|
@ -114,9 +134,9 @@ export function* mapInitSaga() {
|
|||
|
||||
const { path, mode, hash } = getUrlData();
|
||||
const {
|
||||
provider,
|
||||
user: { id },
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
const provider: ReturnType<typeof selectMapProvider> = yield select(selectMapProvider);
|
||||
|
||||
yield put(mapSetProvider(provider));
|
||||
|
||||
|
@ -139,14 +159,12 @@ export function* mapInitSaga() {
|
|||
yield call(setReadySaga);
|
||||
yield call(replaceAddressIfItsBusy, map.random_url, map.address);
|
||||
} else {
|
||||
yield put(setAddressOrigin(''));
|
||||
yield put(mapSetAddressOrigin(''));
|
||||
}
|
||||
|
||||
yield put(setEditing(true));
|
||||
// TODO: start editing
|
||||
yield put(editorSetEditing(true));
|
||||
} else {
|
||||
yield put(setEditing(false));
|
||||
// TODO: stop editing
|
||||
yield put(editorSetEditing(false));
|
||||
}
|
||||
|
||||
yield call(setReadySaga);
|
||||
|
@ -155,7 +173,7 @@ export function* mapInitSaga() {
|
|||
}
|
||||
|
||||
yield call(startEmptyEditorSaga);
|
||||
yield put(setReady(true));
|
||||
yield put(editorSetReady(true));
|
||||
|
||||
pushLoaderState(100);
|
||||
|
||||
|
@ -163,7 +181,7 @@ export function* mapInitSaga() {
|
|||
}
|
||||
|
||||
function* setActiveStickerSaga() {
|
||||
yield put(setMode(MODES.STICKERS));
|
||||
yield put(editorSetMode(MODES.STICKERS));
|
||||
}
|
||||
|
||||
function* setTitleSaga({ title }: ReturnType<typeof mapSetTitle>) {
|
||||
|
@ -172,10 +190,14 @@ function* setTitleSaga({ title }: ReturnType<typeof mapSetTitle>) {
|
|||
}
|
||||
}
|
||||
|
||||
function* startEditingSaga() {
|
||||
const { path } = getUrlData();
|
||||
yield pushPath(`/${path}/edit`);
|
||||
}
|
||||
|
||||
function* clearSaga({ type }) {
|
||||
switch (type) {
|
||||
case USER_ACTIONS.CLEAR_POLY:
|
||||
// TODO: clear router waypoints
|
||||
case EDITOR_ACTIONS.CLEAR_POLY:
|
||||
yield put(
|
||||
mapSet({
|
||||
route: [],
|
||||
|
@ -183,7 +205,7 @@ function* clearSaga({ type }) {
|
|||
);
|
||||
break;
|
||||
|
||||
case USER_ACTIONS.CLEAR_STICKERS:
|
||||
case EDITOR_ACTIONS.CLEAR_STICKERS:
|
||||
yield put(
|
||||
mapSet({
|
||||
stickers: [],
|
||||
|
@ -191,8 +213,8 @@ function* clearSaga({ type }) {
|
|||
);
|
||||
break;
|
||||
|
||||
case USER_ACTIONS.CLEAR_ALL:
|
||||
yield put(setChanged(false));
|
||||
case EDITOR_ACTIONS.CLEAR_ALL:
|
||||
yield put(editorSetChanged(false));
|
||||
yield put(
|
||||
mapSet({
|
||||
route: [],
|
||||
|
@ -205,8 +227,8 @@ function* clearSaga({ type }) {
|
|||
break;
|
||||
}
|
||||
|
||||
yield put(setActiveSticker(null)); // TODO: move to maps
|
||||
yield put(setMode(MODES.NONE));
|
||||
yield put(editorSetActiveSticker(null));
|
||||
yield put(editorSetMode(MODES.NONE));
|
||||
}
|
||||
|
||||
function* sendSaveRequestSaga({
|
||||
|
@ -215,17 +237,18 @@ function* sendSaveRequestSaga({
|
|||
force,
|
||||
is_public,
|
||||
description,
|
||||
}: ReturnType<typeof sendSaveRequest>) {
|
||||
const { route, stickers, provider } = yield select(selectMap);
|
||||
}: ReturnType<typeof editorSendSaveRequest>) {
|
||||
const { route, stickers, provider }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
|
||||
if (!route.length && !stickers.length) {
|
||||
return yield put(setSaveError(TIPS.SAVE_EMPTY)); // TODO: move setSaveError to editor
|
||||
return yield put(editorSetSaveError(TIPS.SAVE_EMPTY));
|
||||
}
|
||||
|
||||
const { logo, distance } = yield select(selectUser);
|
||||
const { token } = yield select(selectUserUser);
|
||||
const { logo }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
const { distance }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
|
||||
yield put(setSaveLoading(true)); // TODO: move setSaveLoading to maps
|
||||
yield put(editorSetSaveLoading(true));
|
||||
|
||||
const {
|
||||
result,
|
||||
|
@ -250,20 +273,21 @@ function* sendSaveRequestSaga({
|
|||
description,
|
||||
}),
|
||||
timeout: delay(10000),
|
||||
cancel: take(USER_ACTIONS.RESET_SAVE_DIALOG),
|
||||
cancel: take(EDITOR_ACTIONS.RESET_SAVE_DIALOG),
|
||||
});
|
||||
|
||||
yield put(setSaveLoading(false));
|
||||
yield put(editorSetSaveLoading(false));
|
||||
|
||||
if (cancel) return yield put(setMode(MODES.NONE));
|
||||
if (cancel) return yield put(editorSetMode(MODES.NONE));
|
||||
|
||||
if (result && result.data.code === 'already_exist') return yield put(setSaveOverwrite()); // TODO: move setSaveOverwrite to editor
|
||||
if (result && result.data.code === 'conflict') return yield put(setSaveError(TIPS.SAVE_EXISTS));
|
||||
if (result && result.data.code === 'already_exist') return yield put(editorSetSaveOverwrite());
|
||||
if (result && result.data.code === 'conflict')
|
||||
return yield put(editorSetSaveError(TIPS.SAVE_EXISTS));
|
||||
if (timeout || !result || !result.data.route || !result.data.route.address)
|
||||
return yield put(setSaveError(TIPS.SAVE_TIMED_OUT));
|
||||
return yield put(editorSetSaveError(TIPS.SAVE_TIMED_OUT));
|
||||
|
||||
return yield put( // TODO: move setSaveSuccess to editor
|
||||
setSaveSuccess({
|
||||
return yield put(
|
||||
editorSetSaveSuccess({
|
||||
address: result.data.route.address,
|
||||
title: result.data.route.title,
|
||||
is_public: result.data.route.is_public,
|
||||
|
@ -279,18 +303,23 @@ function* setSaveSuccessSaga({
|
|||
title,
|
||||
is_public,
|
||||
description,
|
||||
}: ReturnType<typeof setSaveSuccess>) {
|
||||
const { id } = yield select(selectUser);
|
||||
const { dialog_active } = yield select(selectUser);
|
||||
}: ReturnType<typeof editorSetSaveSuccess>) {
|
||||
const { id }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
const { dialog_active }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
replacePath(`/${address}/edit`);
|
||||
|
||||
yield put(mapSetTitle(title));
|
||||
yield put(mapSetAddress(address));
|
||||
yield put(mapSetPublic(is_public));
|
||||
yield put(mapSetDescription(description));
|
||||
yield put(setChanged(false));
|
||||
yield put(mapSetOwner({ id }));
|
||||
yield put(
|
||||
mapSet({
|
||||
title,
|
||||
address,
|
||||
is_public,
|
||||
description,
|
||||
owner: { id },
|
||||
})
|
||||
);
|
||||
|
||||
yield put(editorSetChanged(false));
|
||||
|
||||
if (dialog_active) {
|
||||
yield call(searchSetSagaWorker);
|
||||
|
@ -299,26 +328,24 @@ function* setSaveSuccessSaga({
|
|||
// yield editor.setInitialData();
|
||||
// TODO: set initial data here
|
||||
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
export function* mapSaga() {
|
||||
// TODO: setChanged on set route, logo, provider, stickers
|
||||
|
||||
yield takeEvery(USER_ACTIONS.SET_ACTIVE_STICKER, setActiveStickerSaga); // TODO: move active sticker to maps
|
||||
yield takeEvery(EDITOR_ACTIONS.START_EDITING, startEditingSaga);
|
||||
yield takeEvery(EDITOR_ACTIONS.SET_ACTIVE_STICKER, setActiveStickerSaga);
|
||||
yield takeEvery(MAP_ACTIONS.MAP_CLICKED, onMapClick);
|
||||
yield takeEvery(MAP_ACTIONS.SET_TITLE, setTitleSaga);
|
||||
// yield takeEvery(USER_ACTIONS.SET_LOGO, setLogoSaga);
|
||||
yield takeLatest(USER_ACTIONS.SEND_SAVE_REQUEST, sendSaveRequestSaga);
|
||||
yield takeLatest(USER_ACTIONS.SET_SAVE_SUCCESS, setSaveSuccessSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.SEND_SAVE_REQUEST, sendSaveRequestSaga);
|
||||
yield takeLatest(EDITOR_ACTIONS.SET_SAVE_SUCCESS, setSaveSuccessSaga);
|
||||
|
||||
yield takeEvery(
|
||||
// TODO: move all actions to MAP
|
||||
[
|
||||
USER_ACTIONS.CLEAR_POLY,
|
||||
USER_ACTIONS.CLEAR_STICKERS,
|
||||
USER_ACTIONS.CLEAR_ALL,
|
||||
USER_ACTIONS.CLEAR_CANCEL,
|
||||
EDITOR_ACTIONS.CLEAR_POLY,
|
||||
EDITOR_ACTIONS.CLEAR_STICKERS,
|
||||
EDITOR_ACTIONS.CLEAR_ALL,
|
||||
EDITOR_ACTIONS.CLEAR_CANCEL,
|
||||
],
|
||||
clearSaga
|
||||
);
|
||||
|
|
|
@ -4,13 +4,20 @@ import { persistStore, persistReducer } from 'redux-persist';
|
|||
import storage from 'redux-persist/lib/storage';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
|
||||
|
||||
import { createBrowserHistory } from 'history';
|
||||
import { editorLocationChanged } from '~/redux/editor/actions';
|
||||
import { PersistConfig, Persistor } from "redux-persist/es/types";
|
||||
|
||||
|
||||
import { userReducer, IRootReducer } from '~/redux/user';
|
||||
import { userSaga } from '~/redux/user/sagas';
|
||||
import { mapSaga } from '~/redux/map/sagas';
|
||||
import { createBrowserHistory } from 'history';
|
||||
import { locationChanged } from '~/redux/user/actions';
|
||||
import { PersistConfig, Persistor } from "redux-persist/es/types";
|
||||
|
||||
import { editor, IEditorState } from '~/redux/editor';
|
||||
import { editorSaga } from '~/redux/editor/sagas';
|
||||
|
||||
import { map, IMapReducer } from '~/redux/map';
|
||||
import { mapSaga } from '~/redux/map/sagas';
|
||||
|
||||
const userPersistConfig: PersistConfig = {
|
||||
key: 'user',
|
||||
|
@ -21,6 +28,7 @@ const userPersistConfig: PersistConfig = {
|
|||
export interface IState {
|
||||
user: IRootReducer
|
||||
map: IMapReducer,
|
||||
editor: IEditorState,
|
||||
}
|
||||
// create the saga middleware
|
||||
export const sagaMiddleware = createSagaMiddleware();
|
||||
|
@ -36,14 +44,15 @@ export const store = createStore(
|
|||
combineReducers({
|
||||
user: persistReducer(userPersistConfig, userReducer),
|
||||
map,
|
||||
// routing: routerReducer
|
||||
editor,
|
||||
}),
|
||||
composeEnhancers(applyMiddleware(/* routerMiddleware(history), */ sagaMiddleware))
|
||||
composeEnhancers(applyMiddleware(sagaMiddleware))
|
||||
);
|
||||
|
||||
export function configureStore(): { store: Store<any>, persistor: Persistor } {
|
||||
sagaMiddleware.run(userSaga);
|
||||
sagaMiddleware.run(mapSaga);
|
||||
sagaMiddleware.run(editorSaga);
|
||||
|
||||
const persistor = persistStore(store);
|
||||
|
||||
|
@ -54,5 +63,5 @@ export const history = createBrowserHistory();
|
|||
|
||||
history.listen((location, action) => {
|
||||
if (action === 'REPLACE') return;
|
||||
store.dispatch(locationChanged(location.pathname));
|
||||
store.dispatch(editorLocationChanged(location.pathname));
|
||||
});
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
import { USER_ACTIONS } from '~/redux/user/constants';
|
||||
import { IUser } from "~/constants/auth";
|
||||
import { IRootState } from "~/redux/user";
|
||||
import { IRoute } from '~/redux/map/types';
|
||||
// import { IRootState } from "~/redux/user";
|
||||
// import { IRoute } from '~/redux/map/types';
|
||||
|
||||
export const setUser = (user: IUser) => ({ type: USER_ACTIONS.SET_USER, user });
|
||||
export const userLogout = () => ({ type: USER_ACTIONS.USER_LOGOUT });
|
||||
|
||||
export const setEditing = (editing: IRootState['editing']) => ({ type: USER_ACTIONS.SET_EDITING, editing });
|
||||
export const setMode = (mode: IRootState['mode']) => ({ type: USER_ACTIONS.SET_MODE, mode });
|
||||
export const setDistance = (distance: IRootState['distance']) => ({ type: USER_ACTIONS.SET_DISTANCE, distance });
|
||||
export const setChanged = (changed: IRootState['changed']) => ({ type: USER_ACTIONS.SET_CHANGED, changed });
|
||||
export const setRouterPoints = routerPoints => ({ type: USER_ACTIONS.SET_ROUTER_POINTS, routerPoints });
|
||||
export const setActiveSticker = activeSticker => ({ type: USER_ACTIONS.SET_ACTIVE_STICKER, activeSticker });
|
||||
// export const setEditing = (editing: IRootState['editing']) => ({ type: USER_ACTIONS.SET_EDITING, editing });
|
||||
// export const setMode = (mode: IRootState['mode']) => ({ type: USER_ACTIONS.SET_MODE, mode });
|
||||
// export const setDistance = (distance: IRootState['distance']) => ({ type: USER_ACTIONS.SET_DISTANCE, distance });
|
||||
// export const setChanged = (changed: IRootState['changed']) => ({ type: USER_ACTIONS.SET_CHANGED, changed });
|
||||
// export const setRouterPoints = routerPoints => ({ type: USER_ACTIONS.SET_ROUTER_POINTS, routerPoints });
|
||||
// export const setActiveSticker = activeSticker => ({ type: USER_ACTIONS.SET_ACTIVE_STICKER, activeSticker });
|
||||
// export const setLogo = logo => ({ type: USER_ACTIONS.SET_LOGO, logo });
|
||||
// export const setTitle = title => ({ type: USER_ACTIONS.SET_TITLE, title });
|
||||
// export const setDescription = description => ({ type: USER_ACTIONS.SET_DESCRIPTION, description });
|
||||
// export const setAddress = address => ({ type: USER_ACTIONS.SET_ADDRESS, address });
|
||||
export const setAddressOrigin = address_origin => ({ type: USER_ACTIONS.SET_ADDRESS_ORIGIN, address_origin });
|
||||
// export const setAddressOrigin = address_origin => ({ type: USER_ACTIONS.SET_ADDRESS_ORIGIN, address_origin });
|
||||
// export const setPublic = is_public => ({ type: USER_ACTIONS.SET_PUBLIC, is_public });
|
||||
export const setStarred = is_published => ({ type: USER_ACTIONS.SET_STARRED, is_published });
|
||||
export const setSpeed = speed => ({ type: USER_ACTIONS.SET_SPEED, speed });
|
||||
// export const setSpeed = speed => ({ type: USER_ACTIONS.SET_SPEED, speed });
|
||||
|
||||
export const startEditing = () => ({ type: USER_ACTIONS.START_EDITING });
|
||||
export const stopEditing = () => ({ type: USER_ACTIONS.STOP_EDITING });
|
||||
// export const startEditing = () => ({ type: USER_ACTIONS.START_EDITING });
|
||||
// export const stopEditing = () => ({ type: USER_ACTIONS.STOP_EDITING });
|
||||
|
||||
export const routerCancel = () => ({ type: USER_ACTIONS.ROUTER_CANCEL });
|
||||
export const routerSubmit = () => ({ type: USER_ACTIONS.ROUTER_SUBMIT });
|
||||
// export const routerCancel = () => ({ type: USER_ACTIONS.ROUTER_CANCEL });
|
||||
// export const routerSubmit = () => ({ type: USER_ACTIONS.ROUTER_SUBMIT });
|
||||
|
||||
export const clearPoly = () => ({ type: USER_ACTIONS.CLEAR_POLY });
|
||||
export const clearStickers = () => ({ type: USER_ACTIONS.CLEAR_STICKERS });
|
||||
export const clearAll = () => ({ type: USER_ACTIONS.CLEAR_ALL });
|
||||
export const clearCancel = () => ({ type: USER_ACTIONS.CLEAR_CANCEL });
|
||||
// export const clearPoly = () => ({ type: USER_ACTIONS.CLEAR_POLY });
|
||||
// export const clearStickers = () => ({ type: USER_ACTIONS.CLEAR_STICKERS });
|
||||
// export const clearAll = () => ({ type: USER_ACTIONS.CLEAR_ALL });
|
||||
// export const clearCancel = () => ({ type: USER_ACTIONS.CLEAR_CANCEL });
|
||||
|
||||
export const sendSaveRequest = (payload: {
|
||||
title: IRoute['title'],
|
||||
address: IRoute['address'],
|
||||
is_public: IRoute['is_public'],
|
||||
description: IRoute['description'],
|
||||
force: boolean,
|
||||
}) => ({
|
||||
type: USER_ACTIONS.SEND_SAVE_REQUEST,
|
||||
...payload,
|
||||
});
|
||||
// export const sendSaveRequest = (payload: {
|
||||
// title: IRoute['title'],
|
||||
// address: IRoute['address'],
|
||||
// is_public: IRoute['is_public'],
|
||||
// description: IRoute['description'],
|
||||
// force: boolean,
|
||||
// }) => ({
|
||||
// type: USER_ACTIONS.SEND_SAVE_REQUEST,
|
||||
// ...payload,
|
||||
// });
|
||||
|
||||
export const resetSaveDialog = () => ({ type: USER_ACTIONS.RESET_SAVE_DIALOG });
|
||||
// export const resetSaveDialog = () => ({ type: USER_ACTIONS.RESET_SAVE_DIALOG });
|
||||
|
||||
export const setSaveLoading = (save_loading: IRootState['save_loading']) => ({ type: USER_ACTIONS.SET_SAVE_LOADING, save_loading });
|
||||
// export const setSaveLoading = (save_loading: IRootState['save_loading']) => ({ type: USER_ACTIONS.SET_SAVE_LOADING, save_loading });
|
||||
|
||||
export const setSaveSuccess = (payload: {
|
||||
address: IRoute['address'],
|
||||
title: IRoute['address'],
|
||||
is_public: IRoute['is_public'],
|
||||
description: IRoute['description'],
|
||||
// export const setSaveSuccess = (payload: {
|
||||
// address: IRoute['address'],
|
||||
// title: IRoute['address'],
|
||||
// is_public: IRoute['is_public'],
|
||||
// description: IRoute['description'],
|
||||
|
||||
save_error: string,
|
||||
}) => ({ type: USER_ACTIONS.SET_SAVE_SUCCESS, ...payload });
|
||||
// save_error: string,
|
||||
// }) => ({ type: USER_ACTIONS.SET_SAVE_SUCCESS, ...payload });
|
||||
|
||||
export const setSaveError = (save_error: IRootState['save_error']) => ({ type: USER_ACTIONS.SET_SAVE_ERROR, save_error });
|
||||
export const setSaveOverwrite = () => ({ type: USER_ACTIONS.SET_SAVE_OVERWRITE });
|
||||
// export const setSaveError = (save_error: IRootState['save_error']) => ({ type: USER_ACTIONS.SET_SAVE_ERROR, save_error });
|
||||
// export const setSaveOverwrite = () => ({ type: USER_ACTIONS.SET_SAVE_OVERWRITE });
|
||||
|
||||
export const hideRenderer = () => ({ type: USER_ACTIONS.HIDE_RENDERER });
|
||||
export const setRenderer = payload => ({ type: USER_ACTIONS.SET_RENDERER, payload });
|
||||
export const takeAShot = () => ({ type: USER_ACTIONS.TAKE_A_SHOT });
|
||||
export const cropAShot = payload => ({ type: USER_ACTIONS.CROP_A_SHOT, ...payload });
|
||||
// export const hideRenderer = () => ({ type: USER_ACTIONS.HIDE_RENDERER });
|
||||
// export const setRenderer = payload => ({ type: USER_ACTIONS.SET_RENDERER, payload });
|
||||
// export const takeAShot = () => ({ type: USER_ACTIONS.TAKE_A_SHOT });
|
||||
// export const cropAShot = payload => ({ type: USER_ACTIONS.CROP_A_SHOT, ...payload });
|
||||
|
||||
// export const setProvider = provider => ({ type: USER_ACTIONS.SET_PROVIDER, provider });
|
||||
// export const changeProvider = provider => ({ type: USER_ACTIONS.CHANGE_PROVIDER, provider });
|
||||
|
||||
export const setDialog = dialog => ({ type: USER_ACTIONS.SET_DIALOG, dialog });
|
||||
export const setDialogActive = dialog_active => ({ type: USER_ACTIONS.SET_DIALOG_ACTIVE, dialog_active });
|
||||
// export const setDialog = dialog => ({ type: USER_ACTIONS.SET_DIALOG, dialog });
|
||||
// export const setDialogActive = dialog_active => ({ type: USER_ACTIONS.SET_DIALOG_ACTIVE, dialog_active });
|
||||
export const openMapDialog = tab => ({ type: USER_ACTIONS.OPEN_MAP_DIALOG, tab });
|
||||
|
||||
export const locationChanged = location => ({ type: USER_ACTIONS.LOCATION_CHANGED, location });
|
||||
export const setReady = ready => ({ type: USER_ACTIONS.SET_READY, ready });
|
||||
// export const locationChanged = location => ({ type: USER_ACTIONS.LOCATION_CHANGED, location });
|
||||
// export const setReady = ready => ({ type: USER_ACTIONS.SET_READY, ready });
|
||||
|
||||
export const gotVkUser = user => ({ type: USER_ACTIONS.GOT_VK_USER, user });
|
||||
export const keyPressed = ({ key, target: { tagName } }) => ({ type: USER_ACTIONS.KEY_PRESSED, key, target: tagName });
|
||||
// export const keyPressed = ({ key, target: { tagName } }) => ({ type: USER_ACTIONS.KEY_PRESSED, key, target: tagName });
|
||||
|
||||
export const searchSetTitle = title => ({ type: USER_ACTIONS.SEARCH_SET_TITLE, title });
|
||||
export const searchSetDistance = distance => ({ type: USER_ACTIONS.SEARCH_SET_DISTANCE, distance });
|
||||
|
@ -85,15 +85,15 @@ export const searchSetLoading = loading => ({ type: USER_ACTIONS.SEARCH_SET_LOAD
|
|||
|
||||
export const searchPutRoutes = payload => ({ type: USER_ACTIONS.SEARCH_PUT_ROUTES, ...payload });
|
||||
|
||||
export const setMarkersShown = markers_shown => ({ type: USER_ACTIONS.SET_MARKERS_SHOWN, markers_shown });
|
||||
export const getGPXTrack = () => ({ type: USER_ACTIONS.GET_GPX_TRACK });
|
||||
export const setIsEmpty = is_empty => ({ type: USER_ACTIONS.SET_IS_EMPTY, is_empty });
|
||||
// export const getGPXTrack = () => ({ type: USER_ACTIONS.GET_GPX_TRACK });
|
||||
// export const setMarkersShown = markers_shown => ({ type: USER_ACTIONS.SET_MARKERS_SHOWN, markers_shown });
|
||||
// export const setIsEmpty = is_empty => ({ type: USER_ACTIONS.SET_IS_EMPTY, is_empty });
|
||||
|
||||
export const mapsLoadMore = () => ({ type: USER_ACTIONS.MAPS_LOAD_MORE });
|
||||
export const mapsSetShift = (shift: number) => ({ type: USER_ACTIONS.MAPS_SET_SHIFT, shift });
|
||||
|
||||
export const setFeature = (features: { [x: string]: boolean }) => ({ type: USER_ACTIONS.SET_FEATURE, features });
|
||||
export const setIsRouting = (is_routing: boolean) => ({ type: USER_ACTIONS.SET_IS_ROUTING, is_routing });
|
||||
// export const setFeature = (features: { [x: string]: boolean }) => ({ type: USER_ACTIONS.SET_FEATURE, features });
|
||||
// export const setIsRouting = (is_routing: boolean) => ({ type: USER_ACTIONS.SET_IS_ROUTING, is_routing });
|
||||
|
||||
export const dropRoute = (address: string) => ({ type: USER_ACTIONS.DROP_ROUTE, address });
|
||||
export const modifyRoute = (address: string, { title, is_public }: { title: string, is_public: boolean }) => ({
|
||||
|
|
|
@ -1,61 +1,7 @@
|
|||
export interface IActions {
|
||||
[x: string]: string,
|
||||
}
|
||||
|
||||
export const USER_ACTIONS: IActions = {
|
||||
export const USER_ACTIONS = {
|
||||
SET_USER: 'SET_USER',
|
||||
USER_LOGOUT: 'USER_LOGOUT',
|
||||
|
||||
SET_EDITING: 'SET_EDITING',
|
||||
SET_MODE: 'SET_MODE',
|
||||
SET_DISTANCE: 'SET_DISTANCE',
|
||||
SET_CHANGED: 'SET_CHANGED',
|
||||
SET_ROUTER_POINTS: 'SET_ROUTER_POINTS',
|
||||
SET_ACTIVE_STICKER: 'SET_ACTIVE_STICKER',
|
||||
SET_LOGO: 'SET_LOGO',
|
||||
SET_TITLE: 'SET_TITLE',
|
||||
SET_ADDRESS: 'SET_ADDRESS',
|
||||
SET_ADDRESS_ORIGIN: 'SET_ADDRESS_ORIGIN',
|
||||
SET_PUBLIC: 'SET_PUBLIC',
|
||||
SET_STARRED: 'SET_STARRED',
|
||||
SET_DESCRIPTION: 'SET_DESCRIPTION',
|
||||
|
||||
START_EDITING: 'START_EDITING',
|
||||
STOP_EDITING: 'STOP_EDITING',
|
||||
|
||||
ROUTER_CANCEL: 'ROUTER_CANCEL',
|
||||
ROUTER_SUBMIT: 'ROUTER_SUBMIT',
|
||||
|
||||
CLEAR_POLY: 'CLEAR_POLY',
|
||||
CLEAR_STICKERS: 'CLEAR_STICKERS',
|
||||
CLEAR_ALL: 'CLEAR_ALL',
|
||||
CLEAR_CANCEL: 'CLEAR_CANCEL',
|
||||
|
||||
SEND_SAVE_REQUEST: 'SEND_SAVE_REQUEST',
|
||||
SET_SAVE_LOADING: 'SET_SAVE_LOADING',
|
||||
CANCEL_SAVE_REQUEST: 'CANCEL_SAVE_REQUEST',
|
||||
RESET_SAVE_DIALOG: 'RESET_SAVE_DIALOG',
|
||||
|
||||
SET_SAVE_SUCCESS: 'SET_SAVE_SUCCESS',
|
||||
SET_SAVE_ERROR: 'SET_SAVE_ERROR',
|
||||
SET_SAVE_OVERWRITE: 'SET_SAVE_OVERWRITE',
|
||||
|
||||
SHOW_RENDERER: 'SHOW_RENDERER',
|
||||
HIDE_RENDERER: 'HIDE_RENDERER',
|
||||
SET_RENDERER: 'SET_RENDERER',
|
||||
TAKE_A_SHOT: 'TAKE_A_SHOT',
|
||||
CROP_A_SHOT: 'CROP_A_SHOT',
|
||||
|
||||
SET_PROVIDER: 'SET_PROVIDER',
|
||||
CHANGE_PROVIDER: 'CHANGE_PROVIDER',
|
||||
|
||||
SET_DIALOG: 'SET_DIALOG',
|
||||
SET_DIALOG_ACTIVE: 'SET_DIALOG_ACTIVE',
|
||||
LOCATION_CHANGED: 'LOCATION_CHANGED',
|
||||
SET_READY: 'SET_READY',
|
||||
|
||||
GOT_VK_USER: 'GOT_VK_USER',
|
||||
KEY_PRESSED: 'KEY_PRESSED',
|
||||
|
||||
IFRAME_LOGIN_VK: 'IFRAME_LOGIN_VK',
|
||||
|
||||
|
@ -68,21 +14,13 @@ export const USER_ACTIONS: IActions = {
|
|||
SEARCH_SET_LOADING: 'SEARCH_SET_LOADING',
|
||||
|
||||
OPEN_MAP_DIALOG: 'OPEN_MAP_DIALOG',
|
||||
SET_SPEED: 'SET_SPEED',
|
||||
|
||||
SET_MARKERS_SHOWN: 'SET_MARKERS_SHOWN',
|
||||
|
||||
GET_GPX_TRACK: 'GET_GPX_TRACK',
|
||||
SET_IS_EMPTY: 'SET_IS_EMPTY',
|
||||
|
||||
MAPS_LOAD_MORE: 'MAPS_LOAD_MORE',
|
||||
MAPS_SET_SHIFT: 'MAPS_SET_SHIFT',
|
||||
|
||||
SET_FEATURE: 'SET_FEATURE',
|
||||
SET_IS_ROUTING: 'SET_IS_ROUTING',
|
||||
|
||||
DROP_ROUTE: 'DROP_ROUTE',
|
||||
SET_STARRED: 'SET_STARRED',
|
||||
MODIFY_ROUTE: 'MODIFY_ROUTE',
|
||||
|
||||
SET_ROUTE_STARRED: 'SET_ROUTE_STARRED',
|
||||
TOGGLE_ROUTE_STARRED: 'TOGGLE_ROUTE_STARRED',
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { IRootState } from ".";
|
||||
import * as ActionCreators from './actions'
|
||||
import { TIPS } from "~/constants/tips";
|
||||
import { TABS } from "~/constants/dialogs";
|
||||
import { USER_ACTIONS } from "./constants";
|
||||
|
||||
|
@ -10,11 +9,6 @@ export interface ActionHandler<T> {
|
|||
(state: IRootState, payload: UnsafeReturnType<T>): IRootState;
|
||||
}
|
||||
|
||||
const getEstimated = (distance: number, speed: number = 15): number => {
|
||||
const time = (distance && (distance / speed)) || 0;
|
||||
return (time && parseFloat(time.toFixed(1)));
|
||||
};
|
||||
|
||||
const setUser: ActionHandler<typeof ActionCreators.setUser> = (state, { user }) => ({
|
||||
...state,
|
||||
user: {
|
||||
|
@ -23,121 +17,6 @@ const setUser: ActionHandler<typeof ActionCreators.setUser> = (state, { user })
|
|||
},
|
||||
});
|
||||
|
||||
const setEditing: ActionHandler<typeof ActionCreators.setEditing> = (state, { editing }) => ({
|
||||
...state, editing
|
||||
});
|
||||
|
||||
const setChanged: ActionHandler<typeof ActionCreators.setChanged> = (state, { changed }) => ({
|
||||
...state,
|
||||
changed
|
||||
});
|
||||
|
||||
const setMode: ActionHandler<typeof ActionCreators.setMode> = (state, { mode }) => ({
|
||||
...state,
|
||||
mode
|
||||
});
|
||||
|
||||
const setDistance: ActionHandler<typeof ActionCreators.setDistance> = (state, { distance }) => ({
|
||||
...state,
|
||||
distance,
|
||||
estimated: getEstimated(distance, state.speed),
|
||||
});
|
||||
|
||||
const setRouterPoints: ActionHandler<typeof ActionCreators.setRouterPoints> = (state, { routerPoints }) => ({
|
||||
...state,
|
||||
routerPoints,
|
||||
});
|
||||
|
||||
const setActiveSticker: ActionHandler<typeof ActionCreators.setActiveSticker> = (state, { activeSticker }) => ({
|
||||
...state,
|
||||
activeSticker: activeSticker || { set: null, sticker: null }
|
||||
});
|
||||
|
||||
// const setLogo: ActionHandler<typeof ActionCreators.setLogo> = (state, { logo }) => ({
|
||||
// ...state,
|
||||
// logo
|
||||
// });
|
||||
|
||||
// const setTitle: ActionHandler<typeof ActionCreators.setTitle> = (state, { title }) => ({
|
||||
// ...state,
|
||||
// title
|
||||
// });
|
||||
|
||||
// const setDescription: ActionHandler<typeof ActionCreators.setDescription> = (state, { description }) => ({
|
||||
// ...state,
|
||||
// description
|
||||
// });
|
||||
|
||||
// const setAddress: ActionHandler<typeof ActionCreators.setAddress> = (state, { address }) => ({
|
||||
// ...state,
|
||||
// address
|
||||
// });
|
||||
|
||||
const setAddressOrigin: ActionHandler<typeof ActionCreators.setAddressOrigin> = (state, { address_origin }) => ({
|
||||
...state,
|
||||
address_origin
|
||||
});
|
||||
|
||||
const sendSaveRequest: ActionHandler<typeof ActionCreators.sendSaveRequest> = (state) => ({
|
||||
...state,
|
||||
save_processing: true,
|
||||
});
|
||||
|
||||
const setSaveError: ActionHandler<typeof ActionCreators.setSaveError> = (state, { save_error }) => ({
|
||||
...state, save_error, save_finished: false, save_processing: false
|
||||
});
|
||||
|
||||
const setSaveLoading: ActionHandler<typeof ActionCreators.setSaveLoading> = (state, { save_loading }) => ({
|
||||
...state, save_loading
|
||||
});
|
||||
|
||||
const setSaveOverwrite: ActionHandler<typeof ActionCreators.setSaveOverwrite> = (state) => ({
|
||||
...state,
|
||||
save_overwriting: true,
|
||||
save_finished: false,
|
||||
save_processing: false,
|
||||
save_error: TIPS.SAVE_OVERWRITE,
|
||||
});
|
||||
|
||||
const setSaveSuccess: ActionHandler<typeof ActionCreators.setSaveSuccess> = (state, { save_error }) => ({
|
||||
...state,
|
||||
save_overwriting: false,
|
||||
save_finished: true,
|
||||
save_processing: false,
|
||||
save_error,
|
||||
});
|
||||
|
||||
const resetSaveDialog: ActionHandler<typeof ActionCreators.resetSaveDialog> = (state) => ({
|
||||
...state, save_overwriting: false, save_finished: false, save_processing: false, save_error: '',
|
||||
});
|
||||
|
||||
const hideRenderer: ActionHandler<typeof ActionCreators.hideRenderer> = (state) => ({
|
||||
...state,
|
||||
renderer: { ...state.renderer, renderer_active: false }
|
||||
});
|
||||
|
||||
const setRenderer: ActionHandler<typeof ActionCreators.setRenderer> = (state, { payload }) => ({
|
||||
...state,
|
||||
renderer: { ...state.renderer, ...payload }
|
||||
});
|
||||
|
||||
// const setProvider: ActionHandler<typeof ActionCreators.setProvider> = (state, { provider }) => ({ ...state, provider });
|
||||
|
||||
const setDialog: ActionHandler<typeof ActionCreators.setDialog> = (state, { dialog }) => ({
|
||||
...state,
|
||||
dialog,
|
||||
});
|
||||
|
||||
const setDialogActive: ActionHandler<typeof ActionCreators.setDialogActive> = (state, { dialog_active }) => ({
|
||||
...state,
|
||||
dialog_active: dialog_active || !state.dialog_active,
|
||||
});
|
||||
|
||||
const setReady: ActionHandler<typeof ActionCreators.setReady> = (state, { ready = true }) => ({
|
||||
...state,
|
||||
ready,
|
||||
});
|
||||
|
||||
const searchSetTitle: ActionHandler<typeof ActionCreators.searchSetTitle> = (state, { title = '' }) => ({
|
||||
...state,
|
||||
routes: {
|
||||
|
@ -199,17 +78,8 @@ const searchSetLoading: ActionHandler<typeof ActionCreators.searchSetLoading> =
|
|||
}
|
||||
});
|
||||
|
||||
// const setPublic: ActionHandler<typeof ActionCreators.setPublic> = (state, { is_public = false }) => ({ ...state, is_public });
|
||||
const setStarred: ActionHandler<typeof ActionCreators.setStarred> = (state, { is_published = false }) => ({ ...state, is_published });
|
||||
|
||||
const setSpeed: ActionHandler<typeof ActionCreators.setSpeed> = (state, { speed = 15 }) => ({
|
||||
...state,
|
||||
speed,
|
||||
estimated: getEstimated(state.distance, speed),
|
||||
});
|
||||
|
||||
const setMarkersShown: ActionHandler<typeof ActionCreators.setMarkersShown> = (state, { markers_shown = true }) => ({ ...state, markers_shown });
|
||||
const setIsEmpty: ActionHandler<typeof ActionCreators.setIsEmpty> = (state, { is_empty = true }) => ({ ...state, is_empty });
|
||||
const mapsSetShift: ActionHandler<typeof ActionCreators.mapsSetShift> = (state, { shift = 0 }) => ({
|
||||
...state,
|
||||
routes: {
|
||||
|
@ -218,19 +88,6 @@ const mapsSetShift: ActionHandler<typeof ActionCreators.mapsSetShift> = (state,
|
|||
}
|
||||
});
|
||||
|
||||
const setFeature: ActionHandler<typeof ActionCreators.setFeature> = (state, { features }) => ({
|
||||
...state,
|
||||
features: {
|
||||
...state.features,
|
||||
...features,
|
||||
}
|
||||
});
|
||||
|
||||
const setIsRouting: ActionHandler<typeof ActionCreators.setIsRouting> = (state, { is_routing }) => ({
|
||||
...state,
|
||||
is_routing,
|
||||
});
|
||||
|
||||
const setRouteStarred: ActionHandler<typeof ActionCreators.setRouteStarred> = (state, { address, is_published }) => ({
|
||||
...state,
|
||||
routes: {
|
||||
|
@ -248,33 +105,6 @@ const setRouteStarred: ActionHandler<typeof ActionCreators.setRouteStarred> = (s
|
|||
|
||||
export const USER_HANDLERS = ({
|
||||
[USER_ACTIONS.SET_USER]: setUser,
|
||||
[USER_ACTIONS.SET_EDITING]: setEditing,
|
||||
[USER_ACTIONS.SET_CHANGED]: setChanged,
|
||||
[USER_ACTIONS.SET_MODE]: setMode,
|
||||
[USER_ACTIONS.SET_DISTANCE]: setDistance,
|
||||
[USER_ACTIONS.SET_ROUTER_POINTS]: setRouterPoints,
|
||||
[USER_ACTIONS.SET_ACTIVE_STICKER]: setActiveSticker,
|
||||
// [USER_ACTIONS.SET_LOGO]: setLogo,
|
||||
// [USER_ACTIONS.SET_TITLE]: setTitle,
|
||||
// [USER_ACTIONS.SET_DESCRIPTION]: setDescription,
|
||||
// [USER_ACTIONS.SET_ADDRESS]: setAddress,
|
||||
[USER_ACTIONS.SET_ADDRESS_ORIGIN]: setAddressOrigin,
|
||||
|
||||
[USER_ACTIONS.SET_SAVE_ERROR]: setSaveError,
|
||||
[USER_ACTIONS.SET_SAVE_LOADING]: setSaveLoading,
|
||||
[USER_ACTIONS.SET_SAVE_OVERWRITE]: setSaveOverwrite,
|
||||
[USER_ACTIONS.SET_SAVE_SUCCESS]: setSaveSuccess,
|
||||
[USER_ACTIONS.SEND_SAVE_REQUEST]: sendSaveRequest,
|
||||
[USER_ACTIONS.RESET_SAVE_DIALOG]: resetSaveDialog,
|
||||
|
||||
[USER_ACTIONS.HIDE_RENDERER]: hideRenderer,
|
||||
[USER_ACTIONS.SET_RENDERER]: setRenderer,
|
||||
|
||||
// [USER_ACTIONS.SET_PROVIDER]: setProvider,
|
||||
|
||||
[USER_ACTIONS.SET_DIALOG]: setDialog,
|
||||
[USER_ACTIONS.SET_DIALOG_ACTIVE]: setDialogActive,
|
||||
[USER_ACTIONS.SET_READY]: setReady,
|
||||
|
||||
[USER_ACTIONS.SEARCH_SET_TITLE]: searchSetTitle,
|
||||
[USER_ACTIONS.SEARCH_SET_DISTANCE]: searchSetDistance,
|
||||
|
@ -282,16 +112,10 @@ export const USER_HANDLERS = ({
|
|||
[USER_ACTIONS.SEARCH_SET_TAB]: searchSetTab,
|
||||
[USER_ACTIONS.SEARCH_PUT_ROUTES]: searchPutRoutes,
|
||||
[USER_ACTIONS.SEARCH_SET_LOADING]: searchSetLoading,
|
||||
// [USER_ACTIONS.SET_PUBLIC]: setPublic,
|
||||
[USER_ACTIONS.SET_STARRED]: setStarred,
|
||||
[USER_ACTIONS.SET_SPEED]: setSpeed,
|
||||
|
||||
[USER_ACTIONS.SET_MARKERS_SHOWN]: setMarkersShown,
|
||||
[USER_ACTIONS.SET_IS_EMPTY]: setIsEmpty,
|
||||
[USER_ACTIONS.MAPS_SET_SHIFT]: mapsSetShift,
|
||||
|
||||
[USER_ACTIONS.SET_FEATURE]: setFeature,
|
||||
[USER_ACTIONS.SET_IS_ROUTING]: setIsRouting,
|
||||
[USER_ACTIONS.SET_STARRED]: setStarred,
|
||||
|
||||
[USER_ACTIONS.SET_ROUTE_STARRED]: setRouteStarred,
|
||||
});
|
|
@ -1,8 +1,5 @@
|
|||
import { createReducer } from 'reduxsauce';
|
||||
import { DEFAULT_USER, IUser } from '~/constants/auth';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { DIALOGS, IDialogs } from '~/constants/dialogs';
|
||||
import { IStickers } from "~/constants/stickers";
|
||||
import { USER_HANDLERS } from './handlers';
|
||||
|
||||
export interface IRouteListItem {
|
||||
|
@ -15,50 +12,8 @@ export interface IRouteListItem {
|
|||
}
|
||||
|
||||
export interface IRootReducer {
|
||||
ready: boolean,
|
||||
// ready: boolean,
|
||||
user: IUser,
|
||||
editing: boolean,
|
||||
mode: typeof MODES[keyof typeof MODES],
|
||||
// logo: keyof typeof LOGOS,
|
||||
routerPoints: number,
|
||||
distance: number,
|
||||
// description: string,
|
||||
estimated: number,
|
||||
speed: number,
|
||||
activeSticker: { set?: keyof IStickers, sticker?: string },
|
||||
// title: string,
|
||||
// address: string,
|
||||
// address_origin: string,
|
||||
changed: boolean,
|
||||
// provider: keyof typeof PROVIDERS,
|
||||
markers_shown: boolean,
|
||||
|
||||
is_published: boolean,
|
||||
// is_public: boolean,
|
||||
is_empty: boolean,
|
||||
is_routing: boolean,
|
||||
|
||||
save_error: string,
|
||||
save_finished: boolean,
|
||||
save_overwriting: boolean,
|
||||
save_processing: boolean,
|
||||
save_loading: boolean,
|
||||
|
||||
dialog: IDialogs[keyof IDialogs],
|
||||
dialog_active: boolean,
|
||||
|
||||
features: {
|
||||
routing: boolean,
|
||||
},
|
||||
|
||||
renderer: {
|
||||
data: string,
|
||||
width: number,
|
||||
height: number
|
||||
renderer_active: boolean,
|
||||
info: string,
|
||||
progress: number,
|
||||
},
|
||||
|
||||
routes: {
|
||||
limit: 0,
|
||||
|
@ -81,53 +36,8 @@ export interface IRootReducer {
|
|||
export type IRootState = Readonly<IRootReducer>;
|
||||
|
||||
export const INITIAL_STATE: IRootReducer = {
|
||||
ready: false,
|
||||
user: { ...DEFAULT_USER },
|
||||
|
||||
mode: MODES.NONE,
|
||||
// logo: DEFAULT_LOGO,
|
||||
routerPoints: 0,
|
||||
distance: 0,
|
||||
// description: '',
|
||||
estimated: 0,
|
||||
speed: 15,
|
||||
activeSticker: { set: null, sticker: null },
|
||||
// title: '',
|
||||
// address: '',
|
||||
// address_origin: '',
|
||||
// provider: DEFAULT_PROVIDER,
|
||||
|
||||
markers_shown: true,
|
||||
changed: false,
|
||||
editing: false,
|
||||
|
||||
is_published: false,
|
||||
// is_public: false,
|
||||
is_empty: true,
|
||||
is_routing: false,
|
||||
|
||||
save_error: '',
|
||||
save_finished: false,
|
||||
save_overwriting: false,
|
||||
save_processing: false,
|
||||
save_loading: false,
|
||||
|
||||
dialog: DIALOGS.NONE,
|
||||
dialog_active: false,
|
||||
|
||||
features: {
|
||||
routing: false,
|
||||
},
|
||||
|
||||
renderer: {
|
||||
data: '',
|
||||
width: 0,
|
||||
height: 0,
|
||||
renderer_active: false,
|
||||
info: '',
|
||||
progress: 0,
|
||||
},
|
||||
|
||||
routes: {
|
||||
limit: 0,
|
||||
loading: false, // <-- maybe delete this
|
||||
|
|
|
@ -19,23 +19,23 @@ import {
|
|||
sendRouteStarred,
|
||||
} from '~/utils/api';
|
||||
import {
|
||||
hideRenderer,
|
||||
searchPutRoutes,
|
||||
searchSetLoading,
|
||||
setChanged,
|
||||
setDialogActive,
|
||||
setEditing,
|
||||
setMode,
|
||||
setReady,
|
||||
setRenderer,
|
||||
// hideRenderer,
|
||||
// setChanged,
|
||||
// setDialogActive,
|
||||
// setEditing,
|
||||
// setMode,
|
||||
// setReady,
|
||||
// setRenderer,
|
||||
// setDialog,
|
||||
// setAddressOrigin,
|
||||
// clearAll,
|
||||
// setFeature,
|
||||
searchSetTab,
|
||||
setUser,
|
||||
setDialog,
|
||||
setAddressOrigin,
|
||||
mapsSetShift,
|
||||
searchChangeDistance,
|
||||
clearAll,
|
||||
setFeature,
|
||||
searchPutRoutes,
|
||||
searchSetLoading,
|
||||
searchSetTitle,
|
||||
setRouteStarred,
|
||||
} from '~/redux/user/actions';
|
||||
|
@ -48,43 +48,22 @@ import {
|
|||
pushPath,
|
||||
} from '~/utils/history';
|
||||
import { USER_ACTIONS } from '~/redux/user/constants';
|
||||
import { MODES } from '~/constants/modes';
|
||||
import { DEFAULT_USER } from '~/constants/auth';
|
||||
import {
|
||||
composeArrows,
|
||||
composeDistMark,
|
||||
composeImages,
|
||||
composePoly,
|
||||
composeStickers,
|
||||
downloadCanvas,
|
||||
fetchImages,
|
||||
getPolyPlacement,
|
||||
getStickersPlacement,
|
||||
getTilePlacement,
|
||||
imageFetcher,
|
||||
} from '~/utils/renderer';
|
||||
import { LOGOS } from '~/constants/logos';
|
||||
|
||||
import { DIALOGS, TABS } from '~/constants/dialogs';
|
||||
|
||||
import * as ActionCreators from '~/redux/user/actions';
|
||||
import { downloadGPXTrack, getGPXString } from '~/utils/gpx';
|
||||
import { Unwrap } from '~/utils/middleware';
|
||||
import { IState } from '~/redux/store';
|
||||
import { selectUser, selectUserUser } from './selectors';
|
||||
import { mapInitSaga, loadMapSaga, replaceAddressIfItsBusy } from '~/redux/map/sagas';
|
||||
import { LatLng } from 'leaflet';
|
||||
import { selectMap } from '~/redux/map/selectors';
|
||||
import { editorSetDialog, editorSetDialogActive } from '../editor/actions';
|
||||
import { selectEditor } from '../editor/selectors';
|
||||
import { EDITOR_ACTIONS } from '../editor/constants';
|
||||
|
||||
// const getUser = (state: IState) => state.user.user;
|
||||
// const selectUser = (state: IState) => state.user;
|
||||
|
||||
const hideLoader = () => {
|
||||
document.getElementById('loader').style.opacity = String(0);
|
||||
document.getElementById('loader').style.pointerEvents = 'none';
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
function* generateGuestSaga() {
|
||||
const {
|
||||
data: { user, random_url },
|
||||
|
@ -95,52 +74,43 @@ function* generateGuestSaga() {
|
|||
return { ...user, random_url };
|
||||
}
|
||||
|
||||
function* startEditingSaga() {
|
||||
const { path } = getUrlData();
|
||||
yield pushPath(`/${path}/edit`);
|
||||
}
|
||||
// function* stopEditingSaga() {
|
||||
// const { changed, editing, mode, address_origin } = yield select(selectUser);
|
||||
// const { path } = getUrlData();
|
||||
|
||||
function* stopEditingSaga() {
|
||||
const { changed, editing, mode, address_origin } = yield select(selectUser);
|
||||
const { path } = getUrlData();
|
||||
// if (!editing) return;
|
||||
// if (changed && mode !== MODES.CONFIRM_CANCEL) {
|
||||
// yield put(setMode(MODES.CONFIRM_CANCEL));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (!editing) return;
|
||||
if (changed && mode !== MODES.CONFIRM_CANCEL) {
|
||||
yield put(setMode(MODES.CONFIRM_CANCEL));
|
||||
return;
|
||||
}
|
||||
// yield put(setMode(MODES.NONE));
|
||||
// yield put(setChanged(false));
|
||||
|
||||
// TODO: cancel editing?
|
||||
// yield editor.cancelEditing();
|
||||
yield put(setMode(MODES.NONE));
|
||||
yield put(setChanged(false));
|
||||
// TODO: dont close editor if theres no initial data
|
||||
// yield put(setEditing(editor.hasEmptyHistory)); // don't close editor if no previous map
|
||||
// yield pushPath(`/${address_origin || path}/`);
|
||||
// }
|
||||
|
||||
yield pushPath(`/${address_origin || path}/`);
|
||||
}
|
||||
// function* checkOSRMServiceSaga() {
|
||||
// const routing = yield call(checkOSRMService, [new LatLng(1,1), new LatLng(2,2)]);
|
||||
|
||||
function* checkOSRMServiceSaga() {
|
||||
const routing = yield call(checkOSRMService, [new LatLng(1,1), new LatLng(2,2)]);
|
||||
// yield put(setFeature({ routing }));
|
||||
// }
|
||||
|
||||
yield put(setFeature({ routing }));
|
||||
}
|
||||
// export function* setReadySaga() {
|
||||
// yield put(setReady(true));
|
||||
// hideLoader();
|
||||
|
||||
export function* setReadySaga() {
|
||||
yield put(setReady(true));
|
||||
hideLoader();
|
||||
|
||||
yield call(checkOSRMServiceSaga);
|
||||
yield put(searchSetTab(TABS.MY));
|
||||
}
|
||||
// yield call(checkOSRMServiceSaga);
|
||||
// yield put(searchSetTab(TABS.MY));
|
||||
// }
|
||||
|
||||
function* authCheckSaga({ key }: RehydrateAction) {
|
||||
if (key !== 'user') return;
|
||||
|
||||
pushLoaderState(70);
|
||||
|
||||
const { id, token } = yield select(selectUserUser);
|
||||
const { ready } = yield select(selectUser);
|
||||
const { id, token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
const { ready }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
if (window.location.search || true) {
|
||||
const { viewer_id, auth_key } = yield parseQuery(window.location.search);
|
||||
|
@ -215,128 +185,127 @@ function* authCheckSaga({ key }: RehydrateAction) {
|
|||
// return true;
|
||||
// }
|
||||
|
||||
// function* getRenderData() {
|
||||
// yield put(setRenderer({ info: 'Загрузка тайлов', progress: 0.1 }));
|
||||
|
||||
function* getRenderData() {
|
||||
yield put(setRenderer({ info: 'Загрузка тайлов', progress: 0.1 }));
|
||||
// const { route, stickers, provider }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
|
||||
const { route, stickers, provider }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
// const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
// canvas.width = window.innerWidth;
|
||||
// canvas.height = window.innerHeight;
|
||||
// const ctx = canvas.getContext('2d');
|
||||
|
||||
const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
// const geometry = getTilePlacement();
|
||||
// const points = getPolyPlacement(route);
|
||||
// const sticker_points = getStickersPlacement(stickers);
|
||||
// // TODO: get distance:
|
||||
// const distance = 0;
|
||||
// // const distance = editor.poly.poly.distance;
|
||||
|
||||
const geometry = getTilePlacement();
|
||||
const points = getPolyPlacement(route);
|
||||
const sticker_points = getStickersPlacement(stickers);
|
||||
// TODO: get distance:
|
||||
const distance = 0;
|
||||
// const distance = editor.poly.poly.distance;
|
||||
// ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// const images = yield fetchImages(ctx, geometry, provider);
|
||||
|
||||
const images = yield fetchImages(ctx, geometry, provider);
|
||||
// yield put(setRenderer({ info: 'Отрисовка', progress: 0.5 }));
|
||||
|
||||
yield put(setRenderer({ info: 'Отрисовка', progress: 0.5 }));
|
||||
// yield composeImages({ geometry, images, ctx });
|
||||
// yield composePoly({ points, ctx });
|
||||
// yield composeArrows({ points, ctx });
|
||||
// yield composeDistMark({ ctx, points, distance });
|
||||
// yield composeStickers({ stickers: sticker_points, ctx });
|
||||
|
||||
yield composeImages({ geometry, images, ctx });
|
||||
yield composePoly({ points, ctx });
|
||||
yield composeArrows({ points, ctx });
|
||||
yield composeDistMark({ ctx, points, distance });
|
||||
yield composeStickers({ stickers: sticker_points, ctx });
|
||||
// yield put(setRenderer({ info: 'Готово', progress: 1 }));
|
||||
|
||||
yield put(setRenderer({ info: 'Готово', progress: 1 }));
|
||||
// return yield canvas.toDataURL('image/jpeg');
|
||||
// }
|
||||
|
||||
return yield canvas.toDataURL('image/jpeg');
|
||||
}
|
||||
// function* takeAShotSaga() {
|
||||
// const worker = call(getRenderData);
|
||||
|
||||
function* takeAShotSaga() {
|
||||
const worker = call(getRenderData);
|
||||
// const { result, timeout } = yield race({
|
||||
// result: worker,
|
||||
// timeout: delay(500),
|
||||
// });
|
||||
|
||||
const { result, timeout } = yield race({
|
||||
result: worker,
|
||||
timeout: delay(500),
|
||||
});
|
||||
// if (timeout) yield put(setMode(MODES.SHOT_PREFETCH));
|
||||
|
||||
if (timeout) yield put(setMode(MODES.SHOT_PREFETCH));
|
||||
// const data = yield result || worker;
|
||||
|
||||
const data = yield result || worker;
|
||||
// yield put(setMode(MODES.NONE));
|
||||
// yield put(
|
||||
// setRenderer({
|
||||
// data,
|
||||
// renderer_active: true,
|
||||
// width: window.innerWidth,
|
||||
// height: window.innerHeight,
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
|
||||
yield put(setMode(MODES.NONE));
|
||||
yield put(
|
||||
setRenderer({
|
||||
data,
|
||||
renderer_active: true,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
})
|
||||
);
|
||||
}
|
||||
// function* getCropData({ x, y, width, height }) {
|
||||
// const {
|
||||
// logo,
|
||||
// renderer: { data },
|
||||
// } = yield select(selectUser);
|
||||
// const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
// canvas.width = width;
|
||||
// canvas.height = height;
|
||||
// const ctx = canvas.getContext('2d');
|
||||
// const image = yield imageFetcher(data);
|
||||
|
||||
function* getCropData({ x, y, width, height }) {
|
||||
const {
|
||||
logo,
|
||||
renderer: { data },
|
||||
} = yield select(selectUser);
|
||||
const canvas = <HTMLCanvasElement>document.getElementById('renderer');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const image = yield imageFetcher(data);
|
||||
// ctx.drawImage(image, -x, -y);
|
||||
|
||||
ctx.drawImage(image, -x, -y);
|
||||
// if (logo && LOGOS[logo][1]) {
|
||||
// const logoImage = yield imageFetcher(LOGOS[logo][1]);
|
||||
// ctx.drawImage(logoImage, width - logoImage.width, height - logoImage.height);
|
||||
// }
|
||||
|
||||
if (logo && LOGOS[logo][1]) {
|
||||
const logoImage = yield imageFetcher(LOGOS[logo][1]);
|
||||
ctx.drawImage(logoImage, width - logoImage.width, height - logoImage.height);
|
||||
}
|
||||
// return yield canvas.toDataURL('image/jpeg');
|
||||
// }
|
||||
|
||||
return yield canvas.toDataURL('image/jpeg');
|
||||
}
|
||||
// function* cropAShotSaga(params) {
|
||||
// const { title, address } = yield select(selectUser);
|
||||
// yield call(getCropData, params);
|
||||
// const canvas = document.getElementById('renderer') as HTMLCanvasElement;
|
||||
|
||||
function* cropAShotSaga(params) {
|
||||
const { title, address } = yield select(selectUser);
|
||||
yield call(getCropData, params);
|
||||
const canvas = document.getElementById('renderer') as HTMLCanvasElement;
|
||||
// downloadCanvas(canvas, (title || address).replace(/\./gi, ' '));
|
||||
|
||||
downloadCanvas(canvas, (title || address).replace(/\./gi, ' '));
|
||||
// return yield put(hideRenderer());
|
||||
// }
|
||||
|
||||
return yield put(hideRenderer());
|
||||
}
|
||||
// function* locationChangeSaga({ location }: ReturnType<typeof ActionCreators.locationChanged>) {
|
||||
// const {
|
||||
// address,
|
||||
// ready,
|
||||
// user: { id, random_url },
|
||||
// } = yield select(selectUser);
|
||||
|
||||
function* locationChangeSaga({ location }: ReturnType<typeof ActionCreators.locationChanged>) {
|
||||
const {
|
||||
address,
|
||||
ready,
|
||||
user: { id, random_url },
|
||||
} = yield select(selectUser);
|
||||
// const { owner }: ReturnType<typeof selectMap> = yield select(selectMap)
|
||||
|
||||
const { owner }: ReturnType<typeof selectMap> = yield select(selectMap)
|
||||
// if (!ready) return;
|
||||
|
||||
if (!ready) return;
|
||||
// const { path, mode } = getUrlData(location);
|
||||
|
||||
const { path, mode } = getUrlData(location);
|
||||
// if (address !== path) {
|
||||
// const map = yield call(loadMapSaga, path);
|
||||
|
||||
if (address !== path) {
|
||||
const map = yield call(loadMapSaga, path);
|
||||
// if (map && map.route && map.route.owner && mode === 'edit' && map.route.owner !== id) {
|
||||
// return yield call(replaceAddressIfItsBusy, map.random_url, map.address);
|
||||
// }
|
||||
// } else if (mode === 'edit' && owner.id !== id) {
|
||||
// return yield call(replaceAddressIfItsBusy, random_url, address);
|
||||
// } else {
|
||||
// yield put(setAddressOrigin(''));
|
||||
// }
|
||||
|
||||
if (map && map.route && map.route.owner && mode === 'edit' && map.route.owner !== id) {
|
||||
return yield call(replaceAddressIfItsBusy, map.random_url, map.address);
|
||||
}
|
||||
} else if (mode === 'edit' && owner.id !== id) {
|
||||
return yield call(replaceAddressIfItsBusy, random_url, address);
|
||||
} else {
|
||||
yield put(setAddressOrigin(''));
|
||||
}
|
||||
|
||||
if (mode !== 'edit') {
|
||||
yield put(setEditing(false));
|
||||
// editor.stopEditing();
|
||||
} else {
|
||||
yield put(setEditing(true));
|
||||
// editor.startEditing();
|
||||
}
|
||||
}
|
||||
// if (mode !== 'edit') {
|
||||
// yield put(setEditing(false));
|
||||
// // editor.stopEditing();
|
||||
// } else {
|
||||
// yield put(setEditing(true));
|
||||
// // editor.startEditing();
|
||||
// }
|
||||
// }
|
||||
|
||||
function* gotVkUserSaga({ user: u }: ReturnType<typeof ActionCreators.gotVkUser>) {
|
||||
const {
|
||||
|
@ -346,40 +315,40 @@ function* gotVkUserSaga({ user: u }: ReturnType<typeof ActionCreators.gotVkUser>
|
|||
yield put(setUser({ ...user, random_url }));
|
||||
}
|
||||
|
||||
function* keyPressedSaga({ key, target }: ReturnType<typeof ActionCreators.keyPressed>): any {
|
||||
if (target === 'INPUT' || target === 'TEXTAREA') {
|
||||
return;
|
||||
}
|
||||
// function* keyPressedSaga({ key, target }: ReturnType<typeof ActionCreators.keyPressed>): any {
|
||||
// if (target === 'INPUT' || target === 'TEXTAREA') {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (key === 'Escape') {
|
||||
const {
|
||||
dialog_active,
|
||||
mode,
|
||||
renderer: { renderer_active },
|
||||
} = yield select(selectUser);
|
||||
// if (key === 'Escape') {
|
||||
// const {
|
||||
// dialog_active,
|
||||
// mode,
|
||||
// renderer: { renderer_active },
|
||||
// } = yield select(selectUser);
|
||||
|
||||
if (renderer_active) return yield put(hideRenderer());
|
||||
if (dialog_active) return yield put(setDialogActive(false));
|
||||
if (mode !== MODES.NONE) return yield put(setMode(MODES.NONE));
|
||||
} else if (key === 'Delete') {
|
||||
const {
|
||||
user: { editing },
|
||||
} = yield select();
|
||||
// if (renderer_active) return yield put(hideRenderer());
|
||||
// if (dialog_active) return yield put(setDialogActive(false));
|
||||
// if (mode !== MODES.NONE) return yield put(setMode(MODES.NONE));
|
||||
// } else if (key === 'Delete') {
|
||||
// const {
|
||||
// user: { editing },
|
||||
// } = yield select();
|
||||
|
||||
if (!editing) return;
|
||||
// if (!editing) return;
|
||||
|
||||
const { mode } = yield select(selectUser);
|
||||
// const { mode } = yield select(selectUser);
|
||||
|
||||
if (mode === MODES.TRASH) {
|
||||
yield put(clearAll());
|
||||
} else {
|
||||
yield put(setMode(MODES.TRASH));
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (mode === MODES.TRASH) {
|
||||
// yield put(clearAll());
|
||||
// } else {
|
||||
// yield put(setMode(MODES.TRASH));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
function* searchGetRoutes() {
|
||||
const { token } = yield select(selectUserUser);
|
||||
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
|
||||
const {
|
||||
routes: {
|
||||
|
@ -387,7 +356,7 @@ function* searchGetRoutes() {
|
|||
shift,
|
||||
filter: { title, distance, tab },
|
||||
},
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const result: Unwrap<typeof getRouteList> = yield getRouteList({
|
||||
token,
|
||||
|
@ -442,14 +411,17 @@ function* searchSetSaga() {
|
|||
|
||||
function* openMapDialogSaga({ tab }: ReturnType<typeof ActionCreators.openMapDialog>) {
|
||||
const {
|
||||
dialog_active,
|
||||
routes: {
|
||||
filter: { tab: current },
|
||||
},
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const {
|
||||
dialog_active,
|
||||
}: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
if (dialog_active && tab === current) {
|
||||
return yield put(setDialogActive(false));
|
||||
return yield put(editorSetDialogActive(false));
|
||||
}
|
||||
|
||||
if (tab !== current) {
|
||||
|
@ -457,8 +429,8 @@ function* openMapDialogSaga({ tab }: ReturnType<typeof ActionCreators.openMapDia
|
|||
yield put(searchSetTab(tab));
|
||||
}
|
||||
|
||||
yield put(setDialog(DIALOGS.MAP_LIST));
|
||||
yield put(setDialogActive(true));
|
||||
yield put(editorSetDialog(DIALOGS.MAP_LIST));
|
||||
yield put(editorSetDialogActive(true));
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
@ -476,28 +448,28 @@ function* userLogoutSaga(): SagaIterator {
|
|||
}
|
||||
|
||||
function* setUserSaga() {
|
||||
const { dialog_active } = yield select(selectUser);
|
||||
const { dialog_active }: ReturnType<typeof selectEditor> = yield select(selectEditor);
|
||||
|
||||
if (dialog_active) yield call(searchSetSagaWorker);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function* getGPXTrackSaga(): SagaIterator {
|
||||
const { route, stickers }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
const { title, address } = yield select(selectUser);
|
||||
// function* getGPXTrackSaga(): SagaIterator {
|
||||
// const { route, stickers }: ReturnType<typeof selectMap> = yield select(selectMap);
|
||||
// const { title, address } = yield select(selectUser);
|
||||
|
||||
if (!route || route.length <= 0) return;
|
||||
// if (!route || route.length <= 0) return;
|
||||
|
||||
const track = getGPXString({ route, stickers, title: title || address });
|
||||
// const track = getGPXString({ route, stickers, title: title || address });
|
||||
|
||||
return downloadGPXTrack({ track, title });
|
||||
}
|
||||
// return downloadGPXTrack({ track, title });
|
||||
// }
|
||||
|
||||
function* mapsLoadMoreSaga() {
|
||||
const {
|
||||
routes: { limit, list, shift, step, loading, filter },
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
if (loading || list.length >= limit || limit === 0) return;
|
||||
|
||||
|
@ -540,7 +512,7 @@ function* mapsLoadMoreSaga() {
|
|||
}
|
||||
|
||||
function* dropRouteSaga({ address }: ReturnType<typeof ActionCreators.dropRoute>): SagaIterator {
|
||||
const { token } = yield select(selectUserUser);
|
||||
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
const {
|
||||
routes: {
|
||||
list,
|
||||
|
@ -549,7 +521,7 @@ function* dropRouteSaga({ address }: ReturnType<typeof ActionCreators.dropRoute>
|
|||
limit,
|
||||
filter: { min, max },
|
||||
},
|
||||
} = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const index = list.findIndex(el => el.address === address);
|
||||
|
||||
|
@ -574,7 +546,7 @@ function* modifyRouteSaga({
|
|||
title,
|
||||
is_public,
|
||||
}: ReturnType<typeof ActionCreators.modifyRoute>): SagaIterator {
|
||||
const { token } = yield select(selectUserUser);
|
||||
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
const {
|
||||
routes: {
|
||||
list,
|
||||
|
@ -606,12 +578,12 @@ function* modifyRouteSaga({
|
|||
function* toggleRouteStarredSaga({
|
||||
address,
|
||||
}: ReturnType<typeof ActionCreators.toggleRouteStarred>) {
|
||||
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
|
||||
const {
|
||||
routes: { list },
|
||||
}: IState['user'] = yield select(selectUser);
|
||||
}: ReturnType<typeof selectUser> = yield select(selectUser);
|
||||
|
||||
const route = list.find(el => el.address === address);
|
||||
const { token } = yield select(selectUserUser);
|
||||
|
||||
yield put(setRouteStarred(address, !route.is_published));
|
||||
const result = yield sendRouteStarred({
|
||||
|
@ -624,24 +596,24 @@ function* toggleRouteStarredSaga({
|
|||
}
|
||||
|
||||
export function* userSaga() {
|
||||
yield takeLatest(REHYDRATE, authCheckSaga);
|
||||
// yield takeEvery(USER_ACTIONS.STOP_EDITING, stopEditingSaga);
|
||||
// yield takeLatest(USER_ACTIONS.TAKE_A_SHOT, takeAShotSaga);
|
||||
// yield takeLatest(USER_ACTIONS.CROP_A_SHOT, cropAShotSaga);
|
||||
// yield takeLatest(USER_ACTIONS.LOCATION_CHANGED, locationChangeSaga);
|
||||
// yield takeLatest(USER_ACTIONS.KEY_PRESSED, keyPressedSaga);
|
||||
// yield takeLatest(USER_ACTIONS.GET_GPX_TRACK, getGPXTrackSaga);
|
||||
|
||||
yield takeEvery(USER_ACTIONS.START_EDITING, startEditingSaga);
|
||||
yield takeEvery(USER_ACTIONS.STOP_EDITING, stopEditingSaga);
|
||||
yield takeLatest(REHYDRATE, authCheckSaga);
|
||||
|
||||
yield takeEvery(USER_ACTIONS.USER_LOGOUT, userLogoutSaga);
|
||||
|
||||
// yield takeEvery(USER_ACTIONS.ROUTER_CANCEL, routerCancelSaga);
|
||||
// yield takeEvery(USER_ACTIONS.ROUTER_SUBMIT, routerSubmitSaga);
|
||||
|
||||
yield takeLatest(USER_ACTIONS.TAKE_A_SHOT, takeAShotSaga);
|
||||
yield takeLatest(USER_ACTIONS.CROP_A_SHOT, cropAShotSaga);
|
||||
|
||||
// yield takeEvery(USER_ACTIONS.CHANGE_PROVIDER, changeProviderSaga);
|
||||
yield takeLatest(USER_ACTIONS.LOCATION_CHANGED, locationChangeSaga);
|
||||
|
||||
yield takeLatest(USER_ACTIONS.GOT_VK_USER, gotVkUserSaga);
|
||||
yield takeLatest(USER_ACTIONS.KEY_PRESSED, keyPressedSaga);
|
||||
|
||||
// yield takeLatest(USER_ACTIONS.SET_TITLE, setTitleSaga);
|
||||
|
||||
|
@ -654,7 +626,6 @@ export function* userSaga() {
|
|||
yield takeLatest(USER_ACTIONS.SEARCH_SET_TAB, searchSetTabSaga);
|
||||
yield takeLatest(USER_ACTIONS.SET_USER, setUserSaga);
|
||||
|
||||
yield takeLatest(USER_ACTIONS.GET_GPX_TRACK, getGPXTrackSaga);
|
||||
yield takeLatest(USER_ACTIONS.MAPS_LOAD_MORE, mapsLoadMoreSaga);
|
||||
|
||||
yield takeLatest(USER_ACTIONS.DROP_ROUTE, dropRouteSaga);
|
||||
|
|
|
@ -2,7 +2,3 @@ import { IState } from '~/redux/store'
|
|||
|
||||
export const selectUser = (state: IState) => state.user;
|
||||
export const selectUserUser = (state: IState) => state.user.user;
|
||||
export const selectUserEditing = (state: IState) => state.user.editing;
|
||||
export const selectUserMode = (state: IState) => state.user.mode;
|
||||
export const selectUserActiveSticker = (state: IState) => state.user.activeSticker;
|
||||
export const selectUserRenderer = (state: IState) => state.user.renderer;
|
|
@ -164,4 +164,7 @@ export const toTranslit = (string: string = ''): string =>
|
|||
|
||||
export const parseDesc = (text: string = ''): string => text.replace(/(\n{2,})/gi, '\n\n');
|
||||
|
||||
// export const colorizeTitle = (text: string): string => text.replace(/(\[[^\]^]+\])/, ``)
|
||||
export const getEstimated = (distance: number, speed: number = 15): number => {
|
||||
const time = (distance && (distance / speed)) || 0;
|
||||
return (time && parseFloat(time.toFixed(1)));
|
||||
};
|
|
@ -23,5 +23,8 @@
|
|||
"./src/index.tsx",
|
||||
"./backend/**/*",
|
||||
"./custom.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"./src/_modules/**/*"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue