Added the files.
This commit is contained in:
commit
38ccdcbfe5
124 changed files with 32079 additions and 0 deletions
131
client/src/reducers/auth.js
Normal file
131
client/src/reducers/auth.js
Normal file
|
@ -0,0 +1,131 @@
|
|||
import config from '../config/config'
|
||||
import storage from '../lib/storage';
|
||||
import Immutable from 'immutable';
|
||||
|
||||
import { replace } from 'react-router-redux';
|
||||
|
||||
/** ********************************************
|
||||
** Constants **
|
||||
******************************************** */
|
||||
|
||||
const AUTH_USER = Symbol();
|
||||
const UNAUTH_USER = Symbol();
|
||||
const AUTH_ERROR = Symbol();
|
||||
|
||||
const initState = () => {
|
||||
const token = storage.get('token');
|
||||
return Immutable.fromJS({
|
||||
error: null,
|
||||
timestamp: null,
|
||||
authenticated: !!token,
|
||||
isAdmin: !!token && tokenIsAdmin(token),
|
||||
});
|
||||
};
|
||||
|
||||
/** ********************************************
|
||||
** Helper Functions **
|
||||
******************************************** */
|
||||
|
||||
const tokenGetClaims = (token) => {
|
||||
if (!token) {
|
||||
return {};
|
||||
}
|
||||
const tokenArray = token.split('.');
|
||||
if (tokenArray.length !== 3) {
|
||||
return {};
|
||||
}
|
||||
return JSON.parse(window.atob(tokenArray[1].replace('-', '+').replace('_', '/')));
|
||||
};
|
||||
|
||||
const tokenIsAdmin = token => !!tokenGetClaims(token).admin;
|
||||
|
||||
/** ********************************************
|
||||
** Auth States **
|
||||
******************************************** */
|
||||
|
||||
class State {
|
||||
static Auth(error, token) {
|
||||
return {
|
||||
type: error ? AUTH_ERROR : AUTH_USER,
|
||||
isAdmin: error ? undefined : tokenIsAdmin(token),
|
||||
error: error || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static UnAuth(error) {
|
||||
return {
|
||||
type: UNAUTH_USER,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** ********************************************
|
||||
** Actions **
|
||||
******************************************** */
|
||||
|
||||
const LoginUser = (email, password) => async (dispatch) => {
|
||||
try {
|
||||
const response = await fetch(config.apiRoutes.API_URL + config.apiRoutes.auth.login, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
const status = await response.status;
|
||||
const data = await response.json();
|
||||
|
||||
if (!data) throw new Error('Empty response from server');
|
||||
if (data.error) throw new Error(data.error.message);
|
||||
|
||||
storage.set('token', data.token);
|
||||
dispatch(State.Auth(null, data.token));
|
||||
} catch (err) {
|
||||
dispatch(State.Auth(err.message));
|
||||
}
|
||||
};
|
||||
|
||||
const LogoutUser = error => async (dispatch) => {
|
||||
console.log('here')
|
||||
dispatch(State.UnAuth());
|
||||
storage.remove('token');
|
||||
storage.remove('auth');
|
||||
dispatch(replace('/login'));
|
||||
};
|
||||
|
||||
/** ********************************************
|
||||
** Auth Reducer **
|
||||
******************************************** */
|
||||
|
||||
const Auth = (state = initState(), action) => {
|
||||
switch (action.type) {
|
||||
case AUTH_USER:
|
||||
return state.withMutations((val) => {
|
||||
val.set('error', null);
|
||||
val.set('timestamp', Date.now());
|
||||
val.set('authenticated', true);
|
||||
val.set('isAdmin', action.isAdmin);
|
||||
});
|
||||
|
||||
case UNAUTH_USER:
|
||||
return state.withMutations((val) => {
|
||||
val.set('authenticated', false);
|
||||
val.set('isAdmin', false);
|
||||
});
|
||||
|
||||
case AUTH_ERROR:
|
||||
return state.withMutations((val) => {
|
||||
val.set('error', action.error);
|
||||
val.set('timestamp', Date.now());
|
||||
});
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
Auth, LoginUser, LogoutUser
|
||||
};
|
37
client/src/reducers/index.js
Normal file
37
client/src/reducers/index.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
|
||||
import { routerReducer } from "react-router-redux";
|
||||
import thunk from "redux-thunk";
|
||||
|
||||
import { Auth, LoginUser, LogoutUser } from "./auth";
|
||||
import { Registration, RegisterUser, registerDone } from "./registration";
|
||||
import {
|
||||
User,
|
||||
FetchUser,
|
||||
UpdateUser,
|
||||
UserUpdateDone,
|
||||
} from "./user";
|
||||
|
||||
const store = createStore(
|
||||
combineReducers({
|
||||
Auth,
|
||||
Registration,
|
||||
User,
|
||||
router: routerReducer,
|
||||
}),
|
||||
compose(
|
||||
applyMiddleware(thunk),
|
||||
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
)
|
||||
);
|
||||
|
||||
const Action = {
|
||||
LoginUser,
|
||||
LogoutUser,
|
||||
RegisterUser,
|
||||
registerDone,
|
||||
FetchUser,
|
||||
UpdateUser,
|
||||
UserUpdateDone,
|
||||
};
|
||||
|
||||
export { store, Action };
|
96
client/src/reducers/registration.js
Normal file
96
client/src/reducers/registration.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import config from '../config/config';
|
||||
import Immutable from 'immutable';
|
||||
import { Action } from 'reducers';
|
||||
|
||||
/** ********************************************
|
||||
** Constants **
|
||||
******************************************** */
|
||||
|
||||
const REGISTER_SUCCESS = Symbol();
|
||||
const REGISTER_ERR = Symbol();
|
||||
const REGISTER_DONE = Symbol();
|
||||
|
||||
const defaultState = Immutable.fromJS({
|
||||
user: {},
|
||||
registered: false,
|
||||
registerSuccess: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
/** ********************************************
|
||||
** Registration States **
|
||||
******************************************** */
|
||||
|
||||
class State {
|
||||
static Register(error, user) {
|
||||
return {
|
||||
type: error ? REGISTER_ERR : REGISTER_SUCCESS,
|
||||
user: error ? undefined : user,
|
||||
error: error || undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** ********************************************
|
||||
** Actions **
|
||||
******************************************** */
|
||||
|
||||
const RegisterUser = user => async (dispatch) => {
|
||||
try {
|
||||
const response = await fetch(config.apiRoutes.API_URL + config.apiRoutes.auth.register, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ user }),
|
||||
});
|
||||
|
||||
const status = await response.status;
|
||||
const data = await response.json();
|
||||
|
||||
if (!data) throw new Error('Empty response from server');
|
||||
if (data.error) throw new Error(data.error.message);
|
||||
|
||||
dispatch(State.Register(null, data.user));
|
||||
dispatch(Action.LoginUser(user.email, user.password));
|
||||
} catch (err) {
|
||||
dispatch(State.Register(err.message));
|
||||
}
|
||||
};
|
||||
|
||||
/** ********************************************
|
||||
** Registration Reducer **
|
||||
******************************************** */
|
||||
|
||||
const Registration = (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
case REGISTER_SUCCESS:
|
||||
return state.withMutations((val) => {
|
||||
val.set('user', action.user);
|
||||
val.set('error', null);
|
||||
val.set('registered', true);
|
||||
val.set('registerSuccess', true);
|
||||
});
|
||||
|
||||
case REGISTER_ERR:
|
||||
return state.withMutations((val) => {
|
||||
val.set('error', action.error);
|
||||
val.set('registered', true);
|
||||
val.set('registerSuccess', false);
|
||||
});
|
||||
|
||||
case REGISTER_DONE:
|
||||
return state.withMutations((val) => {
|
||||
val.set('registered', false);
|
||||
});
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const registerDone = () => ({ type: REGISTER_DONE });
|
||||
export {
|
||||
Registration, RegisterUser, registerDone,
|
||||
};
|
150
client/src/reducers/user.js
Normal file
150
client/src/reducers/user.js
Normal file
|
@ -0,0 +1,150 @@
|
|||
import Immutable from "immutable";
|
||||
import storage from '../lib/storage';
|
||||
import config from '../config/config';
|
||||
|
||||
import { LogoutUser } from "./auth";
|
||||
|
||||
/** ********************************************
|
||||
** Constants **
|
||||
******************************************** */
|
||||
|
||||
const FETCH_USER = Symbol();
|
||||
const FETCH_USER_ERR = Symbol();
|
||||
|
||||
const UPDATE_USER_ERR = Symbol();
|
||||
const UPDATE_USER_SUCCESS = Symbol();
|
||||
const UPDATE_COMPLETED = Symbol();
|
||||
|
||||
const defaultState = Immutable.fromJS({
|
||||
profile: {},
|
||||
updated: false,
|
||||
updateSuccess: false,
|
||||
fetchSuccess: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
/** ********************************************
|
||||
** User States **
|
||||
******************************************** */
|
||||
|
||||
class State {
|
||||
static FetchUser(error, user) {
|
||||
return {
|
||||
type: error ? FETCH_USER_ERR : FETCH_USER,
|
||||
user: error ? undefined : user,
|
||||
error: error || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static UpdateUser(error) {
|
||||
return {
|
||||
type: error ? UPDATE_USER_ERR : UPDATE_USER_SUCCESS,
|
||||
error: error || undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** ********************************************
|
||||
** Actions **
|
||||
******************************************** */
|
||||
|
||||
const FetchUser = () => async (dispatch) => {
|
||||
try {
|
||||
const response = await fetch(config.apiRoutes.API_URL + config.apiRoutes.user.user, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${storage.get("token")}`,
|
||||
},
|
||||
});
|
||||
|
||||
const status = await response.status;
|
||||
if (status === 401 || status === 403) {
|
||||
return dispatch(LogoutUser());
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (!data) throw new Error("Empty response from server");
|
||||
if (data.error) throw new Error(data.error.message);
|
||||
|
||||
dispatch(State.FetchUser(null, data.user));
|
||||
} catch (err) {
|
||||
dispatch(State.FetchUser(err.message));
|
||||
}
|
||||
};
|
||||
|
||||
const UpdateUser = (user) => async (dispatch) => {
|
||||
try {
|
||||
const response = await fetch(config.apiRoutes.API_URL + config.apiRoutes.user.user, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${storage.get("token")}`,
|
||||
},
|
||||
body: JSON.stringify({ user }),
|
||||
});
|
||||
|
||||
const status = await response.status;
|
||||
if (status === 401 || status === 403) {
|
||||
return dispatch(LogoutUser());
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (!data) throw new Error("Empty response from server");
|
||||
if (data.error) throw new Error(data.error.message);
|
||||
|
||||
dispatch(State.FetchUser(null, data.user));
|
||||
dispatch(State.UpdateUser());
|
||||
} catch (err) {
|
||||
dispatch(State.UpdateUser(err.message));
|
||||
}
|
||||
};
|
||||
|
||||
/** ********************************************
|
||||
** User Reducer **
|
||||
******************************************** */
|
||||
|
||||
const User = (state = defaultState, action) => {
|
||||
switch (action.type) {
|
||||
case FETCH_USER:
|
||||
return state.withMutations((val) => {
|
||||
val.set("error", null);
|
||||
val.set("profile", action.user);
|
||||
val.set("fetchSuccess", true);
|
||||
});
|
||||
|
||||
case FETCH_USER_ERR:
|
||||
return state.withMutations((val) => {
|
||||
val.set("error", action.error);
|
||||
val.set("profile", {});
|
||||
val.set("fetchSuccess", false);
|
||||
});
|
||||
|
||||
case UPDATE_USER_ERR:
|
||||
return state.withMutations((val) => {
|
||||
val.set("error", action.error);
|
||||
val.set("updated", true);
|
||||
val.set("updateSuccess", false);
|
||||
});
|
||||
|
||||
case UPDATE_USER_SUCCESS:
|
||||
return state.withMutations((val) => {
|
||||
val.set("error", null);
|
||||
val.set("updated", true);
|
||||
val.set("updateSuccess", true);
|
||||
});
|
||||
|
||||
case UPDATE_COMPLETED:
|
||||
return state.withMutations((val) => {
|
||||
val.set("updated", false);
|
||||
});
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const UserUpdateDone = () => ({ type: UPDATE_COMPLETED });
|
||||
export { User, FetchUser, UpdateUser, UserUpdateDone };
|
Loading…
Add table
Add a link
Reference in a new issue