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

lib-user: add group manage modal with group update inputs, group delete, and members management #6100

Merged
merged 35 commits into from
Jun 10, 2024

Conversation

mcbouslog
Copy link
Contributor

@mcbouslog mcbouslog commented May 21, 2024

Package

  • lib-user

Describe your changes

  • remove temporary group Edit and Delete components
  • move GroupForm and GroupModal to shared components
  • refactor GroupForm for editing a group, styling per Figma
  • create component to list memberships
  • create component for membership item in memberships list

How to Review

Helpful explanations that will make your reviewer happy:

Checklist

PR Creator - Please cater the checklist to fit the review needed for your code changes.
PR Reviewer - Use the checklist during your review. Each point should be checkmarked or discussed before PR approval.

General

  • Tests are passing locally and on Github
  • Documentation is up to date and changelog has been updated if appropriate
  • You can yarn panic && yarn bootstrap or docker-compose up --build and FEM works as expected
  • FEM works in all major desktop browsers: Firefox, Chrome, Edge, Safari (Use Browserstack account as needed)
  • FEM works in a mobile browser

General UX

Example Staging Project: i-fancy-cats

New Feature

  • The PR creator has listed user actions to use when testing the new feature
  • Unit tests are included for the new feature
  • A storybook story has been created or updated
    • Example of SlideTutorial component with docgen comments, and its story

@mcbouslog mcbouslog changed the base branch from master to lib-user_header-items-refactor May 21, 2024 17:46
Base automatically changed from lib-user_header-items-refactor to master May 23, 2024 15:49
@coveralls
Copy link

coveralls commented May 23, 2024

Coverage Status

coverage: 79.133% (-0.2%) from 79.323%
when pulling 7eeb5bb on lib-user_manage-group
into 9a7a630 on master.

@mcbouslog mcbouslog self-assigned this May 24, 2024
@mcbouslog mcbouslog changed the title [DRAFT] lib-user: add group manage modal with group update inputs, group delete, and members management lib-user: add group manage modal with group update inputs, group delete, and members management May 24, 2024
@mcbouslog mcbouslog marked this pull request as ready for review May 24, 2024 23:20
@mcbouslog mcbouslog requested a review from a team May 28, 2024 14:33
Copy link
Contributor

@goplayoutside3 goplayoutside3 left a comment

Choose a reason for hiding this comment

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

Code read is generally looking good, and the storybooks too. Could you join this group, so I have a test group where I'm admin and multiple members? https://www.zooniverse.org/groups/1326995?join_token=0e834515f7390aa4 (staging)

Noting that the GroupModal + GroupForm is relatively tall, so it takes up the majority of my viewport height which risks hiding the Save button. The figma design for managing a group does not include the extra vertical space and borders that exist in this PR. Is the figma link the correct reference?

I've left several more suggestions and comments below...

Comment on lines 37 to 54
async function handleDeleteMembership({ membershipId }) {
const deleteMembershipResponse = await deletePanoptesMembership({ membershipId })
if (deleteMembershipResponse.ok) {
const updatedMemberships = memberships.filter(membership => membership.id !== membershipId)
setMemberships(updatedMemberships)
}
}

async function handleUpdateMembership({ membershipId, data }) {
const updateMembershipResponse = await updatePanoptesMembership({ membershipId, data })
if (updateMembershipResponse.ok) {
const updatedMemberships = memberships.map(membership => {
if (membership.id === membershipId) {
membership.roles = data.roles
}
return membership
})
setMemberships(updatedMemberships)
Copy link
Contributor

Choose a reason for hiding this comment

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

This sequence is an "optimistic UI" pattern where you're assuming the deletePanoptesMembership or updatePanoptesMembership request to panoptes is successful, and therefore don't need to call usePanoptesMemberships again. Just wondering if you thought about the pros/cons of triggering usePanoptesMemberships upon delete or update, and then simply using data: membershipsData as source of "state" for this component rather than useState.

(I don't have a great answer, mainly just for my own understanding if an "optimistic UI" pattern is the easiest for this component, that's okay!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not exactly sure how I'd implement it using membershipsData as state, as I think I'd have to add a param to the usePanoptesMemberships hook so it knew to update? Open to suggestion, but this was what felt easiest initially. Definitely have to refactor for sad paths in a few places, maybe worth creating a dedicated card/issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought about this concept a bit more, and I think it's worth looking into SWR's mutations. This youtube tutorial is also a great example of SWR data fetching + mutation in practice.

The majority of data handling in the user groups and stats pages simply fetches data from panoptes, which you've implemented with SWR hooks. This works well because the fetched/cached data can't be updated on the user groups or stats pages (for instance, stats are modified on classify pages or a user's display name is updated on their profile settings page). However, group memberships is the major feature that requires modifying data in panoptes while also updating the currently-viewed UI on the fly.

SWR provides hook useSWRMutation for cases where you need to POST, PUT, or DEL to the backend, yet continue to use the data returned from a GET hook like usePanoptesMemberships in MembersListContainer. useSWRMutation is an optimistic UI pattern, but without creating a separate useState variable.

The second reason I think it's worth looking into SWR mutations is to handle the forced page refresh I commented on. Forcing a page refresh after modifying group membership data feels like an anti-pattern in a React application where components in the UI should re-render when passed new data props. GroupStatsContainer also utilizes usePanoptesMemberships and passes membershipsData to GroupStats. With SWR mutations you could rely on membershipsData to update after a mutation and cause a GroupStats re-render without a total page refresh.

Please let me know your thoughts! And if you'd like to separate changes to membership data handling into another PR or continue on this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The useSWRMutation SWR hook noted sounds great to me, certainly preferable. My only hesitation is adding to this PR's changes, but if that's ok with you then it's ok with me and I'd like to try refactoring accordingly.

Other user/group stats PRs aren't dependent on this PR so it won't hold anything up if this gets additional work.

Copy link
Contributor

Choose a reason for hiding this comment

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

Feel free to add to this PR if easiest in the flow of features for lib-user! You could also create a PR requesting to merge into this one with isolated changes for data mutation. Happy to review either way.

@goplayoutside3
Copy link
Contributor

Continuing to review this! One more important check though -

I see both of your accounts joined https://local.zooniverse.org:3000/groups/1326995 (staging), so I tested out the group manage model and I'm confused about whether group members are related to Top Contributors. I removed one of your accounts from the group, so the manage modal looks like this:
Screenshot 2024-05-31 at 9 51 23 AM

But the account I removed still shows up on Top Contributors like this:
Screenshot 2024-05-31 at 9 51 04 AM

Is that expected? The Top Contributors is every account that's ever classified while in the group, even if they're no longer in the group?

@mcbouslog
Copy link
Contributor Author

@goplayoutside3 that's a good question. I think that's expected, but I'm going to tag @yuenmichelle1 for the ERAS perspective on group members included/excluded in a response for request that includes 'top_contributors'.

@mcbouslog
Copy link
Contributor Author

mcbouslog commented Jun 7, 2024

Regarding active/inactive members and stats inclusion, per related Slack thread:

  • when a group member classifies their stats will persist as part of the group stats regardless of their group membership state
  • a user is linked to a user_group through a membership (panoptes resources marked as code)
  • when a member is "removed," which means a user's group membership.state is changed from "active" to "inactive", their classification stats (count and time) while an active group member will remain as part of the group's stats, but subsequent to removal the user's classification stats will not count towards the group's stats
  • i.e. a group cares about inactive member classifications when they were active group members (but not before or after they were active group members)

Planned follow-up for a subsequent PR:

  • update group manage modal Members section for clarity on "Remove member"
    • could include adding info near Members field title
    • could include rewording "Remove member"
  • add tooltip to Top Contributors section noting includes inactive members

Copy link
Contributor

@goplayoutside3 goplayoutside3 left a comment

Choose a reason for hiding this comment

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

Looks good, and the modal styling update is nice 👍

I'd still like to see an in-code comment addressing joinStatusSuccess for documentation (PR comment),

In this PR, you've also added more util functions for fetching data, but none of the requests have unit tests yet. I noticed nock is setup, but unused in lib-user, so I suggest creating some unit tests for the util functions soon to ensure reliability of the utils over time. There are lots of nock examples in app-project.

@github-actions github-actions bot added the approved This PR is approved for merging label Jun 7, 2024
@mcbouslog mcbouslog enabled auto-merge (squash) June 10, 2024 15:28
@mcbouslog mcbouslog merged commit b4935ba into master Jun 10, 2024
8 checks passed
@mcbouslog mcbouslog deleted the lib-user_manage-group branch June 10, 2024 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved This PR is approved for merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants