summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actions/auth.js20
-rw-r--r--src/actions/object-stores.js24
-rw-r--r--src/actions/projects.js24
-rw-r--r--src/actions/users.js19
-rw-r--r--src/api/index.js13
-rw-r--r--src/api/routes/auth.js9
-rw-r--r--src/api/routes/simulations.js73
-rw-r--r--src/api/routes/users.js90
-rw-r--r--src/api/sagas/index.js9
-rw-r--r--src/api/sagas/users.js47
-rw-r--r--src/api/socket.js40
-rw-r--r--src/auth/index.js4
-rw-r--r--src/components/modals/Modal.js1
-rw-r--r--src/components/navigation/Navbar.js5
-rw-r--r--src/components/projects/ProjectAuthList.sass5
-rw-r--r--src/containers/auth/Login.js9
-rw-r--r--src/containers/auth/ProfileName.js16
-rw-r--r--src/containers/projects/VisibleProjectAuthList.js9
-rw-r--r--src/index.js19
-rw-r--r--src/pages/Projects.js21
-rw-r--r--src/reducers/auth.js8
-rw-r--r--src/reducers/index.js6
-rw-r--r--src/reducers/objects.js44
-rw-r--r--src/reducers/projects.js15
-rw-r--r--src/shapes/index.js4
-rw-r--r--src/store/configureStore.js29
26 files changed, 500 insertions, 63 deletions
diff --git a/src/actions/auth.js b/src/actions/auth.js
index f54563ae..2ca6a986 100644
--- a/src/actions/auth.js
+++ b/src/actions/auth.js
@@ -1,15 +1,23 @@
-export const COMPLETE_LOGIN = "COMPLETE_LOGIN";
+export const LOG_IN = "LOG_IN";
+export const LOG_IN_SUCCEEDED = "LOG_IN_SUCCEEDED";
export const LOG_OUT = "LOG_OUT";
-export const completeLogin = (payload) => {
+export function logIn(payload) {
return {
- type: COMPLETE_LOGIN,
+ type: LOG_IN,
payload
};
-};
+}
-export const logOut = () => {
+export function logInSucceeded(payload) {
+ return {
+ type: LOG_IN_SUCCEEDED,
+ payload
+ };
+}
+
+export function logOut() {
return {
type: LOG_OUT
};
-};
+}
diff --git a/src/actions/object-stores.js b/src/actions/object-stores.js
new file mode 100644
index 00000000..08f3f0bd
--- /dev/null
+++ b/src/actions/object-stores.js
@@ -0,0 +1,24 @@
+export const ADD_TO_SIMULATION_STORE = "ADD_TO_SIMULATION_STORE";
+export const ADD_TO_AUTHORIZATION_STORE = "ADD_TO_AUTHORIZATION_STORE";
+export const ADD_TO_USER_STORE = "ADD_TO_USER_STORE";
+
+export function addToSimulationStore(simulation) {
+ return {
+ type: ADD_TO_SIMULATION_STORE,
+ simulation
+ };
+}
+
+export function addToAuthorizationStore(authorization) {
+ return {
+ type: ADD_TO_AUTHORIZATION_STORE,
+ authorization
+ };
+}
+
+export function addToUserStore(user) {
+ return {
+ type: ADD_TO_USER_STORE,
+ user
+ }
+}
diff --git a/src/actions/projects.js b/src/actions/projects.js
index 0ab1f820..efbd15e9 100644
--- a/src/actions/projects.js
+++ b/src/actions/projects.js
@@ -5,42 +5,42 @@ export const ADD_PROJECT = "ADD_PROJECT";
export const DELETE_PROJECT = "DELETE_PROJECT";
export const OPEN_PROJECT = "OPEN_PROJECT";
-export const setAuthVisibilityFilter = (filter) => {
+export function setAuthVisibilityFilter(filter) {
return {
type: SET_AUTH_VISIBILITY_FILTER,
filter: filter
};
-};
+}
-export const openNewProjectModal = () => {
+export function openNewProjectModal() {
return {
type: OPEN_NEW_PROJECT_MODAL
};
-};
+}
-export const closeNewProjectModal = () => {
+export function closeNewProjectModal() {
return {
type: CLOSE_NEW_PROJECT_MODAL
};
-};
+}
-export const addProject = (name) => {
+export function addProject(name) {
return {
type: ADD_PROJECT,
name
};
-};
+}
-export const deleteProject = (id) => {
+export function deleteProject(id) {
return {
type: DELETE_PROJECT,
id
};
-};
+}
-export const openProject = (id) => {
+export function openProject(id) {
return {
type: OPEN_PROJECT,
id
};
-};
+}
diff --git a/src/actions/users.js b/src/actions/users.js
new file mode 100644
index 00000000..093adddd
--- /dev/null
+++ b/src/actions/users.js
@@ -0,0 +1,19 @@
+export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER = "FETCH_AUTHORIZATIONS_OF_CURRENT_USER";
+export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED = "FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED";
+
+export function fetchAuthorizationsOfCurrentUser() {
+ return (dispatch, getState) => {
+ const {auth} = getState();
+ dispatch({
+ type: FETCH_AUTHORIZATIONS_OF_CURRENT_USER,
+ userId: auth.userId
+ });
+ };
+}
+
+export function fetchAuthorizationsOfCurrentUserSucceeded(authorizationsOfCurrentUser) {
+ return {
+ type: FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED,
+ authorizationsOfCurrentUser
+ };
+}
diff --git a/src/api/index.js b/src/api/index.js
index e69de29b..a26422c0 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -0,0 +1,13 @@
+import {sendSocketRequest} from "./socket";
+
+export function sendRequest(request) {
+ return new Promise((resolve, reject) => {
+ sendSocketRequest(request, response => {
+ if (response.status.code === 200) {
+ resolve(response.content);
+ } else {
+ reject(response);
+ }
+ })
+ });
+}
diff --git a/src/api/routes/auth.js b/src/api/routes/auth.js
new file mode 100644
index 00000000..76a39572
--- /dev/null
+++ b/src/api/routes/auth.js
@@ -0,0 +1,9 @@
+export function performTokenSignIn(token) {
+ return new Promise((resolve, reject) => {
+ window["jQuery"].post(
+ "/tokensignin",
+ {idtoken: token},
+ data => resolve(data)
+ )
+ });
+}
diff --git a/src/api/routes/simulations.js b/src/api/routes/simulations.js
new file mode 100644
index 00000000..3c7c748e
--- /dev/null
+++ b/src/api/routes/simulations.js
@@ -0,0 +1,73 @@
+import {sendRequest} from "../index";
+
+export function addSimulation(simulation) {
+ return sendRequest({
+ path: "/simulations",
+ method: "POST",
+ parameters: {
+ body: {
+ simulation
+ },
+ path: {},
+ query: {}
+ }
+ });
+}
+
+export function getSimulation(simulationId) {
+ return sendRequest({
+ path: "/simulations/{simulationId}",
+ method: "GET",
+ parameters: {
+ body: {},
+ path: {
+ simulationId
+ },
+ query: {}
+ }
+ });
+}
+
+export function updateSimulation(simulation) {
+ return sendRequest({
+ path: "/simulations/{simulationId}",
+ method: "PUT",
+ parameters: {
+ body: {
+ simulation
+ },
+ path: {
+ simulationId: simulation.id
+ },
+ query: {}
+ }
+ });
+}
+
+export function deleteSimulation(simulationId) {
+ return sendRequest({
+ path: "/simulations/{simulationId}",
+ method: "DELETE",
+ parameters: {
+ body: {},
+ path: {
+ simulationId
+ },
+ query: {}
+ }
+ });
+}
+
+export function getAuthorizationsBySimulation(simulationId) {
+ return sendRequest({
+ path: "/simulations/{simulationId}/authorizations",
+ method: "GET",
+ parameters: {
+ body: {},
+ path: {
+ simulationId
+ },
+ query: {}
+ }
+ })
+}
diff --git a/src/api/routes/users.js b/src/api/routes/users.js
new file mode 100644
index 00000000..c91e07b2
--- /dev/null
+++ b/src/api/routes/users.js
@@ -0,0 +1,90 @@
+import {sendRequest} from "../index";
+
+export function getUserByEmail(email) {
+ return sendRequest({
+ path: "/users",
+ method: "GET",
+ parameters: {
+ body: {},
+ path: {},
+ query: {
+ email
+ }
+ }
+ });
+}
+
+export function addUser(user) {
+ return sendRequest({
+ path: "/users",
+ method: "POST",
+ parameters: {
+ body: {
+ user: user
+ },
+ path: {},
+ query: {}
+ }
+ });
+}
+
+export function getUser(userId) {
+ return sendRequest({
+ path: "/users/{userId}",
+ method: "GET",
+ parameters: {
+ body: {},
+ path: {
+ userId
+ },
+ query: {}
+ }
+ });
+}
+
+export function updateUser(userId, user) {
+ return sendRequest({
+ path: "/users/{userId}",
+ method: "PUT",
+ parameters: {
+ body: {
+ user: {
+ givenName: user.givenName,
+ familyName: user.familyName
+ }
+ },
+ path: {
+ userId
+ },
+ query: {}
+ }
+ });
+}
+
+export function deleteUser(userId) {
+ return sendRequest({
+ path: "/users/{userId}",
+ method: "DELETE",
+ parameters: {
+ body: {},
+ path: {
+ userId
+ },
+ query: {}
+ }
+ });
+}
+
+export function getAuthorizationsByUser(userId) {
+ return sendRequest({
+ path: "/users/{userId}/authorizations",
+ method: "GET",
+ parameters: {
+ body: {},
+ path: {
+ userId
+ },
+ query: {}
+ }
+ });
+}
diff --git a/src/api/sagas/index.js b/src/api/sagas/index.js
new file mode 100644
index 00000000..ea92533a
--- /dev/null
+++ b/src/api/sagas/index.js
@@ -0,0 +1,9 @@
+import {takeEvery} from "redux-saga/effects";
+import {LOG_IN} from "../../actions/auth";
+import {FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../../actions/users";
+import {fetchAuthorizationsOfCurrentUser, fetchLoggedInUser} from "./users";
+
+export default function* rootSaga() {
+ yield takeEvery(LOG_IN, fetchLoggedInUser);
+ yield takeEvery(FETCH_AUTHORIZATIONS_OF_CURRENT_USER, fetchAuthorizationsOfCurrentUser);
+}
diff --git a/src/api/sagas/users.js b/src/api/sagas/users.js
new file mode 100644
index 00000000..b999b693
--- /dev/null
+++ b/src/api/sagas/users.js
@@ -0,0 +1,47 @@
+import {call, put} from "redux-saga/effects";
+import {logInSucceeded} from "../../actions/auth";
+import {addToAuthorizationStore, addToSimulationStore, addToUserStore} from "../../actions/object-stores";
+import {fetchAuthorizationsOfCurrentUserSucceeded} from "../../actions/users";
+import {performTokenSignIn} from "../routes/auth";
+import {getSimulation} from "../routes/simulations";
+import {addUser, getAuthorizationsByUser, getUser} from "../routes/users";
+
+export function* fetchLoggedInUser(action) {
+ try {
+ const tokenResponse = yield call(performTokenSignIn, action.payload.authToken);
+ let userId = tokenResponse.userId;
+
+ if (tokenResponse.isNewUser) {
+ const newUser = yield call(addUser, action.payload);
+ userId = newUser.id;
+ }
+
+ yield put(logInSucceeded(Object.assign({userId}, action.payload)));
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+export function* fetchAuthorizationsOfCurrentUser(action) {
+ try {
+ const authorizations = yield call(getAuthorizationsByUser, action.userId);
+
+ for (const authorization of authorizations) {
+ yield put(addToAuthorizationStore(authorization));
+
+ const simulation = yield call(getSimulation, authorization.simulationId);
+ yield put(addToSimulationStore(simulation));
+
+ const user = yield call(getUser, authorization.userId);
+ yield put(addToUserStore(user));
+ }
+
+ const authorizationIds = authorizations.map(authorization => (
+ [authorization.userId, authorization.simulationId]
+ ));
+
+ yield put(fetchAuthorizationsOfCurrentUserSucceeded(authorizationIds));
+ } catch (error) {
+ console.log(error);
+ }
+}
diff --git a/src/api/socket.js b/src/api/socket.js
new file mode 100644
index 00000000..86422808
--- /dev/null
+++ b/src/api/socket.js
@@ -0,0 +1,40 @@
+import io from "socket.io-client";
+import {getAuthToken} from "../auth/index";
+
+let socket;
+let requestIdCounter = 0;
+const callbacks = {};
+
+export function setupSocketConnection(onConnect) {
+ socket = io.connect("http://localhost:8081");
+ socket.on("connect", onConnect);
+ socket.on("response", onSocketResponse);
+}
+
+export function sendSocketRequest(request, callback) {
+ if (!socket.connected) {
+ console.error("Attempted to send request over unconnected socket");
+ return;
+ }
+
+ const newId = requestIdCounter++;
+ callbacks[newId] = callback;
+
+ request.id = newId;
+ request.token = getAuthToken();
+
+ if (!request.isRootRoute) {
+ request.path = "/v1" + request.path;
+ }
+
+ socket.emit("request", request);
+
+ console.log("Sent socket request:", request);
+}
+
+function onSocketResponse(json) {
+ const response = JSON.parse(json);
+ console.log("Received socket response:", response);
+ callbacks[response.id](response);
+ delete callbacks[response.id];
+}
diff --git a/src/auth/index.js b/src/auth/index.js
index 5ea24ff9..1bfc10c1 100644
--- a/src/auth/index.js
+++ b/src/auth/index.js
@@ -1,4 +1,4 @@
-import {COMPLETE_LOGIN, LOG_OUT} from "../actions/auth";
+import {LOG_IN_SUCCEEDED, LOG_OUT} from "../actions/auth";
const getAuthObject = () => {
const authItem = localStorage.getItem("auth");
@@ -38,7 +38,7 @@ export const clearAuthLocalStorage = () => {
export const authRedirectMiddleware = store => next => action => {
switch (action.type) {
- case COMPLETE_LOGIN:
+ case LOG_IN_SUCCEEDED:
saveAuthLocalStorage(action.payload);
window.location.href = "/projects";
break;
diff --git a/src/components/modals/Modal.js b/src/components/modals/Modal.js
index e7054fec..c4f10b29 100644
--- a/src/components/modals/Modal.js
+++ b/src/components/modals/Modal.js
@@ -26,7 +26,6 @@ class Modal extends React.Component {
window["$"]("#" + this.id).on("hide.bs.modal", () => {
if (this.visible) {
this.props.onCancel();
- console.log("TEST");
}
});
}
diff --git a/src/components/navigation/Navbar.js b/src/components/navigation/Navbar.js
index bbd08591..96dd93b4 100644
--- a/src/components/navigation/Navbar.js
+++ b/src/components/navigation/Navbar.js
@@ -3,6 +3,7 @@ import FontAwesome from "react-fontawesome";
import Mailto from "react-mailto";
import {Link} from "react-router-dom";
import Logout from "../../containers/auth/Logout";
+import ProfileName from "../../containers/auth/ProfileName";
import "./Navbar.css";
class Navbar extends Component {
@@ -23,7 +24,9 @@ class Navbar extends Component {
headers={{subject: "OpenDC Support"}}>
<FontAwesome name="question-circle" size="lg"/>
</Mailto>
- <Link className="username" title="My Profile" to="/profile">Profile</Link>
+ <Link className="username" title="My Profile" to="/profile">
+ <ProfileName/>
+ </Link>
<Logout/>
</div>
</div>
diff --git a/src/components/projects/ProjectAuthList.sass b/src/components/projects/ProjectAuthList.sass
index 1c65305e..5cdfacaa 100644
--- a/src/components/projects/ProjectAuthList.sass
+++ b/src/components/projects/ProjectAuthList.sass
@@ -48,10 +48,13 @@
span
margin-right: 10px
+.project-row .project-icons
+ text-align: right
+
.project-row .project-icons div
display: inline
position: relative
- top: 5px
+ top: 4px
width: 30px
height: 30px
margin-right: 5px
diff --git a/src/containers/auth/Login.js b/src/containers/auth/Login.js
index 358ea7e9..f1deb33c 100644
--- a/src/containers/auth/Login.js
+++ b/src/containers/auth/Login.js
@@ -2,7 +2,7 @@ import PropTypes from "prop-types";
import React from "react";
import GoogleLogin from "react-google-login";
import {connect} from "react-redux";
-import {completeLogin} from "../../actions/auth";
+import {logIn} from "../../actions/auth";
class LoginContainer extends React.Component {
static propTypes = {
@@ -12,8 +12,11 @@ class LoginContainer extends React.Component {
onAuthResponse(response) {
this.props.onLogin({
+ email: response.getBasicProfile().getEmail(),
+ givenName: response.getBasicProfile().getGivenName(),
+ familyName: response.getBasicProfile().getFamilyName(),
googleId: response.googleId,
- authToken: response.accessToken,
+ authToken: response.getAuthResponse().id_token,
expiresAt: response.getAuthResponse().expires_at
});
}
@@ -44,7 +47,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = dispatch => {
return {
- onLogin: (payload) => dispatch(completeLogin(payload)),
+ onLogin: (payload) => dispatch(logIn(payload)),
};
};
diff --git a/src/containers/auth/ProfileName.js b/src/containers/auth/ProfileName.js
new file mode 100644
index 00000000..27df133c
--- /dev/null
+++ b/src/containers/auth/ProfileName.js
@@ -0,0 +1,16 @@
+import React from "react";
+import {connect} from "react-redux";
+
+const mapStateToProps = state => {
+ return {
+ text: state.auth.givenName + " " + state.auth.familyName
+ };
+};
+
+const SpanElement = ({text}) => <span>{text}</span>;
+
+const ProfileName = connect(
+ mapStateToProps
+)(SpanElement);
+
+export default ProfileName;
diff --git a/src/containers/projects/VisibleProjectAuthList.js b/src/containers/projects/VisibleProjectAuthList.js
index 746380f6..f668711e 100644
--- a/src/containers/projects/VisibleProjectAuthList.js
+++ b/src/containers/projects/VisibleProjectAuthList.js
@@ -15,8 +15,15 @@ const getVisibleProjectAuths = (projectAuths, filter) => {
};
const mapStateToProps = state => {
+ const denormalizedAuthorizations = state.authorizationsOfCurrentUser.map(authorizationIds => {
+ const authorization = Object.assign({}, state.objects.authorizations[authorizationIds]);
+ authorization.simulation = state.objects.simulations[authorization.simulationId];
+ authorization.user = state.objects.users[authorization.userId];
+ return authorization;
+ });
+
return {
- authorizations: getVisibleProjectAuths(state.authorizations, state.authVisibilityFilter)
+ authorizations: getVisibleProjectAuths(denormalizedAuthorizations, state.authVisibilityFilter)
};
};
diff --git a/src/index.js b/src/index.js
index 1176224e..8fa45ebf 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,18 +1,21 @@
import React from "react";
import ReactDOM from "react-dom";
import {Provider} from "react-redux";
+import {setupSocketConnection} from "./api/socket";
import "./index.css";
import registerServiceWorker from "./registerServiceWorker";
import Routes from "./routes";
import configureStore from "./store/configureStore";
-const store = configureStore();
+setupSocketConnection(() => {
+ const store = configureStore();
-ReactDOM.render(
- <Provider store={store}>
- <Routes/>
- </Provider>,
- document.getElementById('root')
-);
+ ReactDOM.render(
+ <Provider store={store}>
+ <Routes/>
+ </Provider>,
+ document.getElementById('root')
+ );
-registerServiceWorker();
+ registerServiceWorker();
+});
diff --git a/src/pages/Projects.js b/src/pages/Projects.js
index 69a28f9d..06655768 100644
--- a/src/pages/Projects.js
+++ b/src/pages/Projects.js
@@ -1,6 +1,7 @@
import React from 'react';
import {connect} from "react-redux";
import {addProject, openNewProjectModal} from "../actions/projects";
+import {fetchAuthorizationsOfCurrentUser} from "../actions/users";
import Navbar from "../components/navigation/Navbar";
import ProjectFilterPanel from "../components/projects/FilterPanel";
import NewProjectButton from "../components/projects/NewProjectButton";
@@ -9,9 +10,9 @@ import NewProjectModal from "../containers/projects/NewProjectModal";
import VisibleProjectList from "../containers/projects/VisibleProjectAuthList";
import "./Projects.css";
-class Projects extends React.Component {
+class ProjectsContainer extends React.Component {
componentDidMount() {
- // TODO perform initial fetch
+ this.props.fetchAuthorizationsOfCurrentUser();
}
onInputSubmission(text) {
@@ -25,7 +26,7 @@ class Projects extends React.Component {
<div className="container project-page-container full-height">
<ProjectFilterPanel/>
<VisibleProjectList/>
- <NewProjectButton onClick={() => {this.props.dispatch(openNewProjectModal())}}/>
+ <NewProjectButton onClick={() => {this.props.openNewProjectModal()}}/>
</div>
<NewProjectModal/>
<Login visible={false}/>
@@ -34,4 +35,16 @@ class Projects extends React.Component {
}
}
-export default connect()(Projects);
+const mapDispatchToProps = dispatch => {
+ return {
+ fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()),
+ openNewProjectModal: () => dispatch(openNewProjectModal()),
+ };
+};
+
+const Projects = connect(
+ undefined,
+ mapDispatchToProps
+)(ProjectsContainer);
+
+export default Projects;
diff --git a/src/reducers/auth.js b/src/reducers/auth.js
index 0d01b300..a65b3b3e 100644
--- a/src/reducers/auth.js
+++ b/src/reducers/auth.js
@@ -1,12 +1,12 @@
-import {COMPLETE_LOGIN, LOG_OUT} from "../actions/auth";
+import {LOG_IN_SUCCEEDED, LOG_OUT} from "../actions/auth";
-export const auth = (state = {}, action) => {
+export function auth(state = {}, action) {
switch (action.type) {
- case COMPLETE_LOGIN:
+ case LOG_IN_SUCCEEDED:
return action.payload;
case LOG_OUT:
return {};
default:
return state;
}
-};
+}
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 4e35f6e8..71379a6f 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,10 +1,12 @@
import {combineReducers} from "redux";
import {auth} from "./auth";
-import {authorizations, authVisibilityFilter, newProjectModalVisible} from "./projects";
+import {objects} from "./objects";
+import {authorizationsOfCurrentUser, authVisibilityFilter, newProjectModalVisible} from "./projects";
const rootReducer = combineReducers({
auth,
- authorizations,
+ objects,
+ authorizationsOfCurrentUser,
newProjectModalVisible,
authVisibilityFilter,
});
diff --git a/src/reducers/objects.js b/src/reducers/objects.js
new file mode 100644
index 00000000..69e68ca7
--- /dev/null
+++ b/src/reducers/objects.js
@@ -0,0 +1,44 @@
+import {combineReducers} from "redux";
+import {ADD_TO_AUTHORIZATION_STORE, ADD_TO_SIMULATION_STORE, ADD_TO_USER_STORE} from "../actions/object-stores";
+
+export const objects = combineReducers({
+ simulations,
+ authorizations,
+ users,
+});
+
+function simulations(state = {}, action) {
+ switch (action.type) {
+ case ADD_TO_SIMULATION_STORE:
+ return Object.assign(
+ state,
+ {[action.simulation.id]: action.simulation}
+ );
+ default:
+ return state;
+ }
+}
+
+function authorizations(state = {}, action) {
+ switch (action.type) {
+ case ADD_TO_AUTHORIZATION_STORE:
+ return Object.assign(
+ state,
+ {[[action.authorization.userId, action.authorization.simulationId]]: action.authorization}
+ );
+ default:
+ return state;
+ }
+}
+
+function users(state = {}, action) {
+ switch (action.type) {
+ case ADD_TO_USER_STORE:
+ return Object.assign(
+ state,
+ {[action.user.id]: action.user}
+ );
+ default:
+ return state;
+ }
+}
diff --git a/src/reducers/projects.js b/src/reducers/projects.js
index b6450fd7..ba3c792d 100644
--- a/src/reducers/projects.js
+++ b/src/reducers/projects.js
@@ -5,9 +5,12 @@ import {
OPEN_NEW_PROJECT_MODAL,
SET_AUTH_VISIBILITY_FILTER
} from "../actions/projects";
+import {FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED} from "../actions/users";
-export const authorizations = (state = [], action) => {
+export function authorizationsOfCurrentUser(state = [], action) {
switch (action.type) {
+ case FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED:
+ return action.authorizationsOfCurrentUser;
case ADD_PROJECT:
return [
...state,
@@ -22,9 +25,9 @@ export const authorizations = (state = [], action) => {
default:
return state;
}
-};
+}
-export const newProjectModalVisible = (state = false, action) => {
+export function newProjectModalVisible(state = false, action) {
switch (action.type) {
case OPEN_NEW_PROJECT_MODAL:
return true;
@@ -33,13 +36,13 @@ export const newProjectModalVisible = (state = false, action) => {
default:
return state;
}
-};
+}
-export const authVisibilityFilter = (state = "SHOW_ALL", action) => {
+export function authVisibilityFilter(state = "SHOW_ALL", action) {
switch (action.type) {
case SET_AUTH_VISIBILITY_FILTER:
return action.filter;
default:
return state;
}
-};
+}
diff --git a/src/shapes/index.js b/src/shapes/index.js
index 72153f54..770e8d76 100644
--- a/src/shapes/index.js
+++ b/src/shapes/index.js
@@ -4,7 +4,7 @@ const Shapes = {};
Shapes.User = PropTypes.shape({
id: PropTypes.number.isRequired,
- googleId: PropTypes.number.isRequired,
+ googleId: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
givenName: PropTypes.string.isRequired,
familyName: PropTypes.string.isRequired,
@@ -25,4 +25,4 @@ Shapes.Authorization = PropTypes.shape({
authorizationLevel: PropTypes.string.isRequired,
});
-export default Shapes; \ No newline at end of file
+export default Shapes;
diff --git a/src/store/configureStore.js b/src/store/configureStore.js
index ec932cf7..ecd804a2 100644
--- a/src/store/configureStore.js
+++ b/src/store/configureStore.js
@@ -1,20 +1,29 @@
import {applyMiddleware, compose, createStore} from "redux";
import persistState from "redux-localstorage";
import {createLogger} from "redux-logger";
+import createSagaMiddleware from 'redux-saga';
+import thunk from "redux-thunk";
+import rootSaga from "../api/sagas/index";
import {authRedirectMiddleware} from "../auth/index";
import rootReducer from "../reducers/index";
+const sagaMiddleware = createSagaMiddleware();
const logger = createLogger();
-const configureStore = () => createStore(
- rootReducer,
- compose(
- persistState("auth"),
- applyMiddleware(
- logger,
- authRedirectMiddleware,
+export default function configureStore() {
+ const store = createStore(
+ rootReducer,
+ compose(
+ persistState("auth"),
+ applyMiddleware(
+ logger,
+ thunk,
+ sagaMiddleware,
+ authRedirectMiddleware,
+ )
)
- )
-);
+ );
+ sagaMiddleware.run(rootSaga);
-export default configureStore;
+ return store;
+}