diff --git a/src/redux/map/handlers.ts b/src/redux/map/handlers.ts new file mode 100644 index 0000000..a5d12a5 --- /dev/null +++ b/src/redux/map/handlers.ts @@ -0,0 +1,3 @@ +export const MAP_HANDLERS = { + +} \ No newline at end of file diff --git a/src/redux/map/index.ts b/src/redux/map/index.ts index e69de29..ce8f294 100644 --- a/src/redux/map/index.ts +++ b/src/redux/map/index.ts @@ -0,0 +1,11 @@ +import { createReducer } from 'reduxsauce'; +import { MAP_HANDLERS } from './handlers'; + +export interface IMapReducer { + +} + +export const MAP_INITIAL_STATE = { + +} +export const map = createReducer(MAP_INITIAL_STATE, MAP_HANDLERS) \ No newline at end of file diff --git a/src/redux/user/actions.ts b/src/redux/user/actions.ts index b06db61..3c48f15 100644 --- a/src/redux/user/actions.ts +++ b/src/redux/user/actions.ts @@ -1,35 +1,35 @@ -import { ACTIONS } from '$redux/user/constants'; +import { USER_ACTIONS } from '$redux/user/constants'; import { IUser } from "$constants/auth"; import { IRootState } from "$redux/user"; -export const setUser = (user: IUser) => ({ type: ACTIONS.SET_USER, user }); -export const userLogout = () => ({ type: ACTIONS.USER_LOGOUT }); +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: ACTIONS.SET_EDITING, editing }); -export const setMode = (mode: IRootState['mode']) => ({ type: ACTIONS.SET_MODE, mode }); -export const setDistance = (distance: IRootState['distance']) => ({ type: ACTIONS.SET_DISTANCE, distance }); -export const setChanged = (changed: IRootState['changed']) => ({ type: ACTIONS.SET_CHANGED, changed }); -export const setRouterPoints = routerPoints => ({ type: ACTIONS.SET_ROUTER_POINTS, routerPoints }); -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_published => ({ type: ACTIONS.SET_STARRED, is_published }); -export const setSpeed = speed => ({ type: ACTIONS.SET_SPEED, speed }); +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 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 startEditing = () => ({ type: ACTIONS.START_EDITING }); -export const stopEditing = () => ({ type: ACTIONS.STOP_EDITING }); +export const startEditing = () => ({ type: USER_ACTIONS.START_EDITING }); +export const stopEditing = () => ({ type: USER_ACTIONS.STOP_EDITING }); -export const routerCancel = () => ({ type: ACTIONS.ROUTER_CANCEL }); -export const routerSubmit = () => ({ type: ACTIONS.ROUTER_SUBMIT }); +export const routerCancel = () => ({ type: USER_ACTIONS.ROUTER_CANCEL }); +export const routerSubmit = () => ({ type: USER_ACTIONS.ROUTER_SUBMIT }); -export const clearPoly = () => ({ type: ACTIONS.CLEAR_POLY }); -export const clearStickers = () => ({ type: ACTIONS.CLEAR_STICKERS }); -export const clearAll = () => ({ type: ACTIONS.CLEAR_ALL }); -export const clearCancel = () => ({ type: 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: IRootState['title'], @@ -38,13 +38,13 @@ export const sendSaveRequest = (payload: { description: IRootState['description'], force: boolean, }) => ({ - type: ACTIONS.SEND_SAVE_REQUEST, + type: USER_ACTIONS.SEND_SAVE_REQUEST, ...payload, }); -export const resetSaveDialog = () => ({ type: ACTIONS.RESET_SAVE_DIALOG }); +export const resetSaveDialog = () => ({ type: USER_ACTIONS.RESET_SAVE_DIALOG }); -export const setSaveLoading = (save_loading: IRootState['save_loading']) => ({ type: 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: IRootState['address'], @@ -53,50 +53,50 @@ export const setSaveSuccess = (payload: { description: IRootState['description'], save_error: string, -}) => ({ type: ACTIONS.SET_SAVE_SUCCESS, ...payload }); +}) => ({ type: USER_ACTIONS.SET_SAVE_SUCCESS, ...payload }); -export const setSaveError = (save_error: IRootState['save_error']) => ({ type: ACTIONS.SET_SAVE_ERROR, save_error }); -export const setSaveOverwrite = () => ({ type: 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: ACTIONS.HIDE_RENDERER }); -export const setRenderer = payload => ({ type: ACTIONS.SET_RENDERER, payload }); -export const takeAShot = () => ({ type: ACTIONS.TAKE_A_SHOT }); -export const cropAShot = payload => ({ type: 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: ACTIONS.SET_PROVIDER, provider }); -export const changeProvider = provider => ({ type: ACTIONS.CHANGE_PROVIDER, provider }); +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: ACTIONS.SET_DIALOG, dialog }); -export const setDialogActive = dialog_active => ({ type: ACTIONS.SET_DIALOG_ACTIVE, dialog_active }); -export const openMapDialog = tab => ({ type: ACTIONS.OPEN_MAP_DIALOG, tab }); +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: ACTIONS.LOCATION_CHANGED, location }); -export const setReady = ready => ({ type: 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: ACTIONS.GOT_VK_USER, user }); -export const keyPressed = ({ key, target: { tagName } }) => ({ type: ACTIONS.KEY_PRESSED, key, target: tagName }); +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 searchSetTitle = title => ({ type: ACTIONS.SEARCH_SET_TITLE, title }); -export const searchSetDistance = distance => ({ type: ACTIONS.SEARCH_SET_DISTANCE, distance }); -export const searchChangeDistance = distance => ({ type: ACTIONS.SEARCH_CHANGE_DISTANCE, distance }); -export const searchSetTab = tab => ({ type: ACTIONS.SEARCH_SET_TAB, tab }); -export const searchSetLoading = loading => ({ type: ACTIONS.SEARCH_SET_LOADING, loading }); +export const searchSetTitle = title => ({ type: USER_ACTIONS.SEARCH_SET_TITLE, title }); +export const searchSetDistance = distance => ({ type: USER_ACTIONS.SEARCH_SET_DISTANCE, distance }); +export const searchChangeDistance = distance => ({ type: USER_ACTIONS.SEARCH_CHANGE_DISTANCE, distance }); +export const searchSetTab = tab => ({ type: USER_ACTIONS.SEARCH_SET_TAB, tab }); +export const searchSetLoading = loading => ({ type: USER_ACTIONS.SEARCH_SET_LOADING, loading }); -export const searchPutRoutes = payload => ({ type: ACTIONS.SEARCH_PUT_ROUTES, ...payload }); +export const searchPutRoutes = payload => ({ type: USER_ACTIONS.SEARCH_PUT_ROUTES, ...payload }); -export const setMarkersShown = markers_shown => ({ type: ACTIONS.SET_MARKERS_SHOWN, markers_shown }); -export const getGPXTrack = () => ({ type: ACTIONS.GET_GPX_TRACK }); -export const setIsEmpty = is_empty => ({ type: ACTIONS.SET_IS_EMPTY, is_empty }); +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 mapsLoadMore = () => ({ type: ACTIONS.MAPS_LOAD_MORE }); -export const mapsSetShift = (shift: number) => ({ type: ACTIONS.MAPS_SET_SHIFT, shift }); +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: ACTIONS.SET_FEATURE, features }); -export const setIsRouting = (is_routing: boolean) => ({ type: 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: ACTIONS.DROP_ROUTE, address }); +export const dropRoute = (address: string) => ({ type: USER_ACTIONS.DROP_ROUTE, address }); export const modifyRoute = (address: string, { title, is_public }: { title: string, is_public: boolean }) => ({ - type: ACTIONS.MODIFY_ROUTE, address, title, is_public + type: USER_ACTIONS.MODIFY_ROUTE, address, title, is_public }); -export const toggleRouteStarred = (address: string) => ({ type: ACTIONS.TOGGLE_ROUTE_STARRED, address }); -export const setRouteStarred = (address: string, is_published: boolean) => ({ type: ACTIONS.SET_ROUTE_STARRED, address, is_published }); +export const toggleRouteStarred = (address: string) => ({ type: USER_ACTIONS.TOGGLE_ROUTE_STARRED, address }); +export const setRouteStarred = (address: string, is_published: boolean) => ({ type: USER_ACTIONS.SET_ROUTE_STARRED, address, is_published }); diff --git a/src/redux/user/constants.ts b/src/redux/user/constants.ts index 3dc2869..34dea81 100644 --- a/src/redux/user/constants.ts +++ b/src/redux/user/constants.ts @@ -2,7 +2,7 @@ export interface IActions { [x: string]: string, } -export const ACTIONS: IActions = { +export const USER_ACTIONS: IActions = { SET_USER: 'SET_USER', USER_LOGOUT: 'USER_LOGOUT', diff --git a/src/redux/user/handlers.ts b/src/redux/user/handlers.ts new file mode 100644 index 0000000..da2da64 --- /dev/null +++ b/src/redux/user/handlers.ts @@ -0,0 +1,297 @@ +import { IRootState } from "."; +import * as ActionCreators from './actions' +import { TIPS } from "$constants/tips"; +import { TABS } from "$constants/dialogs"; +import { USER_ACTIONS } from "./constants"; + +type UnsafeReturnType = T extends (...args: any[]) => infer R ? R : any; + +export interface ActionHandler { + (state: IRootState, payload: UnsafeReturnType): IRootState; +} + +const getEstimated = (distance: number, speed: number = 15): number => { + const time = (distance && (distance / speed)) || 0; + return (time && parseFloat(time.toFixed(1))); +}; + +const setUser: ActionHandler = (state, { user }) => ({ + ...state, + user: { + ...state.user, + ...user, + }, +}); + +const setEditing: ActionHandler = (state, { editing }) => ({ + ...state, editing +}); + +const setChanged: ActionHandler = (state, { changed }) => ({ + ...state, + changed +}); + +const setMode: ActionHandler = (state, { mode }) => ({ + ...state, + mode +}); + +const setDistance: ActionHandler = (state, { distance }) => ({ + ...state, + distance, + estimated: getEstimated(distance, state.speed), +}); + +const setRouterPoints: ActionHandler = (state, { routerPoints }) => ({ + ...state, + routerPoints, +}); + +const setActiveSticker: ActionHandler = (state, { activeSticker }) => ({ + ...state, + activeSticker: activeSticker || { set: null, sticker: null } +}); + +const setLogo: ActionHandler = (state, { logo }) => ({ + ...state, + logo +}); + +const setTitle: ActionHandler = (state, { title }) => ({ + ...state, + title +}); + +const setDescription: ActionHandler = (state, { description }) => ({ + ...state, + description +}); + +const setAddress: ActionHandler = (state, { address }) => ({ + ...state, + address +}); + +const setAddressOrigin: ActionHandler = (state, { address_origin }) => ({ + ...state, + address_origin +}); + +const sendSaveRequest: ActionHandler = (state) => ({ + ...state, + save_processing: true, +}); + +const setSaveError: ActionHandler = (state, { save_error }) => ({ + ...state, save_error, save_finished: false, save_processing: false +}); + +const setSaveLoading: ActionHandler = (state, { save_loading }) => ({ + ...state, save_loading +}); + +const setSaveOverwrite: ActionHandler = (state) => ({ + ...state, + save_overwriting: true, + save_finished: false, + save_processing: false, + save_error: TIPS.SAVE_OVERWRITE, +}); + +const setSaveSuccess: ActionHandler = (state, { save_error }) => ({ + ...state, + save_overwriting: false, + save_finished: true, + save_processing: false, + save_error, +}); + +const resetSaveDialog: ActionHandler = (state) => ({ + ...state, save_overwriting: false, save_finished: false, save_processing: false, save_error: '', +}); + +const hideRenderer: ActionHandler = (state) => ({ + ...state, + renderer: { ...state.renderer, renderer_active: false } +}); + +const setRenderer: ActionHandler = (state, { payload }) => ({ + ...state, + renderer: { ...state.renderer, ...payload } +}); + +const setProvider: ActionHandler = (state, { provider }) => ({ ...state, provider }); + +const setDialog: ActionHandler = (state, { dialog }) => ({ + ...state, + dialog, +}); + +const setDialogActive: ActionHandler = (state, { dialog_active }) => ({ + ...state, + dialog_active: dialog_active || !state.dialog_active, +}); + +const setReady: ActionHandler = (state, { ready = true }) => ({ + ...state, + ready, +}); + +const searchSetTitle: ActionHandler = (state, { title = '' }) => ({ + ...state, + routes: { + ...state.routes, + filter: { + ...state.routes.filter, + title, + distance: [0, 10000], + } + } +}); + +const searchSetDistance: ActionHandler = (state, { distance = [0, 9999] }) => ({ + ...state, + routes: { + ...state.routes, + filter: { + ...state.routes.filter, + distance, + } + } +}); + +const searchSetTab: ActionHandler = (state, { tab = TABS[Object.keys(TABS)[0]] }) => ({ + ...state, + routes: { + ...state.routes, + filter: { + ...state.routes.filter, + tab: Object.values(TABS).indexOf(tab) >= 0 ? tab : TABS[Object.values(TABS)[0]], + } + } +}); + +const searchPutRoutes: ActionHandler = (state, { list = [], min, max, limit, step, shift }) => ({ + ...state, + routes: { + ...state.routes, + list, + limit, + step, + shift, + filter: { + ...state.routes.filter, + distance: (state.routes.filter.min === state.routes.filter.max) + ? [min, max] + : state.routes.filter.distance, + min, + max, + } + } +}); + +const searchSetLoading: ActionHandler = (state, { loading = false }) => ({ + ...state, + routes: { + ...state.routes, + loading, + } +}); + +const setPublic: ActionHandler = (state, { is_public = false }) => ({ ...state, is_public }); +const setStarred: ActionHandler = (state, { is_published = false }) => ({ ...state, is_published }); + +const setSpeed: ActionHandler = (state, { speed = 15 }) => ({ + ...state, + speed, + estimated: getEstimated(state.distance, speed), +}); + +const setMarkersShown: ActionHandler = (state, { markers_shown = true }) => ({ ...state, markers_shown }); +const setIsEmpty: ActionHandler = (state, { is_empty = true }) => ({ ...state, is_empty }); +const mapsSetShift: ActionHandler = (state, { shift = 0 }) => ({ + ...state, + routes: { + ...state.routes, + shift, + } +}); + +const setFeature: ActionHandler = (state, { features }) => ({ + ...state, + features: { + ...state.features, + ...features, + } +}); + +const setIsRouting: ActionHandler = (state, { is_routing }) => ({ + ...state, + is_routing, +}); + +const setRouteStarred: ActionHandler = (state, { address, is_published }) => ({ + ...state, + routes: { + ...state.routes, + list: ( + state.routes.list + .map(el => el.address === address ? { ...el, is_published } : el) + .filter(el => ( + (state.routes.filter.tab === TABS.STARRED && el.is_published) || + (state.routes.filter.tab === TABS.PENDING && !el.is_published) + )) + ) + } +}); + +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, + [USER_ACTIONS.SEARCH_CHANGE_DISTANCE]: searchSetDistance, + [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_ROUTE_STARRED]: setRouteStarred, +}); \ No newline at end of file diff --git a/src/redux/user/index.ts b/src/redux/user/index.ts index ca57a7f..4cfae99 100644 --- a/src/redux/user/index.ts +++ b/src/redux/user/index.ts @@ -1,15 +1,13 @@ import { createReducer } from 'reduxsauce'; -import { ACTIONS } from '$redux/user/constants'; import { DEFAULT_USER, IUser } from '$constants/auth'; import { MODES } from '$constants/modes'; import { DEFAULT_LOGO, LOGOS } from '$constants/logos'; -import { TIPS } from '$constants/tips'; import { DEFAULT_PROVIDER, PROVIDERS } from '$constants/providers'; import { DIALOGS, IDialogs, TABS } from '$constants/dialogs'; -import * as ActionCreators from '$redux/user/actions'; -import { IStickers, ISticker } from "$constants/stickers"; +import { IStickers } from "$constants/stickers"; import { IRoutePoint } from '$utils/gpx'; import { IStickerDump } from '$modules/Sticker'; +import { USER_HANDLERS } from './handlers'; export interface IRoute { version: number, @@ -100,305 +98,6 @@ export interface IRootReducer { } export type IRootState = Readonly; -type UnsafeReturnType = T extends (...args: any[]) => infer R ? R : any; - -export interface ActionHandler { - (state: IRootState, payload: UnsafeReturnType): IRootState; -} - -const getEstimated = (distance: number, speed: number = 15): number => { - const time = (distance && (distance / speed)) || 0; - return (time && parseFloat(time.toFixed(1))); -}; - -const setUser: ActionHandler = (state, { user }) => ({ - ...state, - user: { - ...state.user, - ...user, - }, -}); - -const setEditing: ActionHandler = (state, { editing }) => ({ - ...state, editing -}); - -const setChanged: ActionHandler = (state, { changed }) => ({ - ...state, - changed -}); - -const setMode: ActionHandler = (state, { mode }) => ({ - ...state, - mode -}); - -const setDistance: ActionHandler = (state, { distance }) => ({ - ...state, - distance, - estimated: getEstimated(distance, state.speed), -}); - -const setRouterPoints: ActionHandler = (state, { routerPoints }) => ({ - ...state, - routerPoints, -}); - -const setActiveSticker: ActionHandler = (state, { activeSticker }) => ({ - ...state, - activeSticker: activeSticker || { set: null, sticker: null } -}); - -const setLogo: ActionHandler = (state, { logo }) => ({ - ...state, - logo -}); - -const setTitle: ActionHandler = (state, { title }) => ({ - ...state, - title -}); - -const setDescription: ActionHandler = (state, { description }) => ({ - ...state, - description -}); - -const setAddress: ActionHandler = (state, { address }) => ({ - ...state, - address -}); - -const setAddressOrigin: ActionHandler = (state, { address_origin }) => ({ - ...state, - address_origin -}); - -const sendSaveRequest: ActionHandler = (state) => ({ - ...state, - save_processing: true, -}); - -const setSaveError: ActionHandler = (state, { save_error }) => ({ - ...state, save_error, save_finished: false, save_processing: false -}); - -const setSaveLoading: ActionHandler = (state, { save_loading }) => ({ - ...state, save_loading -}); - -const setSaveOverwrite: ActionHandler = (state) => ({ - ...state, - save_overwriting: true, - save_finished: false, - save_processing: false, - save_error: TIPS.SAVE_OVERWRITE, -}); - -const setSaveSuccess: ActionHandler = (state, { save_error }) => ({ - ...state, - save_overwriting: false, - save_finished: true, - save_processing: false, - save_error, -}); - -const resetSaveDialog: ActionHandler = (state) => ({ - ...state, save_overwriting: false, save_finished: false, save_processing: false, save_error: '', -}); -// -// const showRenderer: ActionHandler = (state) => ({ -// ...state, -// renderer: { -// ...state.renderer, -// renderer_active: true -// } -// }); - -const hideRenderer: ActionHandler = (state) => ({ - ...state, - renderer: { ...state.renderer, renderer_active: false } -}); - -const setRenderer: ActionHandler = (state, { payload }) => ({ - ...state, - renderer: { ...state.renderer, ...payload } -}); - -const setProvider: ActionHandler = (state, { provider }) => ({ ...state, provider }); - -const setDialog: ActionHandler = (state, { dialog }) => ({ - ...state, - dialog, -}); - -const setDialogActive: ActionHandler = (state, { dialog_active }) => ({ - ...state, - dialog_active: dialog_active || !state.dialog_active, -}); - -const setReady: ActionHandler = (state, { ready = true }) => ({ - ...state, - ready, -}); - -const searchSetTitle: ActionHandler = (state, { title = '' }) => ({ - ...state, - routes: { - ...state.routes, - filter: { - ...state.routes.filter, - title, - distance: [0, 10000], - } - } -}); - -const searchSetDistance: ActionHandler = (state, { distance = [0, 9999] }) => ({ - ...state, - routes: { - ...state.routes, - filter: { - ...state.routes.filter, - distance, - } - } -}); - -const searchSetTab: ActionHandler = (state, { tab = TABS[Object.keys(TABS)[0]] }) => ({ - ...state, - routes: { - ...state.routes, - filter: { - ...state.routes.filter, - tab: Object.values(TABS).indexOf(tab) >= 0 ? tab : TABS[Object.values(TABS)[0]], - } - } -}); - -const searchPutRoutes: ActionHandler = (state, { list = [], min, max, limit, step, shift }) => ({ - ...state, - routes: { - ...state.routes, - list, - limit, - step, - shift, - filter: { - ...state.routes.filter, - distance: (state.routes.filter.min === state.routes.filter.max) - ? [min, max] - : state.routes.filter.distance, - min, - max, - } - } -}); - -const searchSetLoading: ActionHandler = (state, { loading = false }) => ({ - ...state, - routes: { - ...state.routes, - loading, - } -}); - -const setPublic: ActionHandler = (state, { is_public = false }) => ({ ...state, is_public }); -const setStarred: ActionHandler = (state, { is_published = false }) => ({ ...state, is_published }); - -const setSpeed: ActionHandler = (state, { speed = 15 }) => ({ - ...state, - speed, - estimated: getEstimated(state.distance, speed), -}); - -const setMarkersShown: ActionHandler = (state, { markers_shown = true }) => ({ ...state, markers_shown }); -const setIsEmpty: ActionHandler = (state, { is_empty = true }) => ({ ...state, is_empty }); -const mapsSetShift: ActionHandler = (state, { shift = 0 }) => ({ - ...state, - routes: { - ...state.routes, - shift, - } -}); - -const setFeature: ActionHandler = (state, { features }) => ({ - ...state, - features: { - ...state.features, - ...features, - } -}); - -const setIsRouting: ActionHandler = (state, { is_routing }) => ({ - ...state, - is_routing, -}); - -const setRouteStarred: ActionHandler = (state, { address, is_published }) => ({ - ...state, - routes: { - ...state.routes, - list: ( - state.routes.list - .map(el => el.address === address ? { ...el, is_published } : el) - .filter(el => ( - (state.routes.filter.tab === TABS.STARRED && el.is_published) || - (state.routes.filter.tab === TABS.PENDING && !el.is_published) - )) - ) - } -}); - -const HANDLERS = ({ - [ACTIONS.SET_USER]: setUser, - [ACTIONS.SET_EDITING]: setEditing, - [ACTIONS.SET_CHANGED]: setChanged, - [ACTIONS.SET_MODE]: setMode, - [ACTIONS.SET_DISTANCE]: setDistance, - [ACTIONS.SET_ROUTER_POINTS]: setRouterPoints, - [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, - - [ACTIONS.SET_SAVE_ERROR]: setSaveError, - [ACTIONS.SET_SAVE_LOADING]: setSaveLoading, - [ACTIONS.SET_SAVE_OVERWRITE]: setSaveOverwrite, - [ACTIONS.SET_SAVE_SUCCESS]: setSaveSuccess, - [ACTIONS.SEND_SAVE_REQUEST]: sendSaveRequest, - [ACTIONS.RESET_SAVE_DIALOG]: resetSaveDialog, - - [ACTIONS.HIDE_RENDERER]: hideRenderer, - [ACTIONS.SET_RENDERER]: setRenderer, - - [ACTIONS.SET_PROVIDER]: setProvider, - - [ACTIONS.SET_DIALOG]: setDialog, - [ACTIONS.SET_DIALOG_ACTIVE]: setDialogActive, - [ACTIONS.SET_READY]: setReady, - - [ACTIONS.SEARCH_SET_TITLE]: searchSetTitle, - [ACTIONS.SEARCH_SET_DISTANCE]: searchSetDistance, - [ACTIONS.SEARCH_CHANGE_DISTANCE]: searchSetDistance, - [ACTIONS.SEARCH_SET_TAB]: searchSetTab, - [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, - [ACTIONS.SET_IS_EMPTY]: setIsEmpty, - [ACTIONS.MAPS_SET_SHIFT]: mapsSetShift, - - [ACTIONS.SET_FEATURE]: setFeature, - [ACTIONS.SET_IS_ROUTING]: setIsRouting, - - [ACTIONS.SET_ROUTE_STARRED]: setRouteStarred, -}); export const INITIAL_STATE: IRootReducer = { ready: false, @@ -466,4 +165,4 @@ export const INITIAL_STATE: IRootReducer = { }, }; -export const userReducer = createReducer(INITIAL_STATE, HANDLERS); +export const userReducer = createReducer(INITIAL_STATE, USER_HANDLERS); diff --git a/src/redux/user/sagas.ts b/src/redux/user/sagas.ts index 43ee59d..bb7f70a 100644 --- a/src/redux/user/sagas.ts +++ b/src/redux/user/sagas.ts @@ -63,7 +63,7 @@ import { replacePath } from "$utils/history"; import { editor } from "$modules/Editor"; -import { ACTIONS } from "$redux/user/constants"; +import { USER_ACTIONS } from "$redux/user/constants"; import { MODES } from "$constants/modes"; import { DEFAULT_USER, IUser } from "$constants/auth"; import { TIPS } from "$constants/tips"; @@ -348,16 +348,16 @@ function* routerSubmitSaga() { function* clearSaga({ type }) { switch (type) { - case ACTIONS.CLEAR_POLY: + case USER_ACTIONS.CLEAR_POLY: yield editor.poly.clearAll(); yield editor.router.clearAll(); break; - case ACTIONS.CLEAR_STICKERS: + case USER_ACTIONS.CLEAR_STICKERS: yield editor.stickers.clearAll(); break; - case ACTIONS.CLEAR_ALL: + case USER_ACTIONS.CLEAR_ALL: yield editor.clearAll(); yield put(setChanged(false)); break; @@ -408,7 +408,7 @@ function* sendSaveRequestSaga({ description }), timeout: delay(10000), - cancel: take(ACTIONS.RESET_SAVE_DIALOG) + cancel: take(USER_ACTIONS.RESET_SAVE_DIALOG) }); yield put(setSaveLoading(false)); @@ -922,53 +922,53 @@ function* toggleRouteStarredSaga({ export function* userSaga() { yield takeLatest(REHYDRATE, authCheckSaga); - yield takeEvery(ACTIONS.SET_MODE, setModeSaga); + yield takeEvery(USER_ACTIONS.SET_MODE, setModeSaga); - yield takeEvery(ACTIONS.START_EDITING, startEditingSaga); - yield takeEvery(ACTIONS.STOP_EDITING, stopEditingSaga); + yield takeEvery(USER_ACTIONS.START_EDITING, startEditingSaga); + yield takeEvery(USER_ACTIONS.STOP_EDITING, stopEditingSaga); - yield takeEvery(ACTIONS.USER_LOGOUT, userLogoutSaga); - yield takeEvery(ACTIONS.SET_ACTIVE_STICKER, setActiveStickerSaga); - yield takeEvery(ACTIONS.SET_LOGO, setLogoSaga); + yield takeEvery(USER_ACTIONS.USER_LOGOUT, userLogoutSaga); + yield takeEvery(USER_ACTIONS.SET_ACTIVE_STICKER, setActiveStickerSaga); + yield takeEvery(USER_ACTIONS.SET_LOGO, setLogoSaga); - yield takeEvery(ACTIONS.ROUTER_CANCEL, routerCancelSaga); - yield takeEvery(ACTIONS.ROUTER_SUBMIT, routerSubmitSaga); + yield takeEvery(USER_ACTIONS.ROUTER_CANCEL, routerCancelSaga); + yield takeEvery(USER_ACTIONS.ROUTER_SUBMIT, routerSubmitSaga); yield takeEvery( [ - ACTIONS.CLEAR_POLY, - ACTIONS.CLEAR_STICKERS, - ACTIONS.CLEAR_ALL, - ACTIONS.CLEAR_CANCEL + USER_ACTIONS.CLEAR_POLY, + USER_ACTIONS.CLEAR_STICKERS, + USER_ACTIONS.CLEAR_ALL, + USER_ACTIONS.CLEAR_CANCEL ], clearSaga ); - yield takeLatest(ACTIONS.SEND_SAVE_REQUEST, sendSaveRequestSaga); - yield takeLatest(ACTIONS.SET_SAVE_SUCCESS, setSaveSuccessSaga); - yield takeLatest(ACTIONS.TAKE_A_SHOT, takeAShotSaga); - yield takeLatest(ACTIONS.CROP_A_SHOT, cropAShotSaga); + yield takeLatest(USER_ACTIONS.SEND_SAVE_REQUEST, sendSaveRequestSaga); + yield takeLatest(USER_ACTIONS.SET_SAVE_SUCCESS, setSaveSuccessSaga); + yield takeLatest(USER_ACTIONS.TAKE_A_SHOT, takeAShotSaga); + yield takeLatest(USER_ACTIONS.CROP_A_SHOT, cropAShotSaga); - yield takeEvery(ACTIONS.CHANGE_PROVIDER, changeProviderSaga); - yield takeLatest(ACTIONS.LOCATION_CHANGED, locationChangeSaga); + yield takeEvery(USER_ACTIONS.CHANGE_PROVIDER, changeProviderSaga); + yield takeLatest(USER_ACTIONS.LOCATION_CHANGED, locationChangeSaga); - yield takeLatest(ACTIONS.GOT_VK_USER, gotVkUserSaga); - yield takeLatest(ACTIONS.KEY_PRESSED, keyPressedSaga); + yield takeLatest(USER_ACTIONS.GOT_VK_USER, gotVkUserSaga); + yield takeLatest(USER_ACTIONS.KEY_PRESSED, keyPressedSaga); - yield takeLatest(ACTIONS.SET_TITLE, setTitleSaga); + yield takeLatest(USER_ACTIONS.SET_TITLE, setTitleSaga); yield takeLatest( - [ACTIONS.SEARCH_SET_TITLE, ACTIONS.SEARCH_SET_DISTANCE], + [USER_ACTIONS.SEARCH_SET_TITLE, USER_ACTIONS.SEARCH_SET_DISTANCE], searchSetSaga ); - yield takeLatest(ACTIONS.OPEN_MAP_DIALOG, openMapDialogSaga); - yield takeLatest(ACTIONS.SEARCH_SET_TAB, searchSetTabSaga); - yield takeLatest(ACTIONS.SET_USER, setUserSaga); + yield takeLatest(USER_ACTIONS.OPEN_MAP_DIALOG, openMapDialogSaga); + yield takeLatest(USER_ACTIONS.SEARCH_SET_TAB, searchSetTabSaga); + yield takeLatest(USER_ACTIONS.SET_USER, setUserSaga); - yield takeLatest(ACTIONS.GET_GPX_TRACK, getGPXTrackSaga); - yield takeLatest(ACTIONS.MAPS_LOAD_MORE, mapsLoadMoreSaga); + yield takeLatest(USER_ACTIONS.GET_GPX_TRACK, getGPXTrackSaga); + yield takeLatest(USER_ACTIONS.MAPS_LOAD_MORE, mapsLoadMoreSaga); - yield takeLatest(ACTIONS.DROP_ROUTE, dropRouteSaga); - yield takeLatest(ACTIONS.MODIFY_ROUTE, modifyRouteSaga); - yield takeLatest(ACTIONS.TOGGLE_ROUTE_STARRED, toggleRouteStarredSaga); + yield takeLatest(USER_ACTIONS.DROP_ROUTE, dropRouteSaga); + yield takeLatest(USER_ACTIONS.MODIFY_ROUTE, modifyRouteSaga); + yield takeLatest(USER_ACTIONS.TOGGLE_ROUTE_STARRED, toggleRouteStarredSaga); }