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