modified to match golang backend

This commit is contained in:
Fedor Katurov 2019-12-12 17:22:57 +07:00
parent 62cb8d8e18
commit 2144af9899
13 changed files with 296 additions and 235 deletions

View file

@ -16,7 +16,7 @@ import { isMobile } from '$utils/window';
import classnames from 'classnames'; import classnames from 'classnames';
import * as Range from 'rc-slider/lib/Range'; import * as Range from 'rc-slider/lib/Range';
import { TABS } from '$constants/dialogs'; import { TABS, TABS_TITLES } from '$constants/dialogs';
import { Icon } from '$components/panels/Icon'; import { Icon } from '$components/panels/Icon';
import { pushPath } from '$utils/history'; import { pushPath } from '$utils/history';
import { IRootState, IRouteListItem } from '$redux/user/reducer'; import { IRootState, IRouteListItem } from '$redux/user/reducer';
@ -110,12 +110,12 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
} }
}; };
dropRoute = (_id: string): void => { dropRoute = (address: string): void => {
this.props.dropRoute(_id); this.props.dropRoute(address);
}; };
modifyRoute = ({ _id, title, is_public }: { _id: string, title: string, is_public: boolean }): void => { modifyRoute = ({ address, title, is_public }: { address: string, title: string, is_public: boolean }): void => {
this.props.modifyRoute(_id, { title, is_public }); this.props.modifyRoute(address, { title, is_public });
this.stopEditing(); this.stopEditing();
}; };
@ -161,13 +161,13 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
} }
<div className="dialog-tabs"> <div className="dialog-tabs">
{ {
Object.keys(TABS).map(item => (role === ROLES.admin || item !== 'all') && ( Object.values(TABS).map(item => (role === ROLES.admin || item !== TABS.PENDING) && (
<div <div
className={classnames('dialog-tab', { active: tab === item })} className={classnames('dialog-tab', { active: tab === item })}
onClick={() => this.props.searchSetTab(item)} onClick={() => this.props.searchSetTab(item)}
key={item} key={item}
> >
{TABS[item]} {TABS_TITLES[item]}
</div> </div>
)) ))
} }
@ -211,9 +211,9 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
<RouteRowWrapper <RouteRowWrapper
title={route.title} title={route.title}
distance={route.distance} distance={route.distance}
_id={route.address} address={route.address}
is_public={route.is_public} is_public={route.is_public}
is_starred={route.is_starred} is_published={route.is_published}
tab={tab} tab={tab}
is_editing_mode={is_dropping ? 'drop' : 'edit'} is_editing_mode={is_dropping ? 'drop' : 'edit'}
is_editing_target={editor_target === route.address} is_editing_target={editor_target === route.address}

View file

@ -6,13 +6,13 @@ import { Tooltip } from "$components/panels/Tooltip";
import { ReactElement } from "react"; import { ReactElement } from "react";
interface Props { interface Props {
_id: string, address: string,
stopEditing: typeof MapListDialog.stopEditing, stopEditing: typeof MapListDialog.stopEditing,
dropRoute: typeof MapListDialog.dropRoute, dropRoute: typeof MapListDialog.dropRoute,
} }
export const RouteRowDrop = ({ export const RouteRowDrop = ({
_id, stopEditing, dropRoute, address, stopEditing, dropRoute,
}: Props): ReactElement<Props, null> => ( }: Props): ReactElement<Props, null> => (
<div <div
className="route-row-drop" className="route-row-drop"
@ -21,7 +21,7 @@ export const RouteRowDrop = ({
className="route-row" className="route-row"
> >
<div className="button-group"> <div className="button-group">
<div className="button" onClick={dropRoute.bind(null, _id)}>Удалить</div> <div className="button" onClick={dropRoute.bind(null, address)}>Удалить</div>
<div className="button primary" onClick={stopEditing}>Отмена</div> <div className="button primary" onClick={stopEditing}>Отмена</div>
</div> </div>
</div> </div>

View file

@ -6,7 +6,7 @@ import { MapListDialog } from "$components/dialogs/MapListDialog";
interface Props { interface Props {
title: string; title: string;
_id: string; address: string;
is_public: boolean, is_public: boolean,
modifyRoute: typeof MapListDialog.modifyRoute, modifyRoute: typeof MapListDialog.modifyRoute,
} }
@ -29,10 +29,10 @@ export class RouteRowEditor extends React.Component<Props, State> {
stopEditing = () => { stopEditing = () => {
const { const {
state: { title, is_public }, state: { title, is_public },
props: { _id } props: { address }
} = this; } = this;
this.props.modifyRoute({ _id, title, is_public }) this.props.modifyRoute({ address, title, is_public })
}; };
setPublic = () => this.setState({ is_public: !this.state.is_public }); setPublic = () => this.setState({ is_public: !this.state.is_public });

View file

@ -1,93 +1,100 @@
// @flow // @flow
import * as React from 'react'; import * as React from "react";
import { Icon } from '$components/panels/Icon'; import { Icon } from "$components/panels/Icon";
import { MapListDialog } from "$components/dialogs/MapListDialog"; import { MapListDialog } from "$components/dialogs/MapListDialog";
import { Tooltip } from "$components/panels/Tooltip"; import { Tooltip } from "$components/panels/Tooltip";
import { ReactElement } from "react"; import { ReactElement } from "react";
import classnames from 'classnames'; import classnames from "classnames";
import { toggleRouteStarred } from "$redux/user/actions"; import { toggleRouteStarred } from "$redux/user/actions";
import { TABS } from "$constants/dialogs";
interface Props { interface Props {
tab: string, tab: string;
_id: string, address: string;
title: string, title: string;
distance: number, distance: number;
is_public: boolean, is_public: boolean;
is_admin: boolean, is_admin: boolean;
is_starred: boolean, is_published: boolean;
openRoute: typeof MapListDialog.openRoute, openRoute: typeof MapListDialog.openRoute;
toggleStarred: typeof MapListDialog.toggleStarred, toggleStarred: typeof MapListDialog.toggleStarred;
startEditing: typeof MapListDialog.startEditing, startEditing: typeof MapListDialog.startEditing;
stopEditing: typeof MapListDialog.stopEditing, stopEditing: typeof MapListDialog.stopEditing;
showMenu: typeof MapListDialog.showMenu, showMenu: typeof MapListDialog.showMenu;
hideMenu: typeof MapListDialog.hideMenu, hideMenu: typeof MapListDialog.hideMenu;
showDropCard: typeof MapListDialog.showDropCard, showDropCard: typeof MapListDialog.showDropCard;
} }
export const RouteRowView = ({ export const RouteRowView = ({
title, distance, _id, openRoute, tab, startEditing, showMenu, showDropCard, hideMenu, is_admin, is_starred, toggleStarred, title,
distance,
address,
openRoute,
tab,
startEditing,
showMenu,
showDropCard,
hideMenu,
is_admin,
is_published,
toggleStarred
}: Props): ReactElement<Props, null> => ( }: Props): ReactElement<Props, null> => (
<div <div className={classnames("route-row-view", { has_menu: tab === "my" })}>
className={classnames('route-row-view', { has_menu: (tab === 'my') })} {(tab === TABS.PENDING || tab === TABS.STARRED) && is_admin && (
> <div className="route-row-fav" onClick={toggleStarred.bind(null, address)}>
{ {is_published ? (
(tab === 'all' || tab === 'starred') && is_admin && <Icon icon="icon-star-fill" size={24} />
<div className="route-row-fav" onClick={toggleStarred.bind(null, _id)}> ) : (
{ <Icon icon="icon-star-blank" size={24} />
is_starred )}
? <Icon icon="icon-star-fill" size={24} />
: <Icon icon="icon-star-blank" size={24} />
}
</div> </div>
} )}
<div <div className="route-row" onClick={() => openRoute(address)}>
className="route-row"
onClick={() => openRoute(_id)}
>
<div className="route-title"> <div className="route-title">
{ {(tab === "my" || !is_admin) && is_published && (
(tab === 'my' || !is_admin) && is_starred && <div className="route-row-corner">
<div className="route-row-corner"><Icon icon="icon-star-fill" size={18} /></div> <Icon icon="icon-star-fill" size={18} />
} </div>
<span> )}
{(title || _id)} <span>{title || address}</span>
</span>
</div> </div>
<div className="route-description"> <div className="route-description">
<span> <span>
<Icon icon="icon-link-1" /> <Icon icon="icon-link-1" />
{_id} {address}
</span> </span>
<span> <span>
<Icon icon="icon-cycle-1" /> <Icon icon="icon-cycle-1" />
{(distance && `${distance} km`) || '0 km'} {(distance && `${distance} km`) || "0 km"}
</span> </span>
</div> </div>
</div> </div>
{ {tab === "my" && (
tab === 'my' && <React.Fragment>
<React.Fragment> <div
<div className="route-row-edit-button pointer"
className="route-row-edit-button pointer" onMouseOver={showMenu.bind(null, address)}
onMouseOver={showMenu.bind(null, _id)} onMouseOut={hideMenu}
onMouseOut={hideMenu} >
> <Icon icon="icon-more-vert" />
<Icon icon="icon-more-vert" /> <div className="route-row-edit-menu pointer">
<div className="route-row-edit-menu pointer"> <div onMouseDown={showDropCard.bind(null, address)}>
<div onMouseDown={showDropCard.bind(null, _id)}> <Tooltip>Удалить</Tooltip>
<Tooltip>Удалить</Tooltip> <Icon icon="icon-trash-3" size={32} />
<Icon icon="icon-trash-3" size={32} /> </div>
</div> <div
<div onMouseDown={startEditing.bind(null, _id)} className="modify-button"> onMouseDown={startEditing.bind(null, address)}
<Tooltip>Редактировать</Tooltip> className="modify-button"
<Icon icon="icon-edit-1" size={32} /> >
</div> <Tooltip>Редактировать</Tooltip>
<Icon icon="icon-edit-1" size={32} />
</div> </div>
</div> </div>
</React.Fragment> </div>
} </React.Fragment>
)}
</div> </div>
); );

View file

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

View file

@ -11,7 +11,7 @@ import { Icon } from '$components/panels/Icon';
import classnames from 'classnames'; import classnames from 'classnames';
import { CLIENT } from '$config/frontend'; import { CLIENT } from '$config/frontend';
import { DIALOGS } from '$constants/dialogs'; import { DIALOGS, TABS } from '$constants/dialogs';
import { IRootState } from "$redux/user/reducer"; import { IRootState } from "$redux/user/reducer";
import { Tooltip } from "$components/panels/Tooltip"; import { Tooltip } from "$components/panels/Tooltip";
import { TitleDialog } from "$components/dialogs/TitleDialog"; import { TitleDialog } from "$components/dialogs/TitleDialog";
@ -65,7 +65,7 @@ export class Component extends React.PureComponent<Props, State> {
setMenuOpened = () => this.setState({ menuOpened: !this.state.menuOpened }); setMenuOpened = () => this.setState({ menuOpened: !this.state.menuOpened });
openMapsDialog = () => { openMapsDialog = () => {
this.props.openMapDialog('my'); this.props.openMapDialog(TABS.MY);
}; };
openAppInfoDialog = () => { openAppInfoDialog = () => {

View file

@ -1,16 +1,16 @@
import { CLIENT } from '$config/frontend'; import { CLIENT } from '$config/frontend';
export const API: { [x: string]: string } = { export const API = {
GET_GUEST: `${CLIENT.API_ADDR}/api/auth/`, GET_GUEST: `${CLIENT.API_ADDR}/api/auth/`,
CHECK_TOKEN: `${CLIENT.API_ADDR}/api/auth/`, CHECK_TOKEN: `${CLIENT.API_ADDR}/api/auth/`,
IFRAME_LOGIN_VK: `${CLIENT.API_ADDR}/api/auth/vk/`, IFRAME_LOGIN_VK: `${CLIENT.API_ADDR}/api/auth/vk`,
GET_MAP: `${CLIENT.API_ADDR}/api/route/`, GET_MAP: `${CLIENT.API_ADDR}/api/route/`,
POST_MAP: `${CLIENT.API_ADDR}/api/route/`, POST_MAP: `${CLIENT.API_ADDR}/api/route/`,
GET_ROUTE_LIST: `${CLIENT.API_ADDR}/api/route/list/`, GET_ROUTE_LIST: tab => `${CLIENT.API_ADDR}/api/route/list/${tab}`,
DROP_ROUTE: `${CLIENT.API_ADDR}/api/route/`, DROP_ROUTE: `${CLIENT.API_ADDR}/api/route/`,
MODIFY_ROUTE: `${CLIENT.API_ADDR}/api/route/`, MODIFY_ROUTE: `${CLIENT.API_ADDR}/api/route/`,
SET_STARRED: `${CLIENT.API_ADDR}/api/route/publish/`, SET_STARRED: `${CLIENT.API_ADDR}/api/route/publish`,
}; };
export const API_RETRY_INTERVAL = 10; export const API_RETRY_INTERVAL = 10;

View file

@ -5,9 +5,9 @@ export interface IDialogs {
} }
export interface IMapTabs { export interface IMapTabs {
my: string, MY: string,
all: string, PENDING: string,
starred: string, STARRED: string,
} }
export const DIALOGS: IDialogs = ({ export const DIALOGS: IDialogs = ({
@ -16,8 +16,14 @@ export const DIALOGS: IDialogs = ({
APP_INFO: 'APP_INFO', APP_INFO: 'APP_INFO',
}); });
export const TABS: IMapTabs = ({ export const TABS: IMapTabs = {
my: 'Мои', MY: 'my',
all: 'Заявки', PENDING: 'pending',
starred: 'Каталог', STARRED: 'starred',
}
export const TABS_TITLES = ({
[TABS.MY]: 'Мои',
[TABS.PENDING]: 'Заявки',
[TABS.STARRED]: 'Каталог',
}); });

View file

@ -45,7 +45,7 @@ interface IEditor {
stickers: any, stickers: any,
provider: IRootState['provider'], provider: IRootState['provider'],
is_public: IRootState['is_public'], is_public: IRootState['is_public'],
is_starred: IRootState['is_starred'], is_published: IRootState['is_published'],
description: IRootState['description'], description: IRootState['description'],
logo: IRootState['logo'], logo: IRootState['logo'],
}; };
@ -160,7 +160,7 @@ export class Editor {
stickers: null, stickers: null,
provider: null, provider: null,
is_public: false, is_public: false,
is_starred: false, is_published: false,
description: '', description: '',
logo: null, logo: null,
}; };
@ -320,7 +320,7 @@ export class Editor {
provider = DEFAULT_PROVIDER, provider = DEFAULT_PROVIDER,
logo = DEFAULT_LOGO, logo = DEFAULT_LOGO,
is_public, is_public,
is_starred, is_published,
description, description,
}: Partial<IEditor['initialData']>): void => { }: Partial<IEditor['initialData']>): void => {
this.setTitle(title || ''); this.setTitle(title || '');
@ -348,7 +348,7 @@ export class Editor {
} }
this.setPublic(is_public); this.setPublic(is_public);
this.setStarred(is_starred); this.setStarred(is_published);
this.setDescription(description); this.setDescription(description);
this.setLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO); this.setLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO);
@ -382,7 +382,7 @@ export class Editor {
setInitialData = (): void => { setInitialData = (): void => {
const { path } = getUrlData(); const { path } = getUrlData();
const { id } = this.getUser(); const { id } = this.getUser();
const { is_public, logo, is_starred , description} = this.getState(); const { is_public, logo, is_published , description} = this.getState();
const { route, stickers, provider } = this.dumpData(); const { route, stickers, provider } = this.dumpData();
this.initialData = { this.initialData = {
@ -396,7 +396,7 @@ export class Editor {
provider, provider,
is_public, is_public,
logo, logo,
is_starred, is_published,
description, description,
}; };
}; };

View file

@ -17,7 +17,7 @@ export const setDescription = description => ({ type: ACTIONS.SET_DESCRIPTION, d
export const setAddress = address => ({ type: ACTIONS.SET_ADDRESS, address }); export const setAddress = address => ({ type: ACTIONS.SET_ADDRESS, address });
export const setAddressOrigin = address_origin => ({ type: ACTIONS.SET_ADDRESS_ORIGIN, address_origin }); export const setAddressOrigin = address_origin => ({ type: ACTIONS.SET_ADDRESS_ORIGIN, address_origin });
export const setPublic = is_public => ({ type: ACTIONS.SET_PUBLIC, is_public }); export const setPublic = is_public => ({ type: ACTIONS.SET_PUBLIC, is_public });
export const setStarred = is_starred => ({ type: ACTIONS.SET_STARRED, is_starred }); export const setStarred = is_published => ({ type: ACTIONS.SET_STARRED, is_published });
export const setSpeed = speed => ({ type: ACTIONS.SET_SPEED, speed }); export const setSpeed = speed => ({ type: ACTIONS.SET_SPEED, speed });
export const startEditing = () => ({ type: ACTIONS.START_EDITING }); export const startEditing = () => ({ type: ACTIONS.START_EDITING });
@ -99,4 +99,4 @@ export const modifyRoute = (address: string, { title, is_public }: { title: stri
type: ACTIONS.MODIFY_ROUTE, address, title, is_public type: ACTIONS.MODIFY_ROUTE, address, title, is_public
}); });
export const toggleRouteStarred = (address: string) => ({ type: ACTIONS.TOGGLE_ROUTE_STARRED, address }); export const toggleRouteStarred = (address: string) => ({ type: ACTIONS.TOGGLE_ROUTE_STARRED, address });
export const setRouteStarred = (address: string, is_starred: boolean) => ({ type: ACTIONS.SET_ROUTE_STARRED, address, is_starred }); export const setRouteStarred = (address: string, is_published: boolean) => ({ type: ACTIONS.SET_ROUTE_STARRED, address, is_published });

View file

@ -20,7 +20,7 @@ export interface IRoute {
stickers: IStickerDump[], stickers: IStickerDump[],
provider: IRootState['provider'], provider: IRootState['provider'],
is_public: IRootState['is_public'], is_public: IRootState['is_public'],
is_published: IRootState['is_starred'], is_published: IRootState['is_published'],
description: IRootState['description'], description: IRootState['description'],
logo: IRootState['logo'], logo: IRootState['logo'],
distance: IRootState['distance'] distance: IRootState['distance']
@ -31,7 +31,7 @@ export interface IRouteListItem {
title: string, title: string,
distance: number, distance: number,
is_public: boolean, is_public: boolean,
is_starred: boolean, is_published: boolean,
updated_at: string, updated_at: string,
} }
@ -54,7 +54,7 @@ export interface IRootReducer {
provider: keyof typeof PROVIDERS, provider: keyof typeof PROVIDERS,
markers_shown: boolean, markers_shown: boolean,
is_starred: boolean, is_published: boolean,
is_public: boolean, is_public: boolean,
is_empty: boolean, is_empty: boolean,
is_routing: boolean, is_routing: boolean,
@ -271,7 +271,7 @@ const searchSetTab: ActionHandler<typeof ActionCreators.searchSetTab> = (state,
...state.routes, ...state.routes,
filter: { filter: {
...state.routes.filter, ...state.routes.filter,
tab: Object.keys(TABS).indexOf(tab) >= 0 ? tab : TABS[Object.keys(TABS)[0]], tab: Object.values(TABS).indexOf(tab) >= 0 ? tab : TABS[Object.values(TABS)[0]],
} }
} }
}); });
@ -304,7 +304,7 @@ const searchSetLoading: ActionHandler<typeof ActionCreators.searchSetLoading> =
}); });
const setPublic: ActionHandler<typeof ActionCreators.setPublic> = (state, { is_public = false }) => ({ ...state, is_public }); const setPublic: ActionHandler<typeof ActionCreators.setPublic> = (state, { is_public = false }) => ({ ...state, is_public });
const setStarred: ActionHandler<typeof ActionCreators.setStarred> = (state, { is_starred = false }) => ({ ...state, is_starred }); const setStarred: ActionHandler<typeof ActionCreators.setStarred> = (state, { is_published = false }) => ({ ...state, is_published });
const setSpeed: ActionHandler<typeof ActionCreators.setSpeed> = (state, { speed = 15 }) => ({ const setSpeed: ActionHandler<typeof ActionCreators.setSpeed> = (state, { speed = 15 }) => ({
...state, ...state,
@ -335,16 +335,16 @@ const setIsRouting: ActionHandler<typeof ActionCreators.setIsRouting> = (state,
is_routing, is_routing,
}); });
const setRouteStarred: ActionHandler<typeof ActionCreators.setRouteStarred> = (state, { address, is_starred }) => ({ const setRouteStarred: ActionHandler<typeof ActionCreators.setRouteStarred> = (state, { address, is_published }) => ({
...state, ...state,
routes: { routes: {
...state.routes, ...state.routes,
list: ( list: (
state.routes.list state.routes.list
.map(el => el.address === address ? { ...el, is_starred } : el) .map(el => el.address === address ? { ...el, is_published } : el)
.filter(el => ( .filter(el => (
(state.routes.filter.tab === 'starred' && el.is_starred) || (state.routes.filter.tab === TABS.STARRED && el.is_published) ||
(state.routes.filter.tab === 'all' && !el.is_starred) (state.routes.filter.tab === TABS.PENDING && !el.is_published)
)) ))
) )
} }
@ -421,7 +421,7 @@ export const INITIAL_STATE: IRootReducer = {
changed: false, changed: false,
editing: false, editing: false,
is_starred: false, is_published: false,
is_public: false, is_public: false,
is_empty: true, is_empty: true,
is_routing: false, is_routing: false,

View file

@ -82,7 +82,7 @@ import {
} from "$utils/renderer"; } from "$utils/renderer";
import { LOGOS } from "$constants/logos"; import { LOGOS } from "$constants/logos";
import { DEFAULT_PROVIDER } from "$constants/providers"; import { DEFAULT_PROVIDER } from "$constants/providers";
import { DIALOGS } from "$constants/dialogs"; import { DIALOGS, TABS } from "$constants/dialogs";
import * as ActionCreators from "$redux/user/actions"; import * as ActionCreators from "$redux/user/actions";
import { IRootState } from "$redux/user/reducer"; import { IRootState } from "$redux/user/reducer";
@ -152,7 +152,9 @@ function* stopEditingSaga() {
} }
function* loadMapSaga(path) { function* loadMapSaga(path) {
const { data: { route, error, random_url } }: Unwrap<typeof getStoredMap> = yield call(getStoredMap, { name: path }); const {
data: { route, error, random_url }
}: Unwrap<typeof getStoredMap> = yield call(getStoredMap, { name: path });
if (route && !error) { if (route && !error) {
yield editor.clearAll(); yield editor.clearAll();
@ -161,11 +163,11 @@ function* loadMapSaga(path) {
yield editor.setInitialData(); yield editor.setInitialData();
yield put(setChanged(false)); yield put(setChanged(false));
return { route, random_url }; return { route, random_url };
} }
return null return null;
} }
function* replaceAddressIfItsBusy(destination, original) { function* replaceAddressIfItsBusy(destination, original) {
@ -189,7 +191,7 @@ function* setReadySaga() {
hideLoader(); hideLoader();
yield call(checkOSRMServiceSaga); yield call(checkOSRMServiceSaga);
yield put(searchSetTab("my")); yield put(searchSetTab(TABS.MY));
} }
function* mapInitSaga() { function* mapInitSaga() {
@ -218,7 +220,13 @@ function* mapInitSaga() {
if (map && map.route) { if (map && map.route) {
if (mode && mode === "edit") { if (mode && mode === "edit") {
if (map && map.route && map.route.owner && mode === "edit" && map.route.owner !== id) { if (
map &&
map.route &&
map.route.owner &&
mode === "edit" &&
map.route.owner !== id
) {
yield call(setReadySaga); yield call(setReadySaga);
yield call(replaceAddressIfItsBusy, map.random_url, map.address); yield call(replaceAddressIfItsBusy, map.random_url, map.address);
} else { } else {
@ -403,19 +411,20 @@ function* sendSaveRequestSaga({
yield put(setSaveLoading(false)); yield put(setSaveLoading(false));
if (cancel) return yield put(setMode(MODES.NONE)); if (cancel) return yield put(setMode(MODES.NONE));
if (result && result.mode === "overwriting")
if (result && result.data.code === "already_exist")
return yield put(setSaveOverwrite()); return yield put(setSaveOverwrite());
if (result && result.mode === "exists") if (result && result.data.code === "conflict")
return yield put(setSaveError(TIPS.SAVE_EXISTS)); return yield put(setSaveError(TIPS.SAVE_EXISTS));
if (timeout || !result || !result.success || !result.address) if (timeout || !result || !result.data.route || !result.data.route.address)
return yield put(setSaveError(TIPS.SAVE_TIMED_OUT)); return yield put(setSaveError(TIPS.SAVE_TIMED_OUT));
return yield put( return yield put(
setSaveSuccess({ setSaveSuccess({
address: result.address, address: result.data.route.address,
title: result.title, title: result.data.route.title,
is_public: result.is_public, is_public: result.data.route.is_public,
description: result.description, description: result.data.route.description,
save_error: TIPS.SAVE_SUCCESS save_error: TIPS.SAVE_SUCCESS
}) })
@ -533,8 +542,7 @@ function* locationChangeSaga({
const { const {
address, address,
ready, ready,
user: { id, random_url }, user: { id, random_url }
is_public
} = yield select(getState); } = yield select(getState);
if (!ready) return; if (!ready) return;
@ -544,7 +552,14 @@ function* locationChangeSaga({
if (address !== path) { if (address !== path) {
const map = yield call(loadMapSaga, path); const map = yield call(loadMapSaga, path);
if (map && map.route && map.route.owner && mode === "edit" && map.route.owner !== id) { if (
map &&
map.route &&
map.route.owner &&
mode === "edit" &&
map.route.owner !== id
) {
console.log("replace address if its busy");
return yield call(replaceAddressIfItsBusy, map.random_url, map.address); return yield call(replaceAddressIfItsBusy, map.random_url, map.address);
} }
} else if (mode === "edit" && editor.owner !== id) { } else if (mode === "edit" && editor.owner !== id) {
@ -608,7 +623,7 @@ function* keyPressedSaga({
} }
function* searchGetRoutes() { function* searchGetRoutes() {
const { id, token } = yield select(getUser); const { token } = yield select(getUser);
const { const {
routes: { routes: {
@ -669,7 +684,7 @@ function* searchSetSagaWorker() {
function* searchSetSaga() { function* searchSetSaga() {
yield put(searchSetLoading(true)); yield put(searchSetLoading(true));
yield put(mapsSetShift(0)); yield put(mapsSetShift(0));
yield delay(500); yield delay(300);
yield call(searchSetSagaWorker); yield call(searchSetSagaWorker);
} }
@ -772,30 +787,45 @@ function* mapsLoadMoreSaga() {
if (loading || list.length >= limit || limit === 0) return; if (loading || list.length >= limit || limit === 0) return;
yield delay(100); yield delay(50);
yield put(searchSetLoading(true)); yield put(searchSetLoading(true));
yield put(mapsSetShift(shift + step)); yield put(mapsSetShift(shift + step));
const result = yield call(searchGetRoutes); const {
data: {
limits: { min, max, count },
filter: { shift: resp_shift, step: resp_step },
routes
}
}: Unwrap<typeof getRouteList> = yield call(searchGetRoutes);
if ( if (
(filter.min > result.min && filter.distance[0] <= filter.min) || (filter.min > min && filter.distance[0] <= filter.min) ||
(filter.max < result.max && filter.distance[1] >= filter.max) (filter.max < max && filter.distance[1] >= filter.max)
) { ) {
yield put( yield put(
searchChangeDistance([ searchChangeDistance([
filter.min > result.min && filter.distance[0] <= filter.min filter.min > min && filter.distance[0] <= filter.min
? result.min ? min
: filter.distance[0], : filter.distance[0],
filter.max < result.max && filter.distance[1] >= filter.max filter.max < max && filter.distance[1] >= filter.max
? result.max ? max
: filter.distance[1] : filter.distance[1]
]) ])
); );
} }
yield put(searchPutRoutes({ ...result, list: [...list, ...result.list] })); yield put(
searchPutRoutes({
min,
max,
limit: count,
shift: resp_shift,
step: resp_step,
list: [...list, ...routes]
})
);
yield put(searchSetLoading(false)); yield put(searchSetLoading(false));
} }
@ -875,17 +905,16 @@ function* toggleRouteStarredSaga({
}: IState["user"] = yield select(getState); }: IState["user"] = yield select(getState);
const route = list.find(el => el.address === address); const route = list.find(el => el.address === address);
const { id, token } = yield select(getUser); const { token } = yield select(getUser);
yield put(setRouteStarred(address, !route.is_starred)); yield put(setRouteStarred(address, !route.is_published));
const result = yield sendRouteStarred({ const result = yield sendRouteStarred({
id,
token, token,
address, address,
is_starred: !route.is_starred is_published: !route.is_published
}); });
if (!result) return yield put(setRouteStarred(address, route.is_starred)); if (!result) return yield put(setRouteStarred(address, route.is_published));
} }
export function* userSaga() { export function* userSaga() {

View file

@ -90,25 +90,35 @@ export const postMap = ({
is_public, is_public,
description, description,
token token
}: Partial<IRoute> & { force: boolean; token: string }) => }: Partial<IRoute> & {
force: boolean;
token: string;
}): Promise<IResultWithStatus<{
route: IRoute;
error?: string;
code?: string;
}>> =>
axios axios
.post( .post(
API.POST_MAP, API.POST_MAP,
{ {
title, route: {
address, title,
route, address,
stickers, route,
force, stickers,
logo, logo,
distance, distance,
provider, provider,
is_public, is_public,
description description
},
force
}, },
configWithToken(token) configWithToken(token)
) )
.then(result => result && result.data && result.data); .then(resultMiddleware)
.catch(errorMiddleware);
export const checkIframeToken = ({ export const checkIframeToken = ({
viewer_id, viewer_id,
@ -150,13 +160,12 @@ export const getRouteList = ({
}>> => }>> =>
axios axios
.get( .get(
API.GET_ROUTE_LIST, API.GET_ROUTE_LIST(tab),
configWithToken(token, { configWithToken(token, {
params: { params: {
search, search,
min, min,
max, max,
tab,
token, token,
step, step,
shift shift
@ -199,24 +208,25 @@ export const modifyRoute = ({
}): Promise<IResultWithStatus<{ }): Promise<IResultWithStatus<{
route: IRoute; route: IRoute;
}>> => }>> =>
axios.patch(
API.MODIFY_ROUTE,
{ address, token, is_public, title },
configWithToken(token)
);
export const sendRouteStarred = ({
id,
token,
address,
is_starred
}: {
id: string;
token: string;
address: string;
is_starred: boolean;
}): Promise<IResultWithStatus<{ route: IRoute }>> =>
axios axios
.post(API.SET_STARRED, { id, token, address, is_starred }) .patch(
API.MODIFY_ROUTE,
{ address, token, is_public, title },
configWithToken(token)
)
.then(resultMiddleware)
.catch(errorMiddleware);
export const sendRouteStarred = ({
token,
address,
is_published
}: {
token: string;
address: string;
is_published: boolean;
}): Promise<IResultWithStatus<{ route: IRoute }>> =>
axios
.post(API.SET_STARRED, { address, is_published }, configWithToken(token))
.then(resultMiddleware) .then(resultMiddleware)
.catch(errorMiddleware); .catch(errorMiddleware);