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

ENH Display toast notifications #39

Conversation

emteknetnz
Copy link
Member

@emteknetnz emteknetnz commented Mar 15, 2021

Issue #13

@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 2 times, most recently from d539204 to 62479be Compare March 15, 2021 03:37
@emteknetnz emteknetnz changed the title ENH Remove coupling to RememberLoginHash.logout_across_devices ENH Display toast notificaitons, remove coupling to RememberLoginHash.logout_across_devices Mar 15, 2021
@emteknetnz emteknetnz changed the title ENH Display toast notificaitons, remove coupling to RememberLoginHash.logout_across_devices ENH Display toast notifications, remove coupling to RememberLoginHash.logout_across_devices Mar 15, 2021
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 2 times, most recently from b660a0e to 92ee1fe Compare March 16, 2021 00:13
@emteknetnz emteknetnz changed the title ENH Display toast notifications, remove coupling to RememberLoginHash.logout_across_devices ENH Display toast notifications Mar 16, 2021
@emteknetnz emteknetnz changed the base branch from ui-rendering to 1 March 23, 2021 04:33
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 11 times, most recently from 112bfe2 to e7d869b Compare March 25, 2021 04:12
@emteknetnz emteknetnz marked this pull request as ready for review March 25, 2021 04:13
Copy link

@maxime-rainville maxime-rainville left a comment

Choose a reason for hiding this comment

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

Just going back to what I said on the original PR. The Login component is mixing concerns. It should be split in two:

  • one part that handles the UI (That's what should be in the pattern library)
  • one part that handles the communication with the backend, the displaying of toasts, etc

The pattern library is still broken for me. You need to update that to use disconnected Component as well.

client/src/components/LoginSession/LoginSession.js Outdated Show resolved Hide resolved
client/src/components/LoginSession/LoginSession.js Outdated Show resolved Hide resolved
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 6 times, most recently from 1059772 to a4ac5e9 Compare March 29, 2021 02:15
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 7 times, most recently from 3af340e to fa6edd3 Compare March 30, 2021 03:16
@emteknetnz
Copy link
Member Author

@maxime-rainville I've split the components and responded to all the other feedback, good for peer review again

Copy link

@maxime-rainville maxime-rainville left a comment

Choose a reason for hiding this comment

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

Some things that ought to be in the LoginSessionCantianer is still in the LoginSession component.

I haven't reviewed the fine print of the JS tests because the final shape of the JSX components is still fluid.

client/src/components/LoginSession/LoginSession.js Outdated Show resolved Hide resolved
@@ -10,6 +10,14 @@ const props = {
Created: '2021-01-20 00:33:41',
LastAccessed: '2021-03-11 03:47:22',
LogOutEndpoint: 'admin/loginsession/remove',
logout: (beforeRequest, receivedResponse, caughtException) => {

Choose a reason for hiding this comment

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

A better way of passing mock event handler to your pattern libraries stories is to use @storybook/addon-actions.

import { action } from '@storybook/addon-actions';
const logout = action('logout');
logout.toString = () => 'logout';

That will log an entry in the storybook action logger.
image

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not a mock event handler. The logout() function needs to call beforeRequest() and receivedResponse() in order for the LoginSession state and thus text to update

Copy link
Member Author

Choose a reason for hiding this comment

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

No longer required, can use logout: () => 1 just to satisfy the func.required propType

src/Middleware/LoginSessionController.php Show resolved Hide resolved
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch 2 times, most recently from 592f4ec to a621235 Compare April 5, 2021 23:18
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch from a621235 to a3ae336 Compare April 5, 2021 23:48
@emteknetnz emteknetnz force-pushed the pulls/ui-rendering/backend-updates branch from a3ae336 to b749681 Compare April 5, 2021 23:53
Copy link

@maxime-rainville maxime-rainville left a comment

Choose a reason for hiding this comment

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

I took some extra time to refactor <LoginSessionContainer /> to be a functional and update its matching tests. What you did wasn't horrible or anything, but since you struggled with this part, I thought it would be a good learning experience to illustrate how to write test for a functional component following best practices.

I left lots of detailed comments on the commit to explain why I did it that way.

Have a read and let me know if you have any further questions.

Otherwise, the rest of the PR is great. I left some suggestion here and there but nothing that absolutely needs to be addressed.

Comment on lines 22 to +25
if (!await confirm(confirmMessage, { title: confirmTitle, confirmLabel: buttonLabel })) {
return;
}

logOut();
}

if (loading.fadeOutComplete) {
return null;
props.logout();

Choose a reason for hiding this comment

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

To my eye this looks better, but the current code is fine.

        if (await confirm(confirmMessage, { title: confirmTitle, confirmLabel: buttonLabel })) {
          props.logout();
        }

Choose a reason for hiding this comment

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

logout is not define in your propTypes.

{!props.IsCurrent && <Button
color="link"
className="login-session__logout"
onClick={() => attemptLogOut()}

Choose a reason for hiding this comment

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

That's a bit more succinct.

Suggested change
onClick={() => attemptLogOut()}
onClick={attemptLogOut}

</li>)
)}
<ul className="session-manager-field list-unstyled">
{props.loginSessions.map((loginSession) => (

Choose a reason for hiding this comment

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

Suggested change
{props.loginSessions.map((loginSession) => (
{props.loginSessions.map(loginSession => (

@@ -1,22 +1,22 @@
/* global window */
import React from 'react';
import LoginSession from '../LoginSession/LoginSession';
import LoginSessionContainer from '../LoginSession/LoginSessionContainer';

Choose a reason for hiding this comment

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

Suggested change
import LoginSessionContainer from '../LoginSession/LoginSessionContainer';
import LoginSessionContainer from 'components/LoginSession/LoginSessionContainer';

@@ -111,39 +52,37 @@ function LoginSession(props) {
);

return (
<div className={`login-session ${(loading.complete && !loading.failed) ? 'hidden' : ''}`}>
<div className={`login-session ${(props.complete && !props.failed) ? 'hidden' : ''}`}>

Choose a reason for hiding this comment

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

It would be clearer if you use the classnames lib for this kind of string building.

Comment on lines 91 to 96
httpResolve({
error: false,
success: global.success,
message: 'amazing success'
});
await logoutRequest;

Choose a reason for hiding this comment

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

We fake our HTTP response.

Comment on lines 100 to 105
expect(loginSession.props()).toMatchObject({
...sessionData,
complete: true,
failed: false,
submitting: false
});

Choose a reason for hiding this comment

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

We test the end state of our component, once the session has been invalidated.

Comment on lines 107 to 108
expect(props.displayToastSuccess).toBeCalledWith('amazing success');
expect(props.displayToastFailure).not.toBeCalled();

Choose a reason for hiding this comment

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

These mock calls are a bit smarter. We're not only testing the that our mocks have been called, but that they've been called with the expected success message.

expect(props.displayToastSuccess).not.toBeCalled();
});

it('Handles HTTP Request failure', async () => {

Choose a reason for hiding this comment

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

Our initial test was only testing a regular failure. We were not testing a scenario where we had an actual HTTP failure.

submitting: true
});

httpReject();

Choose a reason for hiding this comment

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

Calling the Promise's reject method will cause our catch block to run.

@maxime-rainville
Copy link

@emteknetnz Reverted my commits and split them off into a separate PR creative-commoners#4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants