Skip to content

Commit

Permalink
Move logic to redux
Browse files Browse the repository at this point in the history
Pros:
- [Strongly recomended](https://redux.js.org/style-guide/style-guide#put-as-much-logic-as-possible-in-reducers)
- Easier testing
- Easier mocking of libraries and use of storybook
- More flexible notification handling
  • Loading branch information
mradenovic committed Jan 31, 2021
1 parent ac03b96 commit 5784fd3
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 2 deletions.
35 changes: 35 additions & 0 deletions simplq/src/api/axios-alt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import axios from 'axios';
// TODO: Read base url from env
const baseURL = 'https://devbackend.simplq.me/v1';

/**
* Async function for for sending request with Auth0
*
* It combines usRequest and maqeRequest. Since
* @auth0/auth0-react can work only wthin a component,
* the whole auth object created with useAuth() must be
* passed as parameter.
*
* @param {Object} auth object returned by useAuth() from @auth0/auth0-react.
* @param {Object} payload object used in action creators in redux-toolkit.
*/
const makeAuthedRequest = async (auth, request) => {
// TODO: Is "audience" == "bseURL"? Read from env or use baseURL
const accessToken = auth.isAuthenticated
? await auth.getAccessTokenSilently({ audience: 'https://devbackend.simplq.me/v1' })
: 'anonymous';

return axios({
baseURL,
...request,
headers: {
...request.headers,
// Add the Authorization header to the existing headers
Authorization: `Bearer ${accessToken}`,
},
}).then((response) => {
return response.data;
});
};

export default makeAuthedRequest;
18 changes: 17 additions & 1 deletion simplq/src/components/pages/Home/MyQueues.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import DeleteIcon from '@material-ui/icons/Delete';
import IconButton from '@material-ui/core/IconButton';
import { useHistory } from 'react-router';
import { useAuth0 } from '@auth0/auth0-react';
import { fetchQueues } from 'store/queuesSlice';
import { useDispatch, useSelector } from 'react-redux';
import styles from './home.module.scss';
import { QueueRequestFactory } from '../../../api/requestFactory';
import useRequest from '../../../api/useRequest';
Expand All @@ -12,12 +14,26 @@ export default () => {
const { requestMaker } = useRequest();
const [myQueues, setMyQueues] = useState([]);
const { isAuthenticated } = useAuth0();
const auth = useAuth0();
const dispatch = useDispatch();
const queues = useSelector((state) => state.queues);

useEffect(() => {
if (isAuthenticated)
requestMaker(QueueRequestFactory.getMyQueues()).then((resp) => setMyQueues(resp.queues));
}, [requestMaker]);

useEffect(() => {
if (isAuthenticated) {
const arg = {
auth,
// example payload for async thunk
payload: { someKey: 'Some value' },
};
dispatch(fetchQueues(arg));
}
}, []);

if (!isAuthenticated) {
return null;
}
Expand All @@ -34,7 +50,7 @@ export default () => {
? "Looks like you don't have any active queues. Start by creating one..."
: 'What would you like to do today? Here are your active queues:'}
</p>
{myQueues.map((queue) => {
{queues.map((queue) => {
const handler = () => history.push(`/queue/${queue.queueId}`);
return (
<div
Expand Down
12 changes: 12 additions & 0 deletions simplq/src/store/appSlice.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import { createSlice } from '@reduxjs/toolkit';
import { fetchQueues } from 'store/queuesSlice';

const appSlice = createSlice({
name: 'appSlice',
Expand All @@ -19,6 +20,17 @@ const appSlice = createSlice({
state.notificationPermission = action.payload;
},
},
extraReducers: {
[fetchQueues.pending]: (state, action) => {
state.infoText = `Loading queues for ${action.meta.arg.auth.user.name}...`;
},
[fetchQueues.rejected]: (state, action) => {
state.errorText = action.error.message;
},
[fetchQueues.fulfilled]: (state, action) => {
state.infoText = `Number of queues fetched: ${action.payload.queues.length}`;
},
},
});

export const {
Expand Down
10 changes: 9 additions & 1 deletion simplq/src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import { combineReducers, configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import queuesSlice from 'store/queuesSlice';
import appReducer from './appSlice';

export const rootReducer = combineReducers({
appReducer,
queues: queuesSlice,
});

export const store = configureStore({
reducer: rootReducer,
middleware: getDefaultMiddleware({
serializableCheck: {
// Ignore auth in async thunks
ignoredActionPaths: ['meta.arg.auth'],
},
}),
});
31 changes: 31 additions & 0 deletions simplq/src/store/queuesSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable no-param-reassign */

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { QueueRequestFactory } from 'api/requestFactory';
import makeAuthedRequest from 'api/axios-alt';

const fetchQueues = createAsyncThunk('queues/requestStatus', async (arg) => {
const { auth } = arg;
const authedRequest = makeAuthedRequest(auth, QueueRequestFactory.getMyQueues());
const response = await authedRequest;
return response;
});

const queuesSlice = createSlice({
name: 'queues',
initialState: [],
// No reducers for now
reducers: {},
extraReducers: {
// handle fulfiled request
[fetchQueues.fulfilled]: (state, action) => {
return action.payload.queues;
},
},
});

export const { queuesFetched } = queuesSlice.actions;

export { fetchQueues };

export default queuesSlice.reducer;

0 comments on commit 5784fd3

Please sign in to comment.