diff --git a/.eslintrc.json b/.eslintrc.json
index 8cb839b77718e11cf14b047af0141eccf647f5c6..17a209196275b907b0409e275efd0576ddae02f3 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,5 +1,6 @@
{
"extends": "airbnb",
+ "parser": "babel-eslint",
"plugins": [
"react",
"jsx-a11y",
diff --git a/package.json b/package.json
index e7a62217c17665ca333eeda568c64cf576ba81ea..f887a5cf7402844e914274cb2776f0b2ef9d515a 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"chalk": "1.1.3",
"connect-history-api-fallback": "1.3.0",
"cross-spawn": "4.0.2",
- "css-loader": "^0.25.0",
+ "css-loader": "0.25.0",
"detect-port": "1.0.1",
"dotenv": "2.0.0",
"eslint": "3.9.1",
@@ -35,19 +35,19 @@
"http-proxy-middleware": "0.17.2",
"jest": "16.0.2",
"json-loader": "0.5.4",
- "node-sass": "^4.1.1",
- "nodemon": "^1.11.0",
+ "node-sass": "4.1.1",
+ "nodemon": "1.11.0",
"object-assign": "4.1.0",
"path-exists": "2.1.0",
"postcss-loader": "1.0.0",
"promise": "7.1.1",
"react-dev-utils": "^0.3.0",
"recursive-readdir": "2.1.0",
- "resolve-url-loader": "^1.6.1",
+ "resolve-url-loader": "1.6.1",
"rimraf": "2.5.4",
- "sass-loader": "^4.1.1",
+ "sass-loader": "4.1.1",
"strip-ansi": "3.0.1",
- "style-loader": "^0.13.1",
+ "style-loader": "0.13.1",
"url-loader": "0.5.7",
"webpack": "1.13.2",
"webpack-dev-server": "1.16.2",
diff --git a/src/components/NavBar/index.js b/src/components/NavBar/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..874bc241c2c7c179b25fdc0ec2282c1b3e792b1c
--- /dev/null
+++ b/src/components/NavBar/index.js
@@ -0,0 +1,53 @@
+import React, { PropTypes } from 'react';
+import { Link } from 'react-router';
+
+import GoogleLogin from '../../containers/GoogleLogin';
+
+export default function NavBar({ SearchBar }) {
+ return (
+
+
+
+
+ {SearchBar ?
:
}
+
+
+
+
+ {localStorage.imageUrl &&

}
+
+
+
+ );
+}
+
+NavBar.propTypes = {
+ SearchBar: PropTypes.func,
+};
diff --git a/src/components/SideBarDetail/index.js b/src/components/SideBarDetail/index.js
index 6530ad2c82319cb53851099772a601b64de79076..c801501d08992dbb9d54990591b2ec602e114956 100644
--- a/src/components/SideBarDetail/index.js
+++ b/src/components/SideBarDetail/index.js
@@ -6,19 +6,17 @@ export default function SideBarDetail({ buildingId }) {
const rootURL = `/buildings/${buildingId}`;
return (
- Home
-
- Overview
+ Overview
Dimensions
- Weather
-
Utilities
-
- Occupancy
-
- Financials
+ {/*
*/}
+ {/* Weather*/}
+ {/*
*/}
+ {/* Occupancy*/}
+ {/*
*/}
+ {/* Financials*/}
);
}
diff --git a/src/containers/BuildingList/index.js b/src/containers/BuildingList/index.js
deleted file mode 100644
index 4b7040723473b3149c406344f3fe9daefba447d8..0000000000000000000000000000000000000000
--- a/src/containers/BuildingList/index.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import React, { Component, PropTypes } from 'react';
-import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux';
-
-import { fetchBuildings, searchTerm } from './actions';
-import BuildingListTable from '../../components/BuildingListTable';
-import './styles.scss';
-import { SearchSVG } from '../../components/bpl';
-
-
-class BuildingList extends Component {
- constructor(props) {
- super(props);
-
- this.state = { term: this.props.buildingList.term };
- this.onInputChange = this.onInputChange.bind(this);
- this.onFormSubmit = this.onFormSubmit.bind(this);
- }
-
- componentDidMount() {
- this.getBuildings();
- }
-
- onInputChange(event) {
- this.setState({ term: event.target.value });
- }
-
- onFormSubmit(event) {
- event.preventDefault();
- this.getBuildings();
- }
-
- getBuildings() {
- this.props.searchTerm(this.state.term);
- this.props.fetchBuildings(this.state.term);
- }
-
- render() {
- return (
-
-
-
-
-
-
-
-
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-BuildingList.propTypes = {
- buildingList: PropTypes.shape({
- buildings: PropTypes.arrayOf(
- PropTypes.shape({
- address: PropTypes.string,
- bbl: PropTypes.number,
- building_id: PropTypes.number,
- lot_id: PropTypes.number,
- borough: PropTypes.string,
- zipcode: PropTypes.number,
- })
- ),
- term: PropTypes.string,
- }),
- fetchBuildings: PropTypes.func,
- searchTerm: PropTypes.func,
-};
-
-function mapDispatchToProps(dispatch) {
- return bindActionCreators({ fetchBuildings, searchTerm }, dispatch);
-}
-
-function mapStateToProps({ buildingList }) {
- return { buildingList };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(BuildingList);
diff --git a/src/containers/BuildingOverview/sagas.js b/src/containers/BuildingOverview/sagas.js
index 2aa9622c449cb1e0b85619f2d3cc87f4f478020c..2a410499591eb17fbb8889f814f018186ce27c88 100644
--- a/src/containers/BuildingOverview/sagas.js
+++ b/src/containers/BuildingOverview/sagas.js
@@ -1,5 +1,6 @@
import { call, put, takeEvery } from 'redux-saga/effects';
import request from '../../utils/request';
+import { getHeaders, turkURL, buildingsURL } from '../../utils/rest_services';
import {
LOAD_BUILDING_DETAIL,
@@ -19,11 +20,6 @@ import {
hitDecisionError,
} from './actions';
-const BUILDING_SERVICE_URL = `${process.env.REACT_APP_BUILDING_SERVICE}`;
-const HEADERS = new Headers({
- 'x-blocpower-app-key': process.env.REACT_APP_KEY,
-});
-
/**
* Detail page request/response handler
*
@@ -33,9 +29,9 @@ function* getBuildingDetail(action) {
const buildingId = action.payload;
const data = yield call(
request,
- `${BUILDING_SERVICE_URL}/building/${buildingId}`, {
+ `${buildingsURL}${buildingId}`, {
method: 'GET',
- headers: HEADERS,
+ headers: getHeaders(),
}
);
@@ -48,9 +44,9 @@ function* getBuildingDetail(action) {
function* loadHit(action) {
const buildingId = action.payload;
- const data = yield call(request, `${BUILDING_SERVICE_URL}/turkhit/${buildingId}`, {
+ const data = yield call(request, `${turkURL}${buildingId}`, {
method: 'GET',
- headers: HEADERS,
+ headers: getHeaders(),
});
if (!data.err) {
@@ -67,9 +63,9 @@ function* loadHit(action) {
*/
function* createHit(action) {
const turkHitFormData = action.payload;
- const data = yield call(request, `${BUILDING_SERVICE_URL}/turkhit/`, {
+ const data = yield call(request, turkURL, {
method: 'POST',
- headers: HEADERS,
+ headers: getHeaders(),
body: JSON.stringify(turkHitFormData),
});
@@ -86,9 +82,9 @@ function* createHit(action) {
* @param {number} action 1 or 0 representing approve or reject
*/
function* approveHit(action) {
- const data = yield call(request, `${BUILDING_SERVICE_URL}/turkhit/${action.buildingId}`, {
+ const data = yield call(request, `${turkURL}${action.buildingId}`, {
method: 'PUT',
- headers: HEADERS,
+ headers: getHeaders(),
body: JSON.stringify({ accept: action.decision }),
});
diff --git a/src/containers/GoogleLogin/actions.js b/src/containers/GoogleLogin/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..65d3316d2c061ed4a6a63fa2d9b98a4d5066b0c7
--- /dev/null
+++ b/src/containers/GoogleLogin/actions.js
@@ -0,0 +1,15 @@
+import { GOOGLE_NAME, GOOGLE_PHOTO } from './constants';
+
+export function addName(name) {
+ return {
+ type: GOOGLE_NAME,
+ payload: name,
+ };
+}
+
+export function addPhoto(photoURL) {
+ return {
+ type: GOOGLE_PHOTO,
+ payload: photoURL,
+ };
+}
diff --git a/src/containers/GoogleLogin/constants.js b/src/containers/GoogleLogin/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b4e33fd161a6a72acafc69df793065d3c2b28c1
--- /dev/null
+++ b/src/containers/GoogleLogin/constants.js
@@ -0,0 +1,2 @@
+export const GOOGLE_NAME = 'ADD_NAME';
+export const GOOGLE_PHOTO = 'GOOGLE_PHOTO';
diff --git a/src/containers/GoogleLogin/index.js b/src/containers/GoogleLogin/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..61b69cf2c6f7001f15750df3c54aab22074dff90
--- /dev/null
+++ b/src/containers/GoogleLogin/index.js
@@ -0,0 +1,242 @@
+import React, { PropTypes, Component } from 'react';
+import { withRouter, routerShape } from 'react-router';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+
+import { addName, addPhoto } from './actions';
+import request from '../../utils/request';
+
+class GoogleLogin extends Component {
+ static onFailure() {
+ // TODO handle error
+ // console.error(err);
+ }
+
+ static onRequest() {
+ // TODO add spinner
+ // console.log('loading...');
+ }
+
+ static checkToken() {
+ return localStorage.gat && new Date() < localStorage.ed;
+ }
+
+ static loggedIn() {
+ return new Promise((resolve, reject) => {
+ if (GoogleLogin.checkToken()) {
+ const gUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo';
+ request(`${gUrl}?access_token=${localStorage.gat}`, { method: 'POST' })
+ .then((res) => {
+ if (res.err) {
+ localStorage.clear();
+ reject(Error('Invalid token'));
+ }
+ resolve(true);
+ });
+ } else {
+ resolve(false);
+ }
+ });
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ disabled: true,
+ loggedIn: false,
+ };
+ }
+
+ componentWillMount() {
+ GoogleLogin.loggedIn().then((res) => {
+ if (res) {
+ this.setState({ loggedIn: true });
+ }
+ }).catch(() => {
+ // TODO handle invalid token error
+ // console.error(err);
+ });
+ }
+
+ componentDidMount() {
+ const { scope, cookiePolicy, loginHint } = this.props;
+ const { name, photoURL } = this.props.googleLogin;
+
+ // Include Google Platform Library
+ // https://developers.google.com/identity/sign-in/web/reference
+ const fjs = document.getElementsByTagName('script')[0];
+ const js = document.createElement('script');
+ js.id = 'google-login';
+ js.src = '//apis.google.com/js/client:platform.js';
+ fjs.parentNode.insertBefore(js, fjs);
+
+ js.onload = () => {
+ const params = {
+ client_id: process.env.REACT_APP_GOOGLE_CLIENT,
+ cookiepolicy: cookiePolicy,
+ login_hint: loginHint,
+ hosted_domain: 'blocpower.org',
+ scope,
+ };
+
+ window.gapi.load('auth2', () => {
+ this.setState({
+ disabled: false,
+ });
+
+ if (!window.gapi.auth2.getAuthInstance()) {
+ window.gapi.auth2.init(params);
+ }
+
+ if (localStorage.gat) {
+ if (new Date() > localStorage.ed) {
+ this.refreshToken();
+ }
+
+ if (name && photoURL) {
+ localStorage.setItem('name', name);
+ localStorage.setItem('imageUrl', photoURL);
+ }
+ }
+ });
+ };
+ }
+
+ onSuccess = (authResponse, user, goBack) => {
+ localStorage.setItem('git', authResponse.id_token);
+ localStorage.setItem('gat', authResponse.access_token);
+ localStorage.setItem('ed', authResponse.expires_at);
+
+ if (user) {
+ localStorage.setItem('name', user.getGivenName());
+ localStorage.setItem('imageUrl', user.getImageUrl());
+ this.props.addName(user.getGivenName());
+ this.props.addPhoto(user.getImageUrl());
+ }
+ this.setState({ loggedIn: true });
+
+ if (goBack) {
+ // TODO go back to previous page
+ this.props.router.push('/');
+ }
+ };
+
+ refreshToken = () => {
+ window.gapi.auth2.getAuthInstance().currentUser.get()
+ .reloadAuthResponse().then((authResponse) => {
+ this.onSuccess(authResponse);
+ });
+ };
+
+ signIn = () => {
+ if (!this.state.disabled) {
+ const auth2 = window.gapi.auth2.getAuthInstance();
+ const { offline, redirectUri, approvalPrompt, prompt } = this.props;
+ const options = {
+ redirect_uri: redirectUri,
+ approval_prompt: approvalPrompt,
+ prompt,
+ };
+ GoogleLogin.onRequest();
+ if (offline) {
+ auth2.grantOfflineAccess(options)
+ .then(
+ res => this.onSuccess(res),
+ err => GoogleLogin.onFailure(err)
+ );
+ } else {
+ auth2.signIn(options)
+ .then((res) => {
+ const basicProfile = res.getBasicProfile();
+ const authResponse = res.getAuthResponse();
+ this.onSuccess(authResponse, basicProfile, true);
+ }, err =>
+ GoogleLogin.onFailure(err)
+ );
+ }
+ }
+ };
+
+ signOut = () => {
+ // TODO prevent logout button from being pressed before gapi.auth2.init
+ // has loaded
+ if (!this.state.disabled) {
+ window.gapi.auth2.getAuthInstance().signOut();
+ localStorage.clear();
+ this.setState({ loggedIn: false });
+ this.props.router.push('/login');
+ }
+ };
+
+ render() {
+ const initialStyle = {
+ color: 'white',
+ height: '40px',
+ marginTop: '15px',
+ };
+
+ const disabledStyle = {
+ opacity: 0.6,
+ };
+
+ const defaultStyle = (() => {
+ if (this.state.disabled) {
+ return { ...initialStyle, disabledStyle };
+ }
+ return initialStyle;
+ })();
+
+ return (
+
+ );
+ }
+}
+
+GoogleLogin.propTypes = {
+ googleLogin: PropTypes.shape({
+ name: PropTypes.string,
+ photoURL: PropTypes.string,
+ }),
+ offline: PropTypes.bool,
+ scope: PropTypes.string,
+ redirectUri: PropTypes.string,
+ cookiePolicy: PropTypes.string,
+ loginHint: PropTypes.string,
+ approvalPrompt: PropTypes.string,
+ prompt: PropTypes.string,
+ router: routerShape,
+ addName: PropTypes.func,
+ addPhoto: PropTypes.func,
+};
+
+GoogleLogin.defaultProps = {
+ offline: false,
+ scope: 'profile email',
+ redirectUri: 'postmessage',
+ cookiePolicy: 'single_host_origin',
+ prompt: '',
+};
+
+function mapStateToProps({ googleLogin }) {
+ return { googleLogin };
+}
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({
+ addName,
+ addPhoto,
+ }, dispatch);
+}
+
+export default withRouter(connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(GoogleLogin));
diff --git a/src/containers/GoogleLogin/reducer.js b/src/containers/GoogleLogin/reducer.js
new file mode 100644
index 0000000000000000000000000000000000000000..32364735c91b6d586362b11cf6300dcdecad55b2
--- /dev/null
+++ b/src/containers/GoogleLogin/reducer.js
@@ -0,0 +1,20 @@
+import { GOOGLE_NAME, GOOGLE_PHOTO } from './constants';
+
+export default function (state = {}, action) {
+ switch (action.type) {
+ case GOOGLE_NAME:
+ return {
+ ...state,
+ name: action.payload,
+ };
+
+ case GOOGLE_PHOTO:
+ return {
+ ...state,
+ photoURL: action.payload,
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/src/containers/BuildingList/actions.js b/src/containers/SearchBar/actions.js
similarity index 56%
rename from src/containers/BuildingList/actions.js
rename to src/containers/SearchBar/actions.js
index 0768281f8540058dca500bfc6b709130e1ad7e44..0fd5e8a0772686e219268e388b7b8d393512a196 100644
--- a/src/containers/BuildingList/actions.js
+++ b/src/containers/SearchBar/actions.js
@@ -1,18 +1,15 @@
import 'whatwg-fetch';
import { FETCH_BUILDINGS, SEARCH_TERM } from './constants';
+import { getHeaders, buildingsURL } from '../../utils/rest_services';
-const ROOT_URL = `${process.env.REACT_APP_BUILDING_SERVICE}/building/`;
-const HEADERS = new Headers({ 'x-blocpower-app-key': process.env.REACT_APP_KEY });
+function fetchBuildings(address) {
+ const url = `${buildingsURL}?address=${address}`;
-const init = {
- method: 'GET',
- headers: HEADERS,
- mode: 'cors',
- cache: 'default',
-};
+ const init = {
+ method: 'GET',
+ headers: getHeaders(),
+ };
-function fetchBuildings(address) {
- const url = `${ROOT_URL}?address=${address}`;
return {
type: FETCH_BUILDINGS,
payload: fetch(url, init).then(response =>
diff --git a/src/containers/BuildingList/constants.js b/src/containers/SearchBar/constants.js
similarity index 100%
rename from src/containers/BuildingList/constants.js
rename to src/containers/SearchBar/constants.js
diff --git a/src/containers/SearchBar/index.js b/src/containers/SearchBar/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5000ed5df83a2548439998ce8e9b5e179b0c0875
--- /dev/null
+++ b/src/containers/SearchBar/index.js
@@ -0,0 +1,84 @@
+import React, { Component, PropTypes } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+
+import { fetchBuildings, searchTerm } from './actions';
+import './styles.scss';
+import { SearchSVG } from '../../components/bpl';
+
+
+class BuildingList extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = { term: this.props.buildingList.term };
+ this.onInputChange = this.onInputChange.bind(this);
+ this.onFormSubmit = this.onFormSubmit.bind(this);
+ }
+
+ componentDidMount() {
+ this.getBuildings();
+ }
+
+ onInputChange(event) {
+ this.setState({ term: event.target.value });
+ }
+
+ onFormSubmit(event) {
+ event.preventDefault();
+ this.getBuildings();
+ }
+
+ getBuildings() {
+ this.props.searchTerm(this.state.term);
+ this.props.fetchBuildings(this.state.term);
+ }
+
+ render() {
+ return (
+
+
+
+

+
+
+
+
+
+ );
+ }
+}
+
+BuildingList.propTypes = {
+ buildingList: PropTypes.shape({
+ term: PropTypes.string,
+ }),
+ fetchBuildings: PropTypes.func,
+ searchTerm: PropTypes.func,
+};
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({ fetchBuildings, searchTerm }, dispatch);
+}
+
+function mapStateToProps({ buildingList }) {
+ return { buildingList };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(BuildingList);
diff --git a/src/containers/BuildingList/reducer.js b/src/containers/SearchBar/reducer.js
similarity index 100%
rename from src/containers/BuildingList/reducer.js
rename to src/containers/SearchBar/reducer.js
diff --git a/src/containers/BuildingList/styles.scss b/src/containers/SearchBar/styles.scss
similarity index 100%
rename from src/containers/BuildingList/styles.scss
rename to src/containers/SearchBar/styles.scss
diff --git a/src/reducers.js b/src/reducers.js
index 82192a2c5c1b8cb9cfca1170b836e3fc470d3cb5..248796275a16072b312dcd8cf15073b220110e3c 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -1,11 +1,13 @@
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
-import BuildingListReducer from './containers/BuildingList/reducer';
+import SearchBarReducer from './containers/SearchBar/reducer';
import BuildingOverviewReducer from './containers/BuildingOverview/reducer';
+import GoogleLoginReducer from './containers/GoogleLogin/reducer';
export default combineReducers({
routing: routerReducer,
- buildingList: BuildingListReducer,
+ buildingList: SearchBarReducer,
buildingDetail: BuildingOverviewReducer,
+ googleLogin: GoogleLoginReducer,
});
diff --git a/src/routes.js b/src/routes.js
index 7e471c18c575a6168cf46f3ff9edfba965dfeccd..ef2a881642aef3532cc2eafddc14f6d29ceb20d6 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -1,26 +1,32 @@
import React from 'react';
import { Route, IndexRoute, IndexRedirect } from 'react-router';
+import { requireAuth, redirectIfLoggedIn } from './utils/auth';
+
+import Login from './screens/Login';
+import NotFound from './screens/NotFound';
+import HomePage from './screens/HomePage';
import BuildingDetail from './screens/BuildingDetail';
-import BuildingList from './containers/BuildingList';
import BuildingOverview from './containers/BuildingOverview';
-import NotFound from './screens/NotFound';
+
import Dummy from './components/dummyComponent';
export default (
-
-
-
-
-
+
+
+
+
+
+
+
-
+
);
diff --git a/src/screens/BuildingDetail/index.js b/src/screens/BuildingDetail/index.js
index 8c3f4d9418af00a3744d8fd001f32965c7a64ad3..620e993e60e5fec0df6333648b3b34c8be76f47d 100644
--- a/src/screens/BuildingDetail/index.js
+++ b/src/screens/BuildingDetail/index.js
@@ -1,10 +1,13 @@
import React, { PropTypes } from 'react';
import SideBarDetail from '../../components/SideBarDetail';
+import NavBar from '../../components/NavBar';
+
export default function BuildingDetail(props) {
return (
-
+
+
diff --git a/src/screens/HomePage/index.js b/src/screens/HomePage/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..31aa3ccc8daa09c20bdefa803f952bd1433449e0
--- /dev/null
+++ b/src/screens/HomePage/index.js
@@ -0,0 +1,37 @@
+import React, { PropTypes } from 'react';
+import { connect } from 'react-redux';
+
+import NavBar from '../../components/NavBar';
+import BuildingList from '../../containers/SearchBar';
+import BuildingListTable from '../../components/BuildingListTable';
+
+function HomePage({ buildingList }) {
+ return (
+
+
+
+
+ );
+}
+
+HomePage.propTypes = {
+ buildingList: PropTypes.shape({
+ buildings: PropTypes.arrayOf(
+ PropTypes.shape({
+ address: PropTypes.string,
+ bbl: PropTypes.number,
+ building_id: PropTypes.number,
+ lot_id: PropTypes.number,
+ borough: PropTypes.string,
+ zipcode: PropTypes.number,
+ })
+ ),
+ term: PropTypes.string,
+ }),
+};
+
+function mapStateToProps({ buildingList }) {
+ return { buildingList };
+}
+
+export default connect(mapStateToProps)(HomePage);
diff --git a/src/screens/Login/index.js b/src/screens/Login/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..edddf946d64346e399b1a481e7e3e453c4df9a07
--- /dev/null
+++ b/src/screens/Login/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import NavBar from '../../components/NavBar';
+
+export default function Login() {
+ return (
+
+
+
Login to get started.
+
+ );
+}
diff --git a/src/utils/auth.js b/src/utils/auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..60a894143512749443932a21630f4cda7b54e147
--- /dev/null
+++ b/src/utils/auth.js
@@ -0,0 +1,20 @@
+import GoogleLogin from '../containers/GoogleLogin';
+
+export function requireAuth(nextState, replace) {
+ // TODO Use GoogleLogin.loggedIn to verify token
+ if (!GoogleLogin.checkToken()) {
+ replace({
+ pathname: '/login',
+ state: { nextPathname: nextState.location.pathname },
+ });
+ }
+}
+
+export function redirectIfLoggedIn(nextState, replace) {
+ if (GoogleLogin.checkToken()) {
+ replace({
+ pathname: '/',
+ state: { nextPathname: nextState.location.pathname },
+ });
+ }
+}
diff --git a/src/utils/rest_services.js b/src/utils/rest_services.js
new file mode 100644
index 0000000000000000000000000000000000000000..04fb1634d10ae80e1b7d7a3cd7f6aff2212b21bb
--- /dev/null
+++ b/src/utils/rest_services.js
@@ -0,0 +1,9 @@
+export function getHeaders() {
+ return new Headers({
+ 'x-blocpower-app-key': process.env.REACT_APP_KEY,
+ 'x-blocpower-google-token': localStorage.git,
+ });
+}
+
+export const buildingsURL = `${process.env.REACT_APP_BUILDING_SERVICE}/building/`;
+export const turkURL = `${process.env.REACT_APP_BUILDING_SERVICE}/turkhit/`;