diff --git a/src/index.tsx b/src/index.tsx
index 30e849b..2e6eaca 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -23,10 +23,13 @@ export const Index = () => (
ReactDOM.render(, document.getElementById('index'));
-(function () {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.register('./service-worker.js', { scope: '/' })
- .then(() => console.log('Service Worker registered successfully.'))
- .catch(error => console.log('Service Worker registration failed:', error));
- }
-}());
+if (process.env.NODE_ENV && process.env.NODE_ENV !== 'development') {
+ (function() {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker
+ .register('./service-worker.js', { scope: '/' })
+ .then(() => console.log('Service Worker registered successfully.'))
+ .catch(error => console.log('Service Worker registration failed:', error));
+ }
+ })();
+}
diff --git a/src/map/CurrentLocation/index.tsx b/src/map/CurrentLocation/index.tsx
new file mode 100644
index 0000000..1710a18
--- /dev/null
+++ b/src/map/CurrentLocation/index.tsx
@@ -0,0 +1,33 @@
+import React, { FC, useState, useEffect } from 'react';
+import { LatLngLiteral, marker, Marker, DivIcon } from 'leaflet';
+import { MainMap } from '~/constants/map';
+
+interface IProps {
+ location: LatLngLiteral;
+}
+
+const CurrentLocation: FC = ({ location }) => {
+ useEffect(() => {
+ if (!location) return;
+
+ const item = new Marker(location, {
+ icon: new DivIcon({
+ html: `
+
+
+ `,
+ }),
+ }).addTo(MainMap);
+
+ return () => item.removeFrom(MainMap);
+ }, [MainMap, location]);
+
+ return null;
+};
+
+export { CurrentLocation };
diff --git a/src/map/Map/index.tsx b/src/map/Map/index.tsx
index b2ad195..95f3752 100644
--- a/src/map/Map/index.tsx
+++ b/src/map/Map/index.tsx
@@ -11,11 +11,12 @@ import { Router } from '~/map/Router';
import { TileLayer } from '~/map/TileLayer';
import { Stickers } from '~/map/Stickers';
import { KmMarks } from '~/map/KmMarks';
-import { Arrows } from '~/map/Arrows';
+import { CurrentLocation } from '~/map/CurrentLocation';
import 'leaflet/dist/leaflet.css';
import { selectEditorEditing, selectEditorMode } from '~/redux/editor/selectors';
import { MODES } from '~/constants/modes';
+import { selectUserLocation } from '~/redux/user/selectors';
const mapStateToProps = state => ({
provider: selectMapProvider(state),
@@ -23,6 +24,7 @@ const mapStateToProps = state => ({
stickers: selectMapStickers(state),
editing: selectEditorEditing(state),
mode: selectEditorMode(state),
+ location: selectUserLocation(state),
});
const mapDispatchToProps = {
@@ -41,6 +43,7 @@ const MapUnconnected: React.FC = ({
stickers,
editing,
mode,
+ location,
mapClicked,
mapSetSticker,
@@ -78,6 +81,7 @@ const MapUnconnected: React.FC = ({
+
,
document.getElementById('canvas')
);
diff --git a/src/redux/store.ts b/src/redux/store.ts
index b2a9195..550ac22 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -4,11 +4,9 @@ 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 { PersistConfig, Persistor } from 'redux-persist/es/types';
import { userReducer, IRootReducer } from '~/redux/user';
import { userSaga } from '~/redux/user/sagas';
@@ -18,6 +16,9 @@ import { editorSaga } from '~/redux/editor/sagas';
import { map, IMapReducer } from '~/redux/map';
import { mapSaga } from '~/redux/map/sagas';
+import { watchLocation, getLocation } from '~/utils/window';
+import { LatLngLiteral } from 'leaflet';
+import { setUserLocation } from './user/actions';
const userPersistConfig: PersistConfig = {
key: 'user',
@@ -26,17 +27,16 @@ const userPersistConfig: PersistConfig = {
};
export interface IState {
- user: IRootReducer
- map: IMapReducer,
- editor: IEditorState,
+ user: IRootReducer;
+ map: IMapReducer;
+ editor: IEditorState;
}
// create the saga middleware
export const sagaMiddleware = createSagaMiddleware();
// redux extension composer
const composeEnhancers =
- typeof window === 'object' &&
- (window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
+ typeof window === 'object' && (window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? (window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
@@ -49,7 +49,7 @@ export const store = createStore(
composeEnhancers(applyMiddleware(sagaMiddleware))
);
-export function configureStore(): { store: Store, persistor: Persistor } {
+export function configureStore(): { store: Store; persistor: Persistor } {
sagaMiddleware.run(userSaga);
sagaMiddleware.run(mapSaga);
sagaMiddleware.run(editorSaga);
@@ -65,3 +65,5 @@ history.listen((location, action) => {
if (action === 'REPLACE') return;
store.dispatch(editorLocationChanged(location.pathname));
});
+
+watchLocation((location: LatLngLiteral) => store.dispatch(setUserLocation(location)));
diff --git a/src/redux/user/actions.ts b/src/redux/user/actions.ts
index 81f970f..0f4bec4 100644
--- a/src/redux/user/actions.ts
+++ b/src/redux/user/actions.ts
@@ -1,5 +1,6 @@
import { USER_ACTIONS } from '~/redux/user/constants';
import { IUser } from "~/constants/auth";
+import { IRootReducer } from '.';
export const setUser = (user: IUser) => ({ type: USER_ACTIONS.SET_USER, user });
export const userLogout = () => ({ type: USER_ACTIONS.USER_LOGOUT });
@@ -24,3 +25,5 @@ export const modifyRoute = (address: string, { title, is_public }: { title: stri
});
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 });
+
+export const setUserLocation = (location: IRootReducer['location']) => ({ type: USER_ACTIONS.SET_USER_LOCATION, location });
diff --git a/src/redux/user/constants.ts b/src/redux/user/constants.ts
index e7cae5b..dbe4a00 100644
--- a/src/redux/user/constants.ts
+++ b/src/redux/user/constants.ts
@@ -5,7 +5,8 @@ export const USER_ACTIONS = {
GOT_VK_USER: 'GOT_VK_USER',
IFRAME_LOGIN_VK: 'IFRAME_LOGIN_VK',
-
+ SET_USER_LOCATION: 'SET_USER_LOCATION',
+
SEARCH_SET_TITLE: 'SEARCH_SET_TITLE',
SEARCH_SET_DISTANCE: 'SEARCH_SET_DISTANCE',
SEARCH_CHANGE_DISTANCE: 'SEARCH_CHANGE_DISTANCE',
diff --git a/src/redux/user/handlers.ts b/src/redux/user/handlers.ts
index 3550434..5473031 100644
--- a/src/redux/user/handlers.ts
+++ b/src/redux/user/handlers.ts
@@ -1,7 +1,7 @@
-import { IRootState } from ".";
-import * as ActionCreators from './actions'
-import { TABS } from "~/constants/dialogs";
-import { USER_ACTIONS } from "./constants";
+import { IRootState, IRootReducer } from '.';
+import * as ActionCreators from './actions';
+import { TABS } from '~/constants/dialogs';
+import { USER_ACTIONS } from './constants';
type UnsafeReturnType = T extends (...args: any[]) => infer R ? R : any;
@@ -17,7 +17,10 @@ const setUser: ActionHandler = (state, { user })
},
});
-const searchSetTitle: ActionHandler = (state, { title = '' }) => ({
+const searchSetTitle: ActionHandler = (
+ state,
+ { title = '' }
+) => ({
...state,
routes: {
...state.routes,
@@ -25,33 +28,42 @@ const searchSetTitle: ActionHandler = (sta
...state.routes.filter,
title,
distance: [0, 10000],
- }
- }
+ },
+ },
});
-const searchSetDistance: ActionHandler = (state, { distance = [0, 9999] }) => ({
+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]] }) => ({
+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 }) => ({
+const searchPutRoutes: ActionHandler = (
+ state,
+ { list = [], min, max, limit, step, shift }
+) => ({
...state,
routes: {
...state.routes,
@@ -61,50 +73,68 @@ const searchPutRoutes: ActionHandler = (s
shift,
filter: {
...state.routes.filter,
- distance: (state.routes.filter.min === state.routes.filter.max)
- ? [min, max]
- : state.routes.filter.distance,
+ distance:
+ state.routes.filter.min === state.routes.filter.max
+ ? [min, max]
+ : state.routes.filter.distance,
min,
max,
- }
- }
+ },
+ },
});
-const searchSetLoading: ActionHandler = (state, { loading = false }) => ({
+const searchSetLoading: ActionHandler = (
+ state,
+ { loading = false }
+) => ({
...state,
routes: {
...state.routes,
loading,
- }
+ },
});
-const setStarred: ActionHandler = (state, { is_published = false }) => ({ ...state, is_published });
+const setStarred: ActionHandler = (
+ state,
+ { is_published = false }
+) => ({ ...state, is_published });
const mapsSetShift: ActionHandler = (state, { shift = 0 }) => ({
...state,
routes: {
...state.routes,
shift,
- }
+ },
});
-const setRouteStarred: ActionHandler = (state, { address, is_published }) => ({
+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 => (
+ 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 = ({
+const setLocation = (
+ state: IRootReducer,
+ { location }: ReturnType
+): IRootReducer => ({
+ ...state,
+ location,
+});
+
+export const USER_HANDLERS = {
[USER_ACTIONS.SET_USER]: setUser,
+ [USER_ACTIONS.SET_USER_LOCATION]: setLocation,
[USER_ACTIONS.SEARCH_SET_TITLE]: searchSetTitle,
[USER_ACTIONS.SEARCH_SET_DISTANCE]: searchSetDistance,
@@ -118,4 +148,4 @@ export const USER_HANDLERS = ({
[USER_ACTIONS.SET_STARRED]: setStarred,
[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 ef444d4..162d8d0 100644
--- a/src/redux/user/index.ts
+++ b/src/redux/user/index.ts
@@ -1,43 +1,44 @@
import { createReducer } from '~/utils/reducer';
import { DEFAULT_USER, IUser } from '~/constants/auth';
import { USER_HANDLERS } from './handlers';
+import { LatLngLiteral } from 'leaflet';
export interface IRouteListItem {
- address: string,
- title: string,
- distance: number,
- is_public: boolean,
- is_published: boolean,
- updated_at: string,
+ address: string;
+ title: string;
+ distance: number;
+ is_public: boolean;
+ is_published: boolean;
+ updated_at: string;
}
export interface IRootReducer {
// ready: boolean,
- user: IUser,
-
+ user: IUser;
+ location: LatLngLiteral;
routes: {
- limit: 0,
- loading: boolean,
- list: Array,
- step: number,
- shift: number,
+ limit: 0;
+ loading: boolean;
+ list: Array;
+ step: number;
+ shift: number;
filter: {
- title: string,
- starred: boolean,
- distance: [number, number],
- author: string,
- tab: string,
- min: number,
- max: number,
- }
- },
+ title: string;
+ starred: boolean;
+ distance: [number, number];
+ author: string;
+ tab: string;
+ min: number;
+ max: number;
+ };
+ };
}
export type IRootState = Readonly;
export const INITIAL_STATE: IRootReducer = {
user: { ...DEFAULT_USER },
-
+ location: null,
routes: {
limit: 0,
loading: false, // <-- maybe delete this
@@ -52,7 +53,7 @@ export const INITIAL_STATE: IRootReducer = {
tab: '',
min: 0,
max: 10000,
- }
+ },
},
};
diff --git a/src/redux/user/sagas.ts b/src/redux/user/sagas.ts
index 744dd87..32c0893 100644
--- a/src/redux/user/sagas.ts
+++ b/src/redux/user/sagas.ts
@@ -34,6 +34,7 @@ import { selectUser, selectUserUser } from './selectors';
import { mapInitSaga } from '~/redux/map/sagas';
import { editorSetDialog, editorSetDialogActive } from '../editor/actions';
import { selectEditor } from '../editor/selectors';
+import { getLocation, watchLocation } from '~/utils/window';
function* generateGuestSaga() {
const {
@@ -343,8 +344,13 @@ export function* updateUserRoutes() {
yield put(searchSetTab(TABS.MY));
}
+// function* getUserLocation() {
+ // yield call(watchLocation, ActionCreators.setUserLocation);
+// }
+
export function* userSaga() {
yield takeLatest(REHYDRATE, authCheckSaga);
+ // yield takeLatest(REHYDRATE, getUserLocation);
yield takeEvery(USER_ACTIONS.USER_LOGOUT, userLogoutSaga);
yield takeLatest(USER_ACTIONS.GOT_VK_USER, gotVkUserSaga);
diff --git a/src/redux/user/selectors.ts b/src/redux/user/selectors.ts
index 6de1196..7a8cc68 100644
--- a/src/redux/user/selectors.ts
+++ b/src/redux/user/selectors.ts
@@ -1,4 +1,5 @@
import { IState } from '~/redux/store'
export const selectUser = (state: IState) => state.user;
-export const selectUserUser = (state: IState) => state.user.user;
\ No newline at end of file
+export const selectUserUser = (state: IState) => state.user.user;
+export const selectUserLocation = (state: IState) => state.user.location;
\ No newline at end of file
diff --git a/src/styles/map.less b/src/styles/map.less
index 608a19b..671303e 100644
--- a/src/styles/map.less
+++ b/src/styles/map.less
@@ -338,3 +338,12 @@
.leaflet-pane {
user-select: none;
}
+
+.current-location {
+ svg {
+ fill: @bar_background;
+ stroke: white;
+ stroke-width: 0.2px;
+ }
+}
+
\ No newline at end of file
diff --git a/src/utils/window.ts b/src/utils/window.ts
index 8174964..0d60bb7 100644
--- a/src/utils/window.ts
+++ b/src/utils/window.ts
@@ -1,3 +1,38 @@
import { MOBILE_BREAKPOINT } from '~/config/frontend';
+import { LatLngLiteral } from 'leaflet';
-export const isMobile = (): boolean => (window.innerWidth <= MOBILE_BREAKPOINT);
+export const isMobile = (): boolean => window.innerWidth <= MOBILE_BREAKPOINT;
+
+export const getLocation = (callback: (pos: LatLngLiteral) => void) => {
+ window.navigator.geolocation.getCurrentPosition(position => {
+ console.log('getting pos');
+
+ if (!position || !position.coords || !position.coords.latitude || !position.coords.longitude)
+ return callback(null);
+
+ const { latitude: lat, longitude: lng } = position.coords;
+
+ callback({ lat, lng });
+ return;
+ });
+};
+
+export const watchLocation = (callback: (pos: LatLngLiteral) => void): number => {
+ return window.navigator.geolocation.watchPosition(
+ position => {
+ console.log('Watch?');
+
+ if (!position || !position.coords || !position.coords.latitude || !position.coords.longitude)
+ return callback(null);
+
+ const { latitude: lat, longitude: lng } = position.coords;
+
+ callback({ lat, lng });
+ return;
+ },
+ () => callback(null),
+ {
+ timeout: 30,
+ }
+ );
+};