Added the files.

This commit is contained in:
Batuhan Berk Başoğlu 2021-03-30 21:50:36 -04:00
commit 38ccdcbfe5
124 changed files with 32079 additions and 0 deletions

131
client/src/reducers/auth.js Normal file
View 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
};

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

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