Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["es2015", "react"],
|
||||
"plugins": ["babel-plugin-transform-class-properties", "transform-object-rest-spread"]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
.DS_STORE
|
||||
node_modules
|
||||
scripts/flow/*/.flowconfig
|
||||
*~
|
||||
*.pyc
|
||||
.grunt
|
||||
_SpecRunner.html
|
||||
__benchmarks__
|
||||
build/
|
||||
remote-repo/
|
||||
coverage/
|
||||
.module-cache
|
||||
fixtures/dom/public/react-dom.js
|
||||
fixtures/dom/public/react.js
|
||||
test/the-files-to-test.generated.js
|
||||
*.log*
|
||||
chrome-user-data
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.idea
|
||||
*.iml
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
dist/bundle.js
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"server_url": "http://localhost:5000",
|
||||
|
||||
"STRIPE_KEY": "pk_test_xPZzi9Y8uYGaHIBprkNe4jDr",
|
||||
"STRIPE_CONNECT_ID": "ca_EeCxc3WY624dMuO6B5JGlizTZfYiqdrp",
|
||||
|
||||
"DEFAULT_LOGO": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultLogo.png",
|
||||
|
||||
"DEFAULT_CHARITY_PROFILE_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultCharityProfilePic.png",
|
||||
"DEFAULT_CHARITY_COVER_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultCharityCoverPic.jpg",
|
||||
|
||||
"DEFAULT_DONOR_PROFILE_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultDonorProfilePic.png",
|
||||
|
||||
"TERMS_PDF": "https://s3-us-west-1.amazonaws.com/charify-assets/terms.pdf",
|
||||
|
||||
"STRIPE_LOGO": "https://s3-us-west-1.amazonaws.com/charify-assets/powered_by_stripe.png"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"server_url": "https://ucharify-api.herokuapp.com",
|
||||
|
||||
"STRIPE_KEY": "pk_live_DsBKJbrrd6vFxI4HzwL5ogAR",
|
||||
"STRIPE_CONNECT_ID": "ca_EeCx0ztPuZRyagXlZgdf4ew2E0Gn8aGU",
|
||||
|
||||
"DEFAULT_LOGO": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultLogo.png",
|
||||
|
||||
"DEFAULT_CHARITY_PROFILE_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultCharityProfilePic.png",
|
||||
"DEFAULT_CHARITY_COVER_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultCharityCoverPic.jpg",
|
||||
|
||||
"DEFAULT_DONOR_PROFILE_PIC": "https://s3-us-west-1.amazonaws.com/charify-assets/defaultDonorProfilePic.png",
|
||||
|
||||
"TERMS_PDF": "https://s3-us-west-1.amazonaws.com/charify-assets/terms.pdf",
|
||||
|
||||
"STRIPE_LOGO": "https://s3-us-west-1.amazonaws.com/charify-assets/powered_by_stripe.png"
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />
|
||||
<link rel="stylesheet" type="text/css" href="/styles.css" />
|
||||
<link rel="icon" href="https://s3-us-west-1.amazonaws.com/charify-assets/defaultLogo.png" type="image/png" />
|
||||
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
|
||||
<title>UCharify</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- Need to change
|
||||
dev: /bundle.js
|
||||
prod: ./bundle.js XXXX discovered that need the dev /bundle.js for history api fallback in prod. Also, it works in AWS, but not opening up the html file local
|
||||
-->
|
||||
<script src="/bundle.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
-> Root
|
||||
-> Home
|
||||
-> LoginForm
|
||||
-> SignupForm
|
||||
-> Main
|
||||
-> Sidebar (always showing)
|
||||
-> Dashboard
|
||||
-> My Grants
|
||||
-> Charities
|
||||
-> My History (past payments list)
|
||||
-> Settings
|
||||
-> (bottom of sidebar) Profile
|
||||
Generated
+7945
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "ucharify",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start:mac": "NODE_ENV=development webpack-dev-server --config ./webpack.config.js --mode development --color --progress",
|
||||
"start:windows": "set NODE_ENV=development& webpack-dev-server --config ./webpack.config.js --mode development --color --progress",
|
||||
"build": "set NODE_ENV=production& webpack --mode production --color --progress"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/talksik/Ucharify.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/talksik/Ucharify/issues"
|
||||
},
|
||||
"homepage": "https://github.com/talksik/Ucharify#readme",
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^3.8.1",
|
||||
"@material-ui/icons": "^3.0.1",
|
||||
"axios": "^0.19.0",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"redux-persist": "^5.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^6.23.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"css-loader": "^2.1.0",
|
||||
"file-loader": "^3.0.1",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^4.1.0",
|
||||
"react-hot-loader": "^4.6.3",
|
||||
"react-redux": "^6.0.0",
|
||||
"redux": "^4.0.1",
|
||||
"redux-devtools-extension": "^2.13.7",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.28.3",
|
||||
"webpack-cli": "^3.2.0",
|
||||
"webpack-dev-server": "^3.1.14"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
const webpack = require('webpack');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: ['react']
|
||||
}
|
||||
}
|
||||
},
|
||||
{ test: /\.css$/, loader: 'style-loader!css-loader' },
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader'
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
modules: true,
|
||||
localIdentName: '[local]___[hash:base64:5]'
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'less-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|svg|jpg|gif)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'images/'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx']
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js',
|
||||
publicPath: '/'
|
||||
},
|
||||
plugins: [new webpack.HotModuleReplacementPlugin()],
|
||||
devServer: {
|
||||
contentBase: './dist',
|
||||
hot: true,
|
||||
port: 8081,
|
||||
historyApiFallback: true
|
||||
},
|
||||
externals: {
|
||||
config: JSON.stringify(
|
||||
process.env.NODE_ENV === 'development'
|
||||
? require('./config.dev.json')
|
||||
: require('./config.prod.json')
|
||||
)
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user