Initial commit
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
import { authConstants, alertConstants } from '../constants';
|
||||
import { dataService } from '../services';
|
||||
import { history } from '../helpers';
|
||||
|
||||
function donorLogin(email, password) {
|
||||
return dispatch => {
|
||||
dispatch(request({ email }));
|
||||
|
||||
dataService(
|
||||
dispatch,
|
||||
'post',
|
||||
'/api/auth/donor/login/',
|
||||
{ email, password },
|
||||
true
|
||||
)
|
||||
.then(data => {
|
||||
if (data.token) {
|
||||
// store jwt token in local storage to keep user logged in between page refreshes
|
||||
localStorage.setItem(
|
||||
'auth',
|
||||
JSON.stringify({ userType: 'donor', token: data.token })
|
||||
);
|
||||
}
|
||||
|
||||
// can use for permissions
|
||||
data.user.type = 'donor';
|
||||
dispatch(success({ message: data.message, user: data.user }));
|
||||
|
||||
history.push('/main');
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(failure(error));
|
||||
});
|
||||
};
|
||||
|
||||
function request(user) {
|
||||
return { type: authConstants.DONOR_LOGIN_REQUEST, payload: user };
|
||||
}
|
||||
function success(data) {
|
||||
return { type: authConstants.DONOR_LOGIN_SUCCESS, payload: data };
|
||||
}
|
||||
function failure(error) {
|
||||
return { type: authConstants.DONOR_LOGIN_FAILURE, payload: error };
|
||||
}
|
||||
}
|
||||
|
||||
function orgLogin(email, password) {
|
||||
return dispatch => {
|
||||
dispatch(request({ email }));
|
||||
|
||||
dataService(
|
||||
dispatch,
|
||||
'post',
|
||||
'/api/auth/org/login/',
|
||||
{ email, password },
|
||||
true
|
||||
)
|
||||
.then(data => {
|
||||
if (data.token) {
|
||||
// store jwt token in local storage to keep user logged in between page refreshes
|
||||
localStorage.setItem(
|
||||
'auth',
|
||||
JSON.stringify({ token: data.token, userType: 'org' })
|
||||
);
|
||||
}
|
||||
|
||||
// can use for permissions
|
||||
data.user.type = 'organization';
|
||||
dispatch(success({ message: data.message, user: data.user }));
|
||||
|
||||
history.push('/org/main');
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(failure(error));
|
||||
});
|
||||
};
|
||||
|
||||
function request(user) {
|
||||
return { type: authConstants.ORGANIZATION_LOGIN_REQUEST, payload: user };
|
||||
}
|
||||
function success(data) {
|
||||
return { type: authConstants.ORGANIZATION_LOGIN_SUCCESS, payload: data };
|
||||
}
|
||||
function failure(error) {
|
||||
return { type: authConstants.ORGANIZATION_LOGIN_FAILURE, payload: error };
|
||||
}
|
||||
}
|
||||
|
||||
// synchronous/blocks
|
||||
function logout() {
|
||||
localStorage.removeItem('auth');
|
||||
|
||||
history.push('/');
|
||||
return { type: authConstants.LOGOUT };
|
||||
}
|
||||
|
||||
function resetPasswordEmail(email, userType) {
|
||||
return dispatch => {
|
||||
dispatch(request({ email }));
|
||||
|
||||
dataService(
|
||||
dispatch,
|
||||
'get',
|
||||
'/api/auth/resetpassword',
|
||||
{ email, usertype: userType },
|
||||
false
|
||||
)
|
||||
.then(data => {
|
||||
dispatch(success(data));
|
||||
|
||||
history.push('/');
|
||||
|
||||
dispatch({
|
||||
type: alertConstants.SHOW_SNACK_BAR,
|
||||
alertMessage: 'Sent Password Reset Email!'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(failure(error));
|
||||
|
||||
dispatch({
|
||||
type: alertConstants.SHOW_SNACK_BAR,
|
||||
alertMessage: error.data.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function request(user) {
|
||||
return {
|
||||
type: authConstants.USER_RESET_PASSWORD_EMAIL_REQUEST,
|
||||
payload: user
|
||||
};
|
||||
}
|
||||
function success(data) {
|
||||
return {
|
||||
type: authConstants.USER_RESET_PASSWORD_EMAIL_SUCCESS,
|
||||
payload: data
|
||||
};
|
||||
}
|
||||
function failure(error) {
|
||||
return {
|
||||
type: authConstants.USER_RESET_PASSWORD_EMAIL_FAILURE,
|
||||
payload: error
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function resetPassword(password, code) {
|
||||
return dispatch => {
|
||||
dispatch(request());
|
||||
|
||||
dataService(
|
||||
dispatch,
|
||||
'post',
|
||||
'/api/auth/resetpassword',
|
||||
{ password, code },
|
||||
false
|
||||
)
|
||||
.then(data => {
|
||||
dispatch(success(data));
|
||||
|
||||
history.push('/');
|
||||
|
||||
dispatch({
|
||||
type: alertConstants.SHOW_SNACK_BAR,
|
||||
alertMessage: 'Successfully reset password!'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(failure(error));
|
||||
|
||||
dispatch({
|
||||
type: alertConstants.SHOW_SNACK_BAR,
|
||||
alertMessage: error.data.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function request(user) {
|
||||
return { type: authConstants.USER_RESET_PASSWORD_REQUEST, payload: user };
|
||||
}
|
||||
function success(data) {
|
||||
return { type: authConstants.USER_RESET_PASSWORD_SUCCESS, payload: data };
|
||||
}
|
||||
function failure(error) {
|
||||
return { type: authConstants.USER_RESET_PASSWORD_FAILURE, payload: error };
|
||||
}
|
||||
}
|
||||
|
||||
export const authActions = {
|
||||
donorLogin,
|
||||
orgLogin,
|
||||
logout,
|
||||
resetPasswordEmail,
|
||||
resetPassword
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './auth.actions';
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Route, Redirect } from 'react-router-dom';
|
||||
|
||||
const PrivateRoute = ({ component: Component, ...rest }) => {
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
render={props => {
|
||||
return JSON.parse(localStorage.getItem('auth')).userType ==
|
||||
rest.userType ? (
|
||||
<Component {...props} />
|
||||
) : (
|
||||
<Redirect
|
||||
to={{ pathname: rest.rejectPath, state: { from: props.location } }}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
authentication: state.authentication
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
login: (email, password) => dispatch(authActions.login(email, password))
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PrivateRoute);
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import styles from './root.less';
|
||||
|
||||
import PrivateRoute from './PrivateRoute';
|
||||
|
||||
import backgroundImage from '../assets/images/mainbg.jpg';
|
||||
|
||||
const Root = props => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* Toast for notifications */}
|
||||
|
||||
<div className={styles.mainCont}>
|
||||
<input
|
||||
className={styles.searchBar}
|
||||
placeholder="Do Everything You Want"
|
||||
/>
|
||||
|
||||
<img className={styles.backgroundImage} src={backgroundImage} />
|
||||
</div>
|
||||
|
||||
<Switch />
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Root;
|
||||
@@ -0,0 +1,38 @@
|
||||
.mainCont {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.searchBar {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: var(--inputPaddingV) var(--inputPaddingH);
|
||||
color: inherit;
|
||||
font-family: inherit;
|
||||
font-size: var(--inputFontSize);
|
||||
font-weight: inherit;
|
||||
line-height: var(--inputLineHeight);
|
||||
border: none;
|
||||
border-radius: 0.4rem;
|
||||
transition: box-shadow var(--transitionDuration);
|
||||
padding: 1em;
|
||||
box-shadow: 0 0 8px #666;
|
||||
width: 400px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
.backgroundImage {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.7;
|
||||
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export const authConstants = {
|
||||
DONOR_LOGIN_REQUEST: 'DONOR_LOGIN_REQUEST',
|
||||
DONOR_LOGIN_SUCCESS: 'DONOR_LOGIN_SUCCESS',
|
||||
DONOR_LOGIN_FAILURE: 'DONOR_LOGIN_FAILURE',
|
||||
|
||||
ORGANIZATION_LOGIN_REQUEST: 'ORGANIZATION_LOGIN_REQUEST',
|
||||
ORGANIZATION_LOGIN_SUCCESS: 'ORGANIZATION_LOGIN_SUCCESS',
|
||||
ORGANIZATION_LOGIN_FAILURE: 'ORGANIZATION_LOGIN_FAILURE',
|
||||
|
||||
LOGOUT: 'USER_LOGOUT',
|
||||
|
||||
USER_RESET_PASSWORD_EMAIL_REQUEST: 'USER_RESET_PASSWORD_EMAIL_REQUEST',
|
||||
USER_RESET_PASSWORD_EMAIL_SUCCESS: 'USER_RESET_PASSWORD_EMAIL_SUCCESS',
|
||||
USER_RESET_PASSWORD_EMAIL_FAILURE: 'USER_RESET_PASSWORD_EMAIL_FAILURE',
|
||||
|
||||
USER_RESET_PASSWORD_REQUEST: 'USER_RESET_PASSWORD_REQUEST',
|
||||
USER_RESET_PASSWORD_SUCCESS: 'USER_RESET_PASSWORD_SUCCESS',
|
||||
USER_RESET_PASSWORD_FAILURE: 'USER_RESET_PASSWORD_FAILURE'
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
export const authHeader = () => {
|
||||
// return authorization header with jwt token
|
||||
let auth = JSON.parse(localStorage.getItem('auth'));
|
||||
|
||||
if (auth) {
|
||||
return { Authorization: 'Bearer ' + auth.token };
|
||||
} else {
|
||||
return { Authorization: 'unauthorize me' };
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
const toJsDate = date => {
|
||||
// Split timestamp into [ Y, M, D, h, m, s ]
|
||||
var dateParts = date.split('-');
|
||||
var utcDate = new Date(
|
||||
dateParts[0],
|
||||
dateParts[1] - 1,
|
||||
dateParts[2].substr(0, 2)
|
||||
);
|
||||
|
||||
var newDate = new Date(
|
||||
utcDate.getTime() + utcDate.getTimezoneOffset() * 60 * 1000
|
||||
);
|
||||
|
||||
var offset = utcDate.getTimezoneOffset() / 60;
|
||||
var hours = utcDate.getHours();
|
||||
|
||||
newDate.setHours(hours - offset);
|
||||
|
||||
return newDate;
|
||||
};
|
||||
|
||||
const dateDiff = (dt1, dt2) => {
|
||||
var diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
||||
diff /= 60 * 60 * 24 * 7 * 4;
|
||||
return Math.abs(Math.round(diff));
|
||||
};
|
||||
|
||||
const getMonthString = month => {
|
||||
const monthNames = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
];
|
||||
return monthNames[month];
|
||||
};
|
||||
|
||||
export const dateFunctions = {
|
||||
toJsDate,
|
||||
dateDiff,
|
||||
getMonthString
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { createBrowserHistory } from 'history';
|
||||
|
||||
export const history = createBrowserHistory();
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from './history.config';
|
||||
export * from './store.config';
|
||||
export * from './auth-header';
|
||||
export * from './dates';
|
||||
export * from './text.js';
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import allReducers from '../reducers';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { persistStore, persistReducer } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
const persistConfig = {
|
||||
key: 'root',
|
||||
storage
|
||||
};
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, allReducers);
|
||||
|
||||
export const storePersistorConfig = () => {
|
||||
let store = createStore(
|
||||
persistedReducer,
|
||||
composeWithDevTools(applyMiddleware(thunk))
|
||||
);
|
||||
|
||||
let persistor = persistStore(store);
|
||||
return { store, persistor };
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
function numberWithCommas(x) {
|
||||
if (x) return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return 0;
|
||||
}
|
||||
|
||||
export const textFunctions = { numberWithCommas };
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
const envVars = require('config');
|
||||
import Root from './components/Root';
|
||||
|
||||
import { storePersistorConfig, history } from './helpers';
|
||||
import { Provider } from 'react-redux';
|
||||
import { PersistGate } from 'redux-persist/integration/react';
|
||||
|
||||
import { Router } from 'react-router-dom';
|
||||
|
||||
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
|
||||
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
primary: { main: '#009688' }, // classic teal
|
||||
submit: { main: '#4caf50' },
|
||||
secondary: { main: '#9E9E9E' }, // greyish text color
|
||||
error: { main: '#F44336' } // red
|
||||
},
|
||||
typography: { useNextVariants: true }
|
||||
});
|
||||
|
||||
var config = storePersistorConfig();
|
||||
|
||||
// TODO: adding back in redux-persist? <PersistGate loading={null} persistor={config.persistor}>
|
||||
// after Provider, before StripeProvider
|
||||
|
||||
ReactDOM.render(
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<Provider store={config.store}>
|
||||
<PersistGate loading={null} persistor={config.persistor}>
|
||||
<Router history={history}>
|
||||
<Root />
|
||||
</Router>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
</MuiThemeProvider>,
|
||||
document.getElementById('app')
|
||||
);
|
||||
|
||||
module.hot.accept();
|
||||
@@ -0,0 +1,16 @@
|
||||
let have_token = JSON.parse(localStorage.getItem('auth')) ? true : false;
|
||||
|
||||
const INITIAL_STATE = {
|
||||
have_token,
|
||||
user: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
signed_up: null
|
||||
};
|
||||
|
||||
export function authentication(state = INITIAL_STATE, action) {
|
||||
switch (action.type) {
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import { authentication } from './auth.reducer';
|
||||
|
||||
/*
|
||||
* We combine all reducers into a single object before updated data is dispatched (sent) to store
|
||||
* Your entire applications state (store) is just whatever gets returned from all your reducers
|
||||
* */
|
||||
|
||||
const allReducers = combineReducers({
|
||||
authentication
|
||||
});
|
||||
|
||||
export default allReducers;
|
||||
@@ -0,0 +1,51 @@
|
||||
import axios from 'axios';
|
||||
const config = require('config');
|
||||
import { authHeader, history } from '../helpers';
|
||||
import { authConstants } from '../constants';
|
||||
|
||||
// Main data service for api calls
|
||||
export const dataService = (
|
||||
dispatch,
|
||||
method,
|
||||
endpoint,
|
||||
data_params = {},
|
||||
data_or_params = true,
|
||||
need_auth = false,
|
||||
headers = {}
|
||||
) => {
|
||||
const requestOptions = {
|
||||
method,
|
||||
url: config.server_url + endpoint,
|
||||
headers
|
||||
};
|
||||
data_or_params
|
||||
? (requestOptions.data = data_params)
|
||||
: (requestOptions.params = data_params);
|
||||
need_auth ? (requestOptions.headers = authHeader()) : {};
|
||||
|
||||
return axios(requestOptions)
|
||||
.then(handleResponse)
|
||||
.catch(handleError(dispatch));
|
||||
};
|
||||
|
||||
const handleResponse = response => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const handleError = dispatch => error => {
|
||||
// logout user if jwt token expired by clearing storage
|
||||
if (error.response.status == 403) {
|
||||
localStorage.removeItem('auth');
|
||||
|
||||
//setting have_token to false, and rest = INITIAL_STATE
|
||||
dispatch({
|
||||
type: authConstants.LOGOUT,
|
||||
payload: {
|
||||
message: 'Auth unsuccessful for call...logging out'
|
||||
}
|
||||
});
|
||||
|
||||
history.push('/login');
|
||||
}
|
||||
throw error.response;
|
||||
};
|
||||
Reference in New Issue
Block a user