diff --git a/.eslintrc b/.eslintrc index 8e5c784..eb2cac7 100755 --- a/.eslintrc +++ b/.eslintrc @@ -16,7 +16,6 @@ "global-require": 1, "react/no-multi-comp": 1, "react/jsx-filename-extension": 0, - "camelcase": 1, "import/no-unresolved": 1, "import/prefer-default-export": 0, "import/extensions": 1, @@ -29,7 +28,9 @@ "jsx-a11y/no-autofocus": 0, "react/jsx-closing-tag-location": 0, "prefer-promise-reject-errors": 0, - "jsx-a11y/mouse-events-have-key-events": 0 + "jsx-a11y/mouse-events-have-key-events": 0, + "camelcase": 0, + "no-trailing-spaces": 0, }, "globals": { "document": false, diff --git a/src/constants/types.js b/src/constants/types.js new file mode 100644 index 0000000..b1ee867 --- /dev/null +++ b/src/constants/types.js @@ -0,0 +1,18 @@ +import { ROLES } from '$constants/auth'; + +export type UserType = { + new_messages: Number, + place_types: Object, + random_url: String, + role: String, + routes: Array, + success: Boolean, + id: String, + token: String, + userdata: { + name: String, + agent: String, + ip: String, + photo: String, + } +}; diff --git a/src/containers/App.jsx b/src/containers/App.jsx index 6101d1a..be3129c 100644 --- a/src/containers/App.jsx +++ b/src/containers/App.jsx @@ -1,6 +1,7 @@ +// @flow import React from 'react'; -import { Editor } from '$modules/Editor'; +import { Editor, editor } from '$modules/Editor'; import { EditorPanel } from '$components/panels/EditorPanel'; import { Fills } from '$components/Fills'; import { DEFAULT_LOGO } from '$constants/logos'; @@ -10,14 +11,30 @@ import { getGuestToken, checkUserToken, getStoredMap } from '$utils/api'; import { storeData, getData } from '$utils/storage'; import { UserPanel } from '$components/panels/UserPanel'; import { getUrlData, pushPath } from '$utils/history'; -import { Provider } from 'react-redux'; -import { PersistGate } from 'redux-persist/integration/react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import { configureStore } from '$redux/store'; +import { hot } from 'react-hot-loader'; +import type { UserType } from '$constants/types'; -const { store, persistor } = configureStore(); +type Props = { + user: UserType, +} -export class App extends React.Component { +type State = { + mode: String, + editing: Boolean, + logo: String, + routerPoints: Number, + totalDistance: Number, + estimateTime: Number, + activeSticker: String, + title: String, + address: String, + changed: Boolean, +} + +class Component extends React.Component { state = { mode: 'none', editing: false, @@ -35,28 +52,28 @@ export class App extends React.Component { }; componentDidMount() { - this.authInit(); - window.editor = this.editor; + // this.authInit(); + window.editor = editor; } - - mapInit = () => { - const { path, mode } = getUrlData(); - if (path) { - getStoredMap({ name: path }) - .then(this.setDataOnLoad) - .then(() => { - if (mode && mode === 'edit') { - this.editor.startEditing(); - } else { - this.editor.stopEditing(); - } - }) - .catch(this.startEmptyEditor); - } else { - // this.hideLoader(); - this.startEmptyEditor(); - } - }; + // + // mapInit = () => { + // const { path, mode } = getUrlData(); + // if (path) { + // getStoredMap({ name: path }) + // .then(this.setDataOnLoad) + // .then(() => { + // if (mode && mode === 'edit') { + // editor.startEditing(); + // } else { + // editor.stopEditing(); + // } + // }) + // .catch(this.startEmptyEditor); + // } else { + // // this.hideLoader(); + // this.startEmptyEditor(); + // } + // }; startEmptyEditor = () => { const { user } = this.state; @@ -64,8 +81,8 @@ export class App extends React.Component { pushPath(`/${user.random_url}/edit`); - this.editor.owner = user.id; - this.editor.startEditing(); + editor.owner = user.id; + editor.startEditing(); this.hideLoader(); @@ -81,7 +98,7 @@ export class App extends React.Component { setDataOnLoad = data => { this.clearChanged(); - this.editor.setData(data); + editor.setData(data); this.hideLoader(); }; @@ -128,47 +145,47 @@ export class App extends React.Component { this.setState({ changed: false }); }; - editor = new Editor({ - container: 'map', - mode: this.state.mode, - setMode: this.setMode, - setRouterPoints: this.setRouterPoints, - setTotalDist: this.setTotalDist, - setActiveSticker: this.setActiveSticker, - setLogo: this.setLogo, - setEditing: this.setEditing, - setTitle: this.setTitle, - setAddress: this.setAddress, - getUser: this.getUser, - triggerOnChange: this.triggerOnChange, - clearChanged: this.clearChanged, - getTitle: this.getTitle, - }); + // editor = new Editor({ + // container: 'map', + // mode: this.state.mode, + // setMode: this.setMode, + // setRouterPoints: this.setRouterPoints, + // setTotalDist: this.setTotalDist, + // setActiveSticker: this.setActiveSticker, + // setLogo: this.setLogo, + // setEditing: this.setEditing, + // setTitle: this.setTitle, + // setAddress: this.setAddress, + // getUser: this.getUser, + // triggerOnChange: this.triggerOnChange, + // clearChanged: this.clearChanged, + // getTitle: this.getTitle, + // }); - authInit = () => { - const user = this.getUserData(); - - const { id, token } = (user || {}); - - if (id && token) { - checkUserToken({ - id, - token - }) - .then(this.setUser) - .then(this.mapInit); - } else { - getGuestToken() - .then(this.setUser) - .then(this.mapInit); - } - }; + // authInit = () => { + // const user = this.getUserData(); + // + // const { id, token } = (user || {}); + // + // if (id && token) { + // checkUserToken({ + // id, + // token + // }) + // .then(this.setUser) + // .then(this.mapInit); + // } else { + // getGuestToken() + // .then(this.setUser) + // .then(this.mapInit); + // } + // }; setUser = user => { if (!user.token || !user.id) return; - if (this.state.user.id === this.editor.owner) { - this.editor.owner = user.id; + if (this.state.user.id === editor.owner) { + editor.owner = user.id; } this.setState({ @@ -188,8 +205,8 @@ export class App extends React.Component { getUserData = () => getData('user') || null; userLogout = () => { - if (this.state.user.id === this.editor.owner) { - this.editor.owner = null; + if (this.state.user.id === editor.owner) { + editor.owner = null; } // this.setState({ @@ -201,45 +218,61 @@ export class App extends React.Component { render() { const { - editor, state: { - mode, routerPoints, totalDistance, estimateTime, activeSticker, logo, user, editing, title, address, changed, + mode, routerPoints, totalDistance, estimateTime, activeSticker, logo, editing, title, address, changed, }, + props: { + user, + } } = this; - return ( - - -
- +
+ - + - + - -
- - + +
); } } + +function mapStateToProps(state) { + const { + user, + } = state; + + return { + user + }; +} + +const mapDispatchToProps = dispatch => bindActionCreators({ + +}, dispatch); + +export const App = connect( + mapStateToProps, + mapDispatchToProps +)(hot(module)(Component)); diff --git a/src/index.js b/src/index.js index e6f3bb6..5f071a7 100644 --- a/src/index.js +++ b/src/index.js @@ -5,16 +5,23 @@ import ReactDOM from 'react-dom'; import { App } from '$containers/App'; import '$styles/main.less'; -import 'raleway-cyrillic'; +import 'raleway-cyrillic/raleway.css'; -// import { Provider } from 'react-redux'; +import { Provider } from 'react-redux'; // import { ConnectedRouter } from 'react-router-redux'; -// import { PersistGate } from 'redux-persist/integration/react'; -// import configureStore, { history } from '$redux/store'; -// const { store, persistor } = configureStore(); +import { PersistGate } from 'redux-persist/integration/react'; +import { configureStore } from '$redux/store'; + +const { store, persistor } = configureStore(); export const Index = () => ( - + + + + + ); ReactDOM.render(, document.getElementById('index')); + +// diff --git a/src/modules/Editor.js b/src/modules/Editor.js index b922523..99336fb 100644 --- a/src/modules/Editor.js +++ b/src/modules/Editor.js @@ -8,27 +8,28 @@ import { DEFAULT_LOGO } from '$constants/logos'; import { parseStickerAngle, parseStickerStyle } from '$utils/import'; import { getUrlData, pushPath } from '$utils/history'; +import { store } from '$redux/store'; +import { setEditing } from '$redux/user/actions'; export class Editor { constructor({ - container, - mode, + // container, + // mode, setMode, setRouterPoints, setTotalDist, setActiveSticker, setLogo, - setEditing, + // setEditing, setTitle, setAddress, - getUser, triggerOnChange, clearChanged, - getTitle, + // getTitle, }) { this.logo = DEFAULT_LOGO; this.owner = null; - this.map = new Map({ container }); + this.map = new Map({ container: 'map' }); this.initialData = {}; const { @@ -76,18 +77,22 @@ export class Editor { this.setActiveSticker = setActiveSticker; this.setLogo = setLogo; this.setMode = setMode; - this.setEditing = setEditing; + // this.setEditing = setEditing; this.setTitle = setTitle; this.setAddress = setAddress; - this.getUser = getUser; - this.mode = mode; - this.getTitle = getTitle; + // this.getUser = getUser; + this.mode = 'none'; + // this.getTitle = getTitle; map.addEventListener('mouseup', this.onClick); map.addEventListener('dragstart', () => lockMapClicks(true)); map.addEventListener('dragstop', () => lockMapClicks(false)); } + getUser = () => store.getState().user; + getTitle = () => store.getState().title; + setEditing = editing => store.dispatch(setEditing(editing)); + createStickerOnClick = (e) => { if (!e || !e.latlng || !this.activeSticker) return; const { latlng } = e; @@ -293,3 +298,20 @@ export class Editor { return (!route || route.length < 1) && (!stickers || stickers.length <= 0); } } + +export const editor = new Editor({ + container: 'map', + mode: 'none', + // setMode: this.setMode, + // setRouterPoints: this.setRouterPoints, + // setTotalDist: this.setTotalDist, + // setActiveSticker: this.setActiveSticker, + // setLogo: this.setLogo, + // setEditing: this.setEditing, + // setTitle: this.setTitle, + // setAddress: this.setAddress, + // getUser: this.getUser, + // triggerOnChange: this.triggerOnChange, + // clearChanged: this.clearChanged, + // getTitle: this.getTitle, +}); diff --git a/src/parts/map.js b/src/parts/map.js index 8bffded..93fbc0d 100644 --- a/src/parts/map.js +++ b/src/parts/map.js @@ -25,8 +25,8 @@ const point_array = { const points = L.layerGroup(); -let mode = 'none'; -const current_map_style = 'default'; +// let mode = 'none'; +const current_map_style = 'dgis'; // Интересные места; // const places_layer; diff --git a/src/redux/auth/actions.js b/src/redux/auth/actions.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/redux/auth/constants.js b/src/redux/auth/constants.js deleted file mode 100644 index 8f853dc..0000000 --- a/src/redux/auth/constants.js +++ /dev/null @@ -1,15 +0,0 @@ -export const ACTIONS = { - -}; - -export const ROLES = { - guest: 'guest', - vk: 'vk', -}; - -export const EMPTY_USER = { - token: '', - name: '', - role: ROLES.guest, - picture: '', -}; diff --git a/src/redux/auth/reducer.js b/src/redux/auth/reducer.js deleted file mode 100644 index 2bc7285..0000000 --- a/src/redux/auth/reducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import { createReducer } from 'reduxsauce'; -import { ACTIONS, EMPTY_USER } from '$redux/auth/constants'; - -const HANDLERS = { - -}; - -export const INITIAL_STATE = { - ...EMPTY_USER -}; - -export const authReducer = createReducer(INITIAL_STATE, HANDLERS); diff --git a/src/redux/auth/sagas.js b/src/redux/auth/sagas.js deleted file mode 100644 index fdb91d3..0000000 --- a/src/redux/auth/sagas.js +++ /dev/null @@ -1,4 +0,0 @@ -export function* authSaga() { - // Login - // yield takeLatest(AUTH_ACTIONS.SEND_LOGIN_REQUEST, sendLoginRequestSaga); -} diff --git a/src/redux/store.js b/src/redux/store.js index 0ba87fd..2d66baf 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -3,15 +3,16 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux'; import { persistStore, persistReducer } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import createSagaMiddleware from 'redux-saga'; -import createHistory from 'history/createBrowserHistory'; + +// import createHistory from 'history/createBrowserHistory'; // import { routerReducer, routerMiddleware } from 'react-router-redux'; -import { authReducer } from '$redux/auth/reducer'; -import { authSaga } from '$redux/auth/sagas'; +import { userReducer } from '$redux/user/reducer'; +import { userSaga } from '$redux/user/sagas'; -const authPersistConfig = { - key: 'auth', - blacklist: [], +const userPersistConfig = { + key: 'user', + blacklist: ['editing'], storage, }; @@ -31,18 +32,15 @@ const composeEnhancers = export const store = createStore( combineReducers({ - auth: persistReducer(authPersistConfig, authReducer), + user: persistReducer(userPersistConfig, userReducer), // routing: routerReducer }), - composeEnhancers(applyMiddleware( - // routerMiddleware(history), - sagaMiddleware - )) + composeEnhancers(applyMiddleware(/* routerMiddleware(history), */ sagaMiddleware)) ); export function configureStore() { // run sagas - sagaMiddleware.run(authSaga); + sagaMiddleware.run(userSaga); const persistor = persistStore(store); diff --git a/src/redux/user/actions.js b/src/redux/user/actions.js new file mode 100644 index 0000000..58908c9 --- /dev/null +++ b/src/redux/user/actions.js @@ -0,0 +1,4 @@ +import { ACTIONS } from '$redux/user/constants'; + +export const setUser = user => ({ type: ACTIONS.SET_USER, user }); +export const setEditing = editing => ({ type: ACTIONS.SET_EDITING, editing }); diff --git a/src/redux/user/constants.js b/src/redux/user/constants.js new file mode 100644 index 0000000..bc847cf --- /dev/null +++ b/src/redux/user/constants.js @@ -0,0 +1,4 @@ +export const ACTIONS = { + SET_USER: 'SET_USER', + SET_EDITING: 'SET_EDITING', +}; diff --git a/src/redux/user/reducer.js b/src/redux/user/reducer.js new file mode 100644 index 0000000..51c93af --- /dev/null +++ b/src/redux/user/reducer.js @@ -0,0 +1,25 @@ +import { createReducer } from 'reduxsauce'; +import { ACTIONS, EMPTY_USER } from '$redux/user/constants'; +import { DEFAULT_USER } from '$constants/auth'; + +const setUser = (state, { user }) => ({ + ...state, + ...user, +}); + +const setEditing = (state, { editing }) => ({ + ...state, + editing, +}); + + +const HANDLERS = { + [ACTIONS.SET_USER]: setUser, + [ACTIONS.SET_EDITING]: setEditing, +}; + +export const INITIAL_STATE = { + ...DEFAULT_USER +}; + +export const userReducer = createReducer(INITIAL_STATE, HANDLERS); diff --git a/src/redux/user/sagas.js b/src/redux/user/sagas.js new file mode 100644 index 0000000..e04ad26 --- /dev/null +++ b/src/redux/user/sagas.js @@ -0,0 +1,80 @@ +import { REHYDRATE } from 'redux-persist'; +import { takeLatest, select, call, put } from 'redux-saga/effects'; +import { checkUserToken, getGuestToken, getStoredMap } from '$utils/api'; +import { setUser } from '$redux/user/actions'; +import { getUrlData, pushPath } from '$utils/history'; +import { editor } from '$modules/Editor'; + +const getUser = state => (state.user); +const hideLoader = () => { + document.getElementById('loader').style.opacity = 0; + document.getElementById('loader').style.pointerEvents = 'none'; + + return true; +}; + +function* generateGuestSaga() { + const user = yield call(getGuestToken); + yield put(setUser(user)); + + return user; +} + +function* startEmptyEditorSaga() { + const { id, random_url } = yield select(getUser); + + console.log('RURL', random_url); + pushPath(`/${random_url}/edit`); + + editor.owner = id; + editor.startEditing(); + + return hideLoader(); + + // todo: this.clearChanged(); +} + +function* mapInitSaga() { + const { path, mode } = getUrlData(); + + if (path) { + const map = yield call(getStoredMap, { name: path }); + + if (map) { + // todo: this.clearChanged(); + editor.setData(map); + + if (mode && mode === 'edit') { + editor.startEditing(); + } else { + editor.stopEditing(); + } + + return hideLoader(); + } + } + + return yield call(startEmptyEditorSaga); +} + +function* authChechSaga() { + const { id, token } = yield select(getUser); + + if (id && token) { + const user = yield call(checkUserToken, { id, token }); + + if (user && user.success) { + yield put(setUser(user)); + return yield call(mapInitSaga); + } + } + + yield call(generateGuestSaga); + return yield call(mapInitSaga); +} + +export function* userSaga() { + // Login + // yield takeLatest(AUTH_ACTIONS.SEND_LOGIN_REQUEST, sendLoginRequestSaga); + yield takeLatest(REHYDRATE, authChechSaga); +} diff --git a/src/styles/main.less b/src/styles/main.less index a280a4f..2725518 100644 --- a/src/styles/main.less +++ b/src/styles/main.less @@ -12,6 +12,7 @@ body { font-family: 'Raleway', sans-serif; font-size: 14px; + padding: 0; } .gray { diff --git a/src/utils/api.js b/src/utils/api.js index a00036a..a08471d 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -10,7 +10,7 @@ export const checkUserToken = ({ id, token }) => axios.get(API.CHECK_TOKEN, { token, action: 'check_token', } -}).then(result => (result && result.data && { ...result.data, id, token })) +}).then(result => (result && result.data && { ...result.data, id, token })); export const getGuestToken = () => axios.get(API.GET_GUEST, { params: {