frontend is_starred and description support

This commit is contained in:
muerwre 2019-03-29 10:54:20 +07:00
parent a4b620471a
commit c040e33a8a
11 changed files with 103 additions and 26 deletions

7
package-lock.json generated
View file

@ -10749,6 +10749,13 @@
"scheduler": "^0.13.1" "scheduler": "^0.13.1"
} }
}, },
"react-expandable-textarea": {
"version": "github:muerwre/react-expandable-textarea#9a3b826abd5203c5d6adf77cf4bfdd10131de417",
"from": "github:muerwre/react-expandable-textarea",
"requires": {
"classnames": "^2.2.6"
}
},
"react-hot-loader": { "react-hot-loader": {
"version": "4.6.5", "version": "4.6.5",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.6.5.tgz", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.6.5.tgz",

View file

@ -90,6 +90,7 @@
"rc-slider": "8.5.0", "rc-slider": "8.5.0",
"react": "16.8.1", "react": "16.8.1",
"react-dom": "16.8.1", "react-dom": "16.8.1",
"react-expandable-textarea": "github:muerwre/react-expandable-textarea",
"react-hot-loader": "^4.1.1", "react-hot-loader": "^4.1.1",
"react-infinite-scroller": "^1.2.2", "react-infinite-scroller": "^1.2.2",
"react-rangeslider": "^2.2.0", "react-rangeslider": "^2.2.0",

View file

@ -7,10 +7,14 @@ import { Icon } from '$components/panels/Icon';
import { Switch } from '$components/Switch'; import { Switch } from '$components/Switch';
import classnames from 'classnames'; import classnames from 'classnames';
import { IRootState } from "$redux/user/reducer";
import { sendSaveRequest, setMode } from "$redux/user/actions"; import { sendSaveRequest, setMode } from "$redux/user/actions";
import ExpandableTextarea from 'react-expandable-textarea';
interface Props {
address: string,
title: string,
is_public: boolean,
interface Props extends IRootState {
width: number, width: number,
setMode: typeof setMode, setMode: typeof setMode,
sendSaveRequest: typeof sendSaveRequest, sendSaveRequest: typeof sendSaveRequest,
@ -25,6 +29,7 @@ interface State {
address: string, address: string,
title: string, title: string,
is_public: boolean, is_public: boolean,
description: string,
} }
export class SaveDialog extends React.Component<Props, State> { export class SaveDialog extends React.Component<Props, State> {
@ -35,6 +40,7 @@ export class SaveDialog extends React.Component<Props, State> {
address: props.address || '', address: props.address || '',
title: props.title || '', title: props.title || '',
is_public: props.is_public || false, is_public: props.is_public || false,
description: props.description || '',
}; };
} }
@ -46,22 +52,23 @@ export class SaveDialog extends React.Component<Props, State> {
}; };
setTitle = ({ target: { value } }) => this.setState({ title: ((value && value.substr(0, 64)) || '') }); setTitle = ({ target: { value } }) => this.setState({ title: ((value && value.substr(0, 64)) || '') });
setAddress = ({ target: { value } }) => this.setState({ address: (value && value.substr(0, 32) || '') }); setAddress = ({ target: { value } }) => this.setState({ address: (value && value.substr(0, 32) || '') });
setDescription = ({ target: { value } }) => this.setState({ description: (value && value.substr(0, 256) || '') });
cancelSaving = () => this.props.setMode(MODES.NONE);
sendSaveRequest = (e, force = false) => { sendSaveRequest = (e, force = false) => {
const { title, is_public } = this.state; const { title, is_public, description } = this.state;
const address = this.getAddress(); const address = this.getAddress();
this.props.sendSaveRequest({ this.props.sendSaveRequest({
title, address, force, is_public title, address, force, is_public, description,
}); });
}; };
forceSaveRequest = e => this.sendSaveRequest(e, true); forceSaveRequest = e => this.sendSaveRequest(e, true);
cancelSaving = () => this.props.setMode(MODES.NONE);
onCopy = e => { onCopy = e => {
e.preventDefault(); e.preventDefault();
const { host, protocol } = getUrlData(); const { host, protocol } = getUrlData();
@ -73,7 +80,7 @@ export class SaveDialog extends React.Component<Props, State> {
}; };
render() { render() {
const { title, is_public } = this.state; const { title, is_public, description } = this.state;
const { save_error, save_finished, save_overwriting, width, save_loading } = this.props; const { save_error, save_finished, save_overwriting, width, save_loading } = this.props;
const { host, protocol } = getUrlData(); const { host, protocol } = getUrlData();
@ -104,6 +111,15 @@ export class SaveDialog extends React.Component<Props, State> {
</div> </div>
</div> </div>
<div className="save-textarea">
<ExpandableTextarea
minRows={2}
maxRows={5}
placeholder="Описание маршрута"
value={description}
onChange={this.setDescription}
/>
</div>
<div className="save-text"> <div className="save-text">
{ save_error || TIPS.SAVE_INFO } { save_error || TIPS.SAVE_INFO }
</div> </div>

View file

@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { IModes, MODES } from '$constants/modes'; import { MODES } from '$constants/modes';
import { RouterDialog } from '$components/dialogs/RouterDialog'; import { RouterDialog } from '$components/dialogs/RouterDialog';
import { StickersDialog } from '$components/dialogs/StickersDialog'; import { StickersDialog } from '$components/dialogs/StickersDialog';

View file

@ -12,14 +12,14 @@ import {
resetSaveDialog, resetSaveDialog,
setActiveSticker, setActiveSticker,
setAddress, setAddress,
setChanged, setChanged, setDescription,
setDistance, setDistance,
setIsEmpty, setIsRouting, setIsEmpty, setIsRouting,
setLogo, setLogo,
setMarkersShown, setMarkersShown,
setMode, setMode,
setPublic, setPublic,
setRouterPoints, setRouterPoints, setStarred,
setTitle, setTitle,
} from '$redux/user/actions'; } from '$redux/user/actions';
import { DEFAULT_PROVIDER, IProvider, PROVIDERS } from '$constants/providers'; import { DEFAULT_PROVIDER, IProvider, PROVIDERS } from '$constants/providers';
@ -37,15 +37,17 @@ interface IEditor {
owner: { id: string }; owner: { id: string };
initialData: { initialData: {
version: number, version: number,
title: string, title: IRootState['title'],
owner: { id: string }, owner: { id: string },
address: string, address: IRootState['address'],
path: any, path: any,
route: any, route: any,
stickers: any, stickers: any,
provider: string, provider: IRootState['provider'],
is_public: boolean, is_public: IRootState['is_public'],
logo: string, is_starred: IRootState['is_starred'],
description: IRootState['description'],
logo: IRootState['logo'],
}; };
activeSticker: IRootState['activeSticker']; activeSticker: IRootState['activeSticker'];
mode: IRootState['mode']; mode: IRootState['mode'];
@ -156,7 +158,9 @@ export class Editor {
route: null, route: null,
stickers: null, stickers: null,
provider: null, provider: null,
is_public: null, is_public: false,
is_starred: false,
description: '',
logo: null, logo: null,
}; };
activeSticker: IEditor['activeSticker']; activeSticker: IEditor['activeSticker'];
@ -183,8 +187,10 @@ export class Editor {
setRouterPoints: typeof setRouterPoints = value => store.dispatch(setRouterPoints(value)); setRouterPoints: typeof setRouterPoints = value => store.dispatch(setRouterPoints(value));
setActiveSticker: typeof setActiveSticker = value => store.dispatch(setActiveSticker(value)); setActiveSticker: typeof setActiveSticker = value => store.dispatch(setActiveSticker(value));
setTitle: typeof setTitle = value => store.dispatch(setTitle(value)); setTitle: typeof setTitle = value => store.dispatch(setTitle(value));
setDescription: typeof setDescription = value => store.dispatch(setDescription(value));
setAddress: typeof setAddress = value => store.dispatch(setAddress(value)); setAddress: typeof setAddress = value => store.dispatch(setAddress(value));
setPublic: typeof setPublic = value => store.dispatch(setPublic(value)); setPublic: typeof setPublic = value => store.dispatch(setPublic(value));
setStarred: typeof setStarred = value => store.dispatch(setStarred(value));
setIsEmpty: typeof setIsEmpty = value => store.dispatch(setIsEmpty(value)); setIsEmpty: typeof setIsEmpty = value => store.dispatch(setIsEmpty(value));
setIsRouting: typeof setIsRouting = value => store.dispatch(setIsRouting(value)); setIsRouting: typeof setIsRouting = value => store.dispatch(setIsRouting(value));
@ -305,7 +311,16 @@ export class Editor {
}; };
setData = ({ setData = ({
route = [], stickers = [], owner, title, address, provider = DEFAULT_PROVIDER, logo = DEFAULT_LOGO, is_public, route = [],
stickers = [],
owner,
title,
address,
provider = DEFAULT_PROVIDER,
logo = DEFAULT_LOGO,
is_public,
is_starred,
description,
}: IEditor['initialData']): void => { }: IEditor['initialData']): void => {
this.setTitle(title || ''); this.setTitle(title || '');
const { id } = this.getUser(); const { id } = this.getUser();
@ -332,6 +347,9 @@ export class Editor {
} }
this.setPublic(is_public); this.setPublic(is_public);
this.setStarred(is_starred);
this.setDescription(description);
this.setLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO); this.setLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO);
this.setProvider((provider && PROVIDERS[provider] && provider) || DEFAULT_PROVIDER); this.setProvider((provider && PROVIDERS[provider] && provider) || DEFAULT_PROVIDER);
@ -348,7 +366,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 } = this.getState(); const { is_public, logo, is_starred , description} = this.getState();
const { route, stickers, provider } = this.dumpData(); const { route, stickers, provider } = this.dumpData();
this.initialData = { this.initialData = {
@ -362,6 +380,8 @@ export class Editor {
provider, provider,
is_public, is_public,
logo, logo,
is_starred,
description,
}; };
}; };

View file

@ -1,5 +1,6 @@
import { ACTIONS } from '$redux/user/constants'; import { ACTIONS } from '$redux/user/constants';
import { IUser } from "$constants/auth"; import { IUser } from "$constants/auth";
import { IRootState } from "$redux/user/reducer";
export const setUser = (user: IUser) => ({ type: ACTIONS.SET_USER, user }); export const setUser = (user: IUser) => ({ type: ACTIONS.SET_USER, user });
export const userLogout = () => ({ type: ACTIONS.USER_LOGOUT }); export const userLogout = () => ({ type: ACTIONS.USER_LOGOUT });
@ -12,9 +13,11 @@ export const setRouterPoints = routerPoints => ({ type: ACTIONS.SET_ROUTER_POINT
export const setActiveSticker = activeSticker => ({ type: ACTIONS.SET_ACTIVE_STICKER, activeSticker }); export const setActiveSticker = activeSticker => ({ type: ACTIONS.SET_ACTIVE_STICKER, activeSticker });
export const setLogo = logo => ({ type: ACTIONS.SET_LOGO, logo }); export const setLogo = logo => ({ type: ACTIONS.SET_LOGO, logo });
export const setTitle = title => ({ type: ACTIONS.SET_TITLE, title }); export const setTitle = title => ({ type: ACTIONS.SET_TITLE, title });
export const setDescription = description => ({ type: ACTIONS.SET_DESCRIPTION, description });
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 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 });
@ -28,7 +31,17 @@ export const clearStickers = () => ({ type: ACTIONS.CLEAR_STICKERS });
export const clearAll = () => ({ type: ACTIONS.CLEAR_ALL }); export const clearAll = () => ({ type: ACTIONS.CLEAR_ALL });
export const clearCancel = () => ({ type: ACTIONS.CLEAR_CANCEL }); export const clearCancel = () => ({ type: ACTIONS.CLEAR_CANCEL });
export const sendSaveRequest = payload => ({ type: ACTIONS.SEND_SAVE_REQUEST, ...payload }); export const sendSaveRequest = (payload: {
title: IRootState['title'],
address: IRootState['address'],
is_public: IRootState['is_public'],
description: IRootState['description'],
force: boolean,
}) => ({
type: ACTIONS.SEND_SAVE_REQUEST,
...payload,
});
export const resetSaveDialog = () => ({ type: ACTIONS.RESET_SAVE_DIALOG }); export const resetSaveDialog = () => ({ type: ACTIONS.RESET_SAVE_DIALOG });
export const setSaveLoading = save_loading => ({ type: ACTIONS.SET_SAVE_LOADING, save_loading }); export const setSaveLoading = save_loading => ({ type: ACTIONS.SET_SAVE_LOADING, save_loading });

View file

@ -17,6 +17,8 @@ export const ACTIONS: IActions = {
SET_ADDRESS: 'SET_ADDRESS', SET_ADDRESS: 'SET_ADDRESS',
SET_ADDRESS_ORIGIN: 'SET_ADDRESS_ORIGIN', SET_ADDRESS_ORIGIN: 'SET_ADDRESS_ORIGIN',
SET_PUBLIC: 'SET_PUBLIC', SET_PUBLIC: 'SET_PUBLIC',
SET_STARRED: 'SET_STARRED',
SET_DESCRIPTION: 'SET_DESCRIPTION',
START_EDITING: 'START_EDITING', START_EDITING: 'START_EDITING',
STOP_EDITING: 'STOP_EDITING', STOP_EDITING: 'STOP_EDITING',

View file

@ -26,6 +26,7 @@ export interface IRootReducer {
logo: keyof typeof LOGOS, logo: keyof typeof LOGOS,
routerPoints: number, routerPoints: number,
distance: number, distance: number,
description: string,
estimated: number, estimated: number,
speed: number, speed: number,
activeSticker: { set?: keyof IStickers, sticker?: string }, activeSticker: { set?: keyof IStickers, sticker?: string },
@ -36,6 +37,7 @@ export interface IRootReducer {
provider: keyof typeof PROVIDERS, provider: keyof typeof PROVIDERS,
markers_shown: boolean, markers_shown: boolean,
is_starred: boolean,
is_public: boolean, is_public: boolean,
is_empty: boolean, is_empty: boolean,
is_routing: boolean, is_routing: boolean,
@ -140,6 +142,11 @@ const setTitle: ActionHandler<typeof ActionCreators.setTitle> = (state, { title
title title
}); });
const setDescription: ActionHandler<typeof ActionCreators.setDescription> = (state, { description }) => ({
...state,
description
});
const setAddress: ActionHandler<typeof ActionCreators.setAddress> = (state, { address }) => ({ const setAddress: ActionHandler<typeof ActionCreators.setAddress> = (state, { address }) => ({
...state, ...state,
address address
@ -276,6 +283,8 @@ 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 setSpeed: ActionHandler<typeof ActionCreators.setSpeed> = (state, { speed = 15 }) => ({ const setSpeed: ActionHandler<typeof ActionCreators.setSpeed> = (state, { speed = 15 }) => ({
...state, ...state,
speed, speed,
@ -330,6 +339,7 @@ const HANDLERS = ({
[ACTIONS.SET_ACTIVE_STICKER]: setActiveSticker, [ACTIONS.SET_ACTIVE_STICKER]: setActiveSticker,
[ACTIONS.SET_LOGO]: setLogo, [ACTIONS.SET_LOGO]: setLogo,
[ACTIONS.SET_TITLE]: setTitle, [ACTIONS.SET_TITLE]: setTitle,
[ACTIONS.SET_DESCRIPTION]: setDescription,
[ACTIONS.SET_ADDRESS]: setAddress, [ACTIONS.SET_ADDRESS]: setAddress,
[ACTIONS.SET_ADDRESS_ORIGIN]: setAddressOrigin, [ACTIONS.SET_ADDRESS_ORIGIN]: setAddressOrigin,
@ -356,6 +366,7 @@ const HANDLERS = ({
[ACTIONS.SEARCH_PUT_ROUTES]: searchPutRoutes, [ACTIONS.SEARCH_PUT_ROUTES]: searchPutRoutes,
[ACTIONS.SEARCH_SET_LOADING]: searchSetLoading, [ACTIONS.SEARCH_SET_LOADING]: searchSetLoading,
[ACTIONS.SET_PUBLIC]: setPublic, [ACTIONS.SET_PUBLIC]: setPublic,
[ACTIONS.SET_STARRED]: setStarred,
[ACTIONS.SET_SPEED]: setSpeed, [ACTIONS.SET_SPEED]: setSpeed,
[ACTIONS.SET_MARKERS_SHOWN]: setMarkersShown, [ACTIONS.SET_MARKERS_SHOWN]: setMarkersShown,
@ -376,6 +387,7 @@ export const INITIAL_STATE: IRootReducer = {
logo: DEFAULT_LOGO, logo: DEFAULT_LOGO,
routerPoints: 0, routerPoints: 0,
distance: 0, distance: 0,
description: '',
estimated: 0, estimated: 0,
speed: 15, speed: 15,
activeSticker: { set: null, sticker: null }, activeSticker: { set: null, sticker: null },
@ -387,6 +399,8 @@ export const INITIAL_STATE: IRootReducer = {
markers_shown: true, markers_shown: true,
changed: false, changed: false,
editing: false, editing: false,
is_starred: false,
is_public: false, is_public: false,
is_empty: true, is_empty: true,
is_routing: false, is_routing: false,

View file

@ -307,7 +307,7 @@ function* clearSaga({ type }) {
} }
function* sendSaveRequestSaga({ function* sendSaveRequestSaga({
title, address, force, is_public title, address, force, is_public, description,
}: ReturnType<typeof ActionCreators.sendSaveRequest>) { }: ReturnType<typeof ActionCreators.sendSaveRequest>) {
if (editor.isEmpty) return yield put(setSaveError(TIPS.SAVE_EMPTY)); if (editor.isEmpty) return yield put(setSaveError(TIPS.SAVE_EMPTY));
@ -319,7 +319,7 @@ function* sendSaveRequestSaga({
const { result, timeout, cancel } = yield race({ const { result, timeout, cancel } = yield race({
result: postMap({ result: postMap({
id, token, route, stickers, title, force, address, logo, distance, provider, is_public id, token, route, stickers, title, force, address, logo, distance, provider, is_public, description,
}), }),
timeout: delay(10000), timeout: delay(10000),
cancel: take(ACTIONS.RESET_SAVE_DIALOG), cancel: take(ACTIONS.RESET_SAVE_DIALOG),

View file

@ -46,7 +46,7 @@
&.active { &.active {
opacity: 1; opacity: 1;
touch-action: all; touch-action: auto;
pointer-events: all; pointer-events: all;
svg { svg {
@ -90,6 +90,7 @@
border-radius: 2px; border-radius: 2px;
display: flex; display: flex;
margin-bottom: 5px; margin-bottom: 5px;
input { input {
padding: 5px 5px 5px 2px; padding: 5px 5px 5px 2px;
background: transparent; background: transparent;
@ -150,14 +151,15 @@
.save-description { .save-description {
textarea { textarea {
background: rgba(0,0,0,0.3); background: rgba(0,0,0,0.3);
outline: none;
border: none; border: none;
border-radius: 3px; border-radius: 3px;
width: 100%; width: 100%;
resize: none; resize: none;
color: inherit; color: inherit;
font: inherit; font: inherit;
height: 5.5em; padding: 5px 10px;
padding: 0.25em; font-size: 14px;
} }
} }

View file

@ -21,6 +21,7 @@ interface IPostMap {
distance: IRootState['distance'], distance: IRootState['distance'],
provider: IRootState['provider'], provider: IRootState['provider'],
is_public: IRootState['is_public'], is_public: IRootState['is_public'],
description: IRootState['description'],
} }
interface IGetRouteList { interface IGetRouteList {
@ -67,7 +68,7 @@ export const getStoredMap = (
)); ));
export const postMap = ({ export const postMap = ({
title, address, route, stickers, id, token, force, logo, distance, provider, is_public, title, address, route, stickers, id, token, force, logo, distance, provider, is_public, description,
}: IPostMap) => axios.post(API.POST_MAP, { }: IPostMap) => axios.post(API.POST_MAP, {
title, title,
address, address,
@ -80,6 +81,7 @@ export const postMap = ({
distance, distance,
provider, provider,
is_public, is_public,
description,
}).then(result => (result && result.data && result.data)); }).then(result => (result && result.data && result.data));
export const checkIframeToken = ( export const checkIframeToken = (