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"
}
},
"react-expandable-textarea": {
"version": "github:muerwre/react-expandable-textarea#9a3b826abd5203c5d6adf77cf4bfdd10131de417",
"from": "github:muerwre/react-expandable-textarea",
"requires": {
"classnames": "^2.2.6"
}
},
"react-hot-loader": {
"version": "4.6.5",
"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",
"react": "16.8.1",
"react-dom": "16.8.1",
"react-expandable-textarea": "github:muerwre/react-expandable-textarea",
"react-hot-loader": "^4.1.1",
"react-infinite-scroller": "^1.2.2",
"react-rangeslider": "^2.2.0",

View file

@ -7,10 +7,14 @@ import { Icon } from '$components/panels/Icon';
import { Switch } from '$components/Switch';
import classnames from 'classnames';
import { IRootState } from "$redux/user/reducer";
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,
setMode: typeof setMode,
sendSaveRequest: typeof sendSaveRequest,
@ -25,6 +29,7 @@ interface State {
address: string,
title: string,
is_public: boolean,
description: string,
}
export class SaveDialog extends React.Component<Props, State> {
@ -35,6 +40,7 @@ export class SaveDialog extends React.Component<Props, State> {
address: props.address || '',
title: props.title || '',
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)) || '') });
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) => {
const { title, is_public } = this.state;
const { title, is_public, description } = this.state;
const address = this.getAddress();
this.props.sendSaveRequest({
title, address, force, is_public
title, address, force, is_public, description,
});
};
forceSaveRequest = e => this.sendSaveRequest(e, true);
cancelSaving = () => this.props.setMode(MODES.NONE);
onCopy = e => {
e.preventDefault();
const { host, protocol } = getUrlData();
@ -73,7 +80,7 @@ export class SaveDialog extends React.Component<Props, State> {
};
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 { host, protocol } = getUrlData();
@ -104,6 +111,15 @@ export class SaveDialog extends React.Component<Props, State> {
</div>
</div>
<div className="save-textarea">
<ExpandableTextarea
minRows={2}
maxRows={5}
placeholder="Описание маршрута"
value={description}
onChange={this.setDescription}
/>
</div>
<div className="save-text">
{ save_error || TIPS.SAVE_INFO }
</div>

View file

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

View file

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

View file

@ -1,5 +1,6 @@
import { ACTIONS } from '$redux/user/constants';
import { IUser } from "$constants/auth";
import { IRootState } from "$redux/user/reducer";
export const setUser = (user: IUser) => ({ type: ACTIONS.SET_USER, user });
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 setLogo = logo => ({ type: ACTIONS.SET_LOGO, logo });
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 setAddressOrigin = address_origin => ({ type: ACTIONS.SET_ADDRESS_ORIGIN, address_origin });
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 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 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 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_ORIGIN: 'SET_ADDRESS_ORIGIN',
SET_PUBLIC: 'SET_PUBLIC',
SET_STARRED: 'SET_STARRED',
SET_DESCRIPTION: 'SET_DESCRIPTION',
START_EDITING: 'START_EDITING',
STOP_EDITING: 'STOP_EDITING',

View file

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

View file

@ -307,7 +307,7 @@ function* clearSaga({ type }) {
}
function* sendSaveRequestSaga({
title, address, force, is_public
title, address, force, is_public, description,
}: ReturnType<typeof ActionCreators.sendSaveRequest>) {
if (editor.isEmpty) return yield put(setSaveError(TIPS.SAVE_EMPTY));
@ -319,7 +319,7 @@ function* sendSaveRequestSaga({
const { result, timeout, cancel } = yield race({
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),
cancel: take(ACTIONS.RESET_SAVE_DIALOG),

View file

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

View file

@ -21,6 +21,7 @@ interface IPostMap {
distance: IRootState['distance'],
provider: IRootState['provider'],
is_public: IRootState['is_public'],
description: IRootState['description'],
}
interface IGetRouteList {
@ -67,7 +68,7 @@ export const getStoredMap = (
));
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, {
title,
address,
@ -80,6 +81,7 @@ export const postMap = ({
distance,
provider,
is_public,
description,
}).then(result => (result && result.data && result.data));
export const checkIframeToken = (