moved editor to separate reducer

This commit is contained in:
Fedor Katurov 2020-01-09 10:59:26 +07:00
parent e950d98b73
commit 87670770b0
38 changed files with 1425 additions and 1069 deletions

120
src/redux/editor/actions.ts Normal file
View 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,
});

View 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`,
};

View 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
View 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
View 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);
}

View 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;

View file

@ -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,
});

View file

@ -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`,

View file

@ -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,
};

View file

@ -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,

View file

@ -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);
@ -298,27 +327,25 @@ 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
);

View file

@ -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));
});

View file

@ -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 }) => ({

View file

@ -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',
};

View file

@ -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,
});

View file

@ -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

View file

@ -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 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 takeLatest(REHYDRATE, authCheckSaga);
yield takeEvery(USER_ACTIONS.START_EDITING, startEditingSaga);
yield takeEvery(USER_ACTIONS.STOP_EDITING, stopEditingSaga);
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);

View file

@ -1,8 +1,4 @@
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;
export const selectUserUser = (state: IState) => state.user.user;