Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move logic to redux #507

Closed
wants to merge 28 commits into from
Closed

Conversation

mradenovic
Copy link
Collaborator

@mradenovic mradenovic commented Jan 31, 2021

Pros:

  • Strongly recomended
  • Easier testing
  • Easier mocking of libraries and use of storybook
  • More flexible notification handling

Resolves #517
Resolves #518

@daltonfury42
Copy link
Collaborator

Wonderful, I always wanted to move to using thunk and actions, but could never get it right. Redux toolkit way of doing this was a bit confusing to me. Let me study your PR.

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
@mradenovic
Copy link
Collaborator Author

redux-toolkit was confusing for me too. Actually, it is very elegant. What makes things complicated is that `auth0' works only in components.

My idea is to pass auth0 to any async thunk. To suppress serializableCheck warnings, it must be ignored. Convention to make things clear would be:

const someAsyncAction = createAsyncThunk('action/requestStatus', async (arg) => {
  const { auth, payload } = arg;
  const { id } = payload
  const response = await doSomeethingById(auth, id);
  return response;
});

/**
 * Dispatching async actions
 *
 * When dispatching async actions with auth0,
 * wrap the `payload` within `arg` parameter of the `payloadCreator` function.
 *
 * Example:
 */

const auth = useAuth()
const payload = { id: '0' }
const arg = {
  auth: auth,
  payload: payload
}
dispatch(someAsyncAction(arg))

@maaverik
Copy link
Collaborator

I've never worked with thunk, so I'll hold off on reviewing till I get a good understanding of it. But essentially, the idea here is to abstract away both the authentication and API calls to reducers, right @mradenovic ?

@mradenovic
Copy link
Collaborator Author

I've never worked with thunk, so I'll hold off on reviewing till I get a good understanding of it. But essentially, the idea here is to abstract away both the authentication and API calls to reducers, right @mradenovic ?

Yes. It is easier for maintenance, and if decided to change something in the logic (i.e. replace auth0 with Firebase auth ), it can be done in one place.

simplq/src/components/pages/Home/MyQueues.jsx Outdated Show resolved Hide resolved
simplq/src/store/queuesSlice.js Outdated Show resolved Hide resolved
@daltonfury42
Copy link
Collaborator

We should centralise this into redux. Our components would then look so much more clean. Can you also add one more where there will be a payload?

@mradenovic
Copy link
Collaborator Author

We should centralise this into redux. Our components would then look so much more clean. Can you also add one more where there will be a payload?

I am working on next itteration. I managed to completely move auth to async thunk with hook. It has some quirks though. I also discovered some bug. It looks like current delete functionality doesn't update myQueues. It worked before #504 was applied, but that is because that bug was constantly fetchin data from the server.

@daltonfury42
Copy link
Collaborator

daltonfury42 commented Feb 1, 2021

I managed to completely move auth to async thunk with hook

Interesting, how did you do that? I did find somewhere a custom middleware+local storage for token solution, but didn't like it.

Yes, I also noticed this. As a side effect of #504 it was getting updated before. But this issue would go away when we move to redux and have the delete queue action that would update the global store, I guess?

@mradenovic
Copy link
Collaborator Author

One more curriosity here: The server does not check if user is authenticated. If I send a request from client as anonyous, I get all the queues (300+). Than I can delete any of the queues even if I am not the owner.

// api/axios-alt.js

// to test, change line 16 declaration

  const accessToken = false //auth.isAuthenticated
    ? await auth.getAccessTokenSilently({ audience: 'https://devbackend.simplq.me/v1' })
    : 'anonymous';

@daltonfury42
Copy link
Collaborator

Yes, this in in my list. I am thinking of doing this:

When a user is not logged in, we create a UUID and store it in the local storage. Instead of Bearer anonymous, we would send this ID in case of unauthenticated users. This ID would be used to identify the resources created by users who have not signed in.

Then post sign in, we call a backend API that would transfer ownerships from this ID to the signed in user, if such an ID exists in local storage.

What do you think? Ideally there should be some anonymous login, which would generate short lived tokens, but this setup looks good enough for me.

@mradenovic
Copy link
Collaborator Author

What do you think? Ideally there should be some anonymous login, which would generate short lived tokens, but this setup looks good enough for me.

I don't know much about handling users on the backend. I usually use ready made solutions when I need one 🤣 Firebase auth has all of that solved and that was what I used in the past for prototyping.

@daltonfury42 daltonfury42 mentioned this pull request Feb 2, 2021
const { isAuthenticated } = useAuth0();
const dispatch = useDispatch();
const queues = useSelector(selectQueues);
const fetchQueues = useCallback(useFetchQueues(), []);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use useCallback() only if the action is going to be dispatched in useEffect().

@mradenovic mradenovic marked this pull request as ready for review February 2, 2021 21:30
@mradenovic mradenovic marked this pull request as draft February 3, 2021 12:23
Copy link
Collaborator

@daltonfury42 daltonfury42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still understanding the change, thanks!

simplq/src/api/auth.js Outdated Show resolved Hide resolved
simplq/src/api/requestFactory/index.js Outdated Show resolved Hide resolved
simplq/src/api/requestFactory/queue.js Outdated Show resolved Hide resolved
simplq/src/components/pages/Home/MyQueues.jsx Outdated Show resolved Hide resolved
simplq/src/components/pages/Home/MyQueues.jsx Outdated Show resolved Hide resolved
simplq/src/components/pages/Status/QueueDetails.jsx Outdated Show resolved Hide resolved
simplq/src/store/appSlice.js Outdated Show resolved Hide resolved
simplq/src/store/queues/queuesSlice.js Show resolved Hide resolved
simplq/src/store/queues/queuesAsyncActions.js Outdated Show resolved Hide resolved
* const fetchQueues = useFetchQueues()
*/
const useFetchQueues = () => {
const auth = useAuth();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is pretty smart ✌️

Comment on lines 23 to 25
if (!auth || !auth.isAuthenticated) {
return { queues: [] };
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need !auth here? We should also add auth. isLoading here, I think.

Also leave this comment:

// TODO: Remove `!auth.isAuthenticated` after resolving https://github.com/SimplQ/simplQ-frontend/issues/477 

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely do not need !auth, it is guaranteed to be there by the hook. There was a lot of copy-paste happening so there will be a lot to remove 😊 I haven't explored what exactly should happen when not authenticated, so that should be implemented later.


* @see ./queuesSlice
*
* @see https://redux-toolkit.js.org/api/createAsyncThunk#return-value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to read this 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daltonfury42 where can I find deployed PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I didn't understand the last one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mradenovic We generate temporary preview deployments. This can be triggered by putting any label on the PR (You can see a sample here)

But due to some security limitations, this is not possible on PRs from forks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll push to repo to see how it works.

Copy link
Collaborator

@daltonfury42 daltonfury42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't wait to merge this. It will be massive. 💪

For me weekend is here, I will migrate remaining components as soon as this PR goes in.

simplq/src/api/requestFactory/queue.js Show resolved Hide resolved
@@ -0,0 +1,26 @@
import { createSlice } from '@reduxjs/toolkit';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should rename the file to userQueusSlice, and correspondingly make changes in lines 4,5,24 and 26.. and also outside usages.

Comment on lines +30 to +31
history.push(`/pageNotFound/queueName=${queueName}`);
return rejectWithValue({ message: `Queue ${queueName} does not exist, try again...` });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

simplq/src/store/asyncActions/deleteQueue.js Show resolved Hide resolved
Comment on lines +24 to +26
loading={!queueStatus}
>
<QueueStats queueStatus={queueStatusResponse} />
<QueueStats queueStatus={queueStatus} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work, we would have to check for empty object. 🤔

An isLoading flag might be better, as you were implementing before?

These kind of glitches we can fix in a follow up PR as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All pending', fulfilled, and rejected` should be handled in reducers. It can be done later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code looks much cleaner now

@mradenovic
Copy link
Collaborator Author

I suggest we continue the conversation at #522.

@mradenovic mradenovic closed this Feb 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor Join page component Refactor QueueDetails
4 participants