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

[HOLD for payment 2024-12-03] [$250] Workspace members - User is not highlighted briefly in the table after being invited #52479

Closed
6 of 8 tasks
lanitochka17 opened this issue Nov 13, 2024 · 26 comments
Assignees
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor

Comments

@lanitochka17
Copy link

lanitochka17 commented Nov 13, 2024

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.0.61-0
Reproducible in staging?: Y
Reproducible in production?: Y
If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: Y
If this was caught during regression testing, add the test name, ID and link from TestRail: N/A
Email or phone of affected tester (no customers): applausetester+kh021101@applause.expensifail.com
Issue reported by: Applause - Internal Team

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to workspace settings
  3. Go to Members
  4. Click Invite
  5. Select any member > Next
  6. Click Invite

Expected Result:

The user will be highlighted briefly in the table after being invited. (previous behavior can be seen in this issue video #51788
).

Actual Result:

The user is not highlighted briefly in the table after being invited

Workaround:

Unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Add any screenshot/video evidence
Bug6663576_1731492388923.20241113_180239.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021856768422191044805
  • Upwork Job ID: 1856768422191044805
  • Last Price Increase: 2024-11-13
  • Automatic offers:
    • suneox | Reviewer | 104962187
@lanitochka17 lanitochka17 added Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Nov 13, 2024
Copy link

melvin-bot bot commented Nov 13, 2024

Triggered auto assignment to @sakluger (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

@gijoe0295
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

The user is not highlighted briefly in the table after being invited

What is the root cause of that problem?

We clear workspace invite member draft Onyx data on beforeRemove event of WorkspaceInvitePage:

const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});

Later in WorkspaceMembersPage, we check for invitedEmailsToAccountIDsDraft before highlighting the newly invited members:

if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {
return;
}
const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String);
selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails, 1500);

So the invited members data is cleared before it's checked in the above effects so scrollAndHighlightItem is not triggered.

What changes do you think we should make in order to solve the problem?

We should delay the beforeRemove callback until the RHP is fully dismissed using InteractionManager.runAfterInteractions

@mkzie2
Copy link
Contributor

mkzie2 commented Nov 13, 2024

Proposal

Please re-state the problem that we are trying to solve in this issue.

The user is not highlighted briefly in the table after being invited

What is the root cause of that problem?

After we invite members, the draft invite members is cleared before WorkspaceMembersPage is focused

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;

It leads invitedEmailsToAccountIDsDraft to be empty when the page is focused. So the new members aren't highlighted.

useEffect(() => {
if (!isFocused) {
return;
}
if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {
return;
}
const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String);
selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails, 1500);

What changes do you think we should make in order to solve the problem?

If the invite API is called here, we should not clear the draft invite members because we've cleared it after highlighting the new members here

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;

  1. We can create a new ref invitedUserRef
invitedUserRef = useRef(false);
  1. Update this to true when we call the invite API here
invitedUserRef.current = true;
  1. Don't clear the draft members if invitedUserRef.current is true;
const unsubscribe = navigation.addListener('beforeRemove', () => {
    if (invitedUserRef.current) {
        return;
    }
    Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;

What alternative solutions did you explore? (Optional)

@bernhardoj
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

User is not highlighted for a moment after adding it to workspace.

What is the root cause of that problem?

We highlight the new member if the page is focused, the accountID list changes, and there is an invite member draft.

if (!isFocused) {
return;
}
if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {
return;
}
const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String);
selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails, 1500);
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
}, [invitedEmailsToAccountIDsDraft, route.params.policyID, isFocused, accountIDs, prevAccountIDs]);

However, after inviting new users, the beforeRemove event is triggered which clears the invite member draft.

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;
}, [navigation, route.params.policyID]);

So the users are never highlighted because the draft is cleared. This happens after #51227.

But after fixing the above problem, the issue still happens when we invite users that we never chatted with before. In that case, the user is disabled. getItemBackgroundColorStyle will return an undefined background color if the item is disabled and the focused state is only true if it's not disabled.

const isItemFocused = (!isDisabled || item.isSelected) && (focusedIndex === normalizedIndex || itemsToHighlight?.has(item.keyForList ?? ''));

style={[
pressableStyle,
isFocused && StyleUtils.getItemBackgroundColorStyle(!!item.isSelected, !!isFocused, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG),
]}

App/src/styles/utils/index.ts

Lines 1127 to 1138 in b1c1a4b

function getItemBackgroundColorStyle(isSelected: boolean, isFocused: boolean, isDisabled: boolean, selectedBG: string, focusedBG: string): ViewStyle {
if (isSelected) {
return {backgroundColor: selectedBG};
}
if (isDisabled) {
return {backgroundColor: undefined};
}
if (isFocused) {
return {backgroundColor: focusedBG};
}

It's to fix #51984.

What changes do you think we should make in order to solve the problem?

We should clear the draft only if the invite page is focused.

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;
}, [navigation, route.params.policyID]);

The original logic was added to solve this issue where the invite member draft is not cleared when we close the page.

useEffect(() => {
    if (!isFocused) {
        return;
    }
    const unsubscribe = navigation.addListener('beforeRemove', () => {
        Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
    });

    return unsubscribe;
}, [navigation, route.params.policyID, isFocused]);

After applying the above changes, the invite member draft won't be cleared if we open the invite page > invite message page > then press the overlay. But on prod, it's also not cleared if we refresh while on the message page and close the RHP from the overlay. If we want, we can clear it in the invite message page too, but only if sendInvitation is not called.

const sendInvitation = () => {
Keyboard.dismiss();
const policyMemberAccountIDs = Object.values(PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList, false, false));
// Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details
Member.addMembersToWorkspace(invitedEmailsToAccountIDsDraft ?? {}, `${welcomeNoteSubject}\n\n${welcomeNote}`, route.params.policyID, policyMemberAccountIDs);
debouncedSaveDraft(null);
Navigation.dismissModal();
};

Now, to fix the disabled new member not getting highlighted, we need to separate the itemsToHighlight vaue.

const isItemFocused = (!isDisabled || item.isSelected) && (focusedIndex === normalizedIndex || itemsToHighlight?.has(item.keyForList ?? ''));
// We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade.
const showTooltip = shouldShowTooltips && normalizedIndex < 10;
return (
<View onLayout={(event: LayoutChangeEvent) => onItemLayout(event, item?.keyForList)}>
<BaseSelectionListItemRenderer
ListItem={ListItem}
item={item}
index={index}

const isItemFocused = (!isDisabled || item.isSelected) && (focusedIndex === normalizedIndex);
const isItemHighlighted = itemsToHighlight?.has(item.keyForList ?? '');

And if isItemHighlighted is true, we pass the highlighted bg color to the pressableStyle.

pressableStyle={isItemHighlighted ? styles.hoveredComponentBG : {}}

We need to update TableListItem to receive pressableStyle and pass it to BaseListItem. This way, disabled members will still be highlighted. This highlight logic is currently being used in workspace members page only.

@sakluger
Copy link
Contributor

The current behavior shown in the video looks fine to me. I'm checking with the team in Slack (https://expensify.slack.com/archives/C06ML6X0W9L/p1731515655449829) to see if this should be considered a bug or not.

@sakluger sakluger added the External Added to denote the issue can be worked on by a contributor label Nov 13, 2024
@melvin-bot melvin-bot bot changed the title Workspace members - User is not highlighted briefly in the table after being invited [$250] Workspace members - User is not highlighted briefly in the table after being invited Nov 13, 2024
Copy link

melvin-bot bot commented Nov 13, 2024

Job added to Upwork: https://www.upwork.com/jobs/~021856768422191044805

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Nov 13, 2024
Copy link

melvin-bot bot commented Nov 13, 2024

Triggered auto assignment to Contributor-plus team member for initial proposal review - @suneox (External)

@sakluger
Copy link
Contributor

I got confirmation that the expected behavior is correct in the OP. Let's fix it!

@sakluger
Copy link
Contributor

I was asked to clarify the intended behavior after inviting a new member to a workspace:

  1. Make sure that user is in the view port (there could be hundreds of members)
  2. Temporarily highlight the member using yellow

@huult
Copy link
Contributor

huult commented Nov 14, 2024

Edited by proposal-police: This proposal was edited at 2024-11-14 07:19:45 UTC.

Proposal

Please re-state the problem that we are trying to solve in this issue.

User is not highlighted briefly in the table after being invited

What is the root cause of that problem?

Before returning to the workspace members, we set setWorkspaceInviteMembersDraft to {} from the workspace invite page

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', () => {
Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
});
return unsubscribe;
}, [navigation, route.params.policyID]);

This code checks if invitedEmailsToAccountIDsDraft is empty or if accountIDs equals prevAccountIDs. If either condition is true, it returns early. Otherwise, it maps the invited emails and calls scrollAndHighlightItem to scroll and highlight the items in the list.

if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {

We set setWorkspaceInviteMembersDraft to {} before returning to the workspace members, therefore it returns early and does not scroll and highlight the item.

What changes do you think we should make in order to solve the problem?

To resolve this issue, we should check for changes in the accountIDs list. If there are new accountIDs, we will scroll and highlight them. The code will be:

if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {

      useEffect(() => {
        if (!isFocused) {
            return;
        }

        // We check if accountIDs haven't changed, then return
+        if (accountIDs === prevAccountIDs) {
+          return;
+        }

        // We check if one or more members were removed from accountIDs, then return
+        if (accountIDs.length < prevAccountIDs.length) {
+          return;
+        }

+        const diffAccountIDs = accountIDs.filter((id) => !prevAccountIDs.includes(id));

        // If no account changes, return early
+        if (!isEmptyObject(invitedEmailsToAccountIDsDraft) && !diffAccountIDs.length) {
+          return;
+        }

-        if (isEmptyObject(invitedEmailsToAccountIDsDraft) || accountIDs === prevAccountIDs) {
-            return;
-        }
-        const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String);
-        selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails, 1500);
+        selectionListRef.current?.scrollAndHighlightItem?.(
+            diffAccountIDs.map((item) => String(item)),
+            1500,
+        );
        Member.setWorkspaceInviteMembersDraft(route.params.policyID, {});
    }, [invitedEmailsToAccountIDsDraft, route.params.policyID, isFocused, accountIDs, prevAccountIDs]);

Test branch

POC
Screen.Recording.2024-11-14.at.14.17.32.mp4

What alternative solutions did you explore? (Optional)

@suneox
Copy link
Contributor

suneox commented Nov 18, 2024

Thanks for all the proposals. The RCA from @bernhardoj proposal is correct—this issue occurred after merging PR #51227. His proposal also supports updating a custom highlighted BG, so we can proceed with this proposal

🎀 👀 🎀 C+ reviewed

Temporarily highlight the member using yellow

@sakluger We need to confirm whether the expected highlight background should look like the one

Screen.Recording.2024-11-17.at.21.34.56.mp4

or if we need a different background color?

Copy link

melvin-bot bot commented Nov 18, 2024

Triggered auto assignment to @techievivek, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@sakluger
Copy link
Contributor

cc @Expensify/design could you please help verify the correct highlight color for when a new member is invited to a workspace? Can we use the same color as we do on the Expenses page as shown in the comment above?

@dannymcclain
Copy link
Contributor

Yes I think we should use the same highlight pattern we use for expenses on the search page.

@dubielzyk-expensify
Copy link
Contributor

Yes I think we should use the same highlight pattern we use for expenses on the search page.

Agree

@shawnborton
Copy link
Contributor

Agree three

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Nov 19, 2024
Copy link

melvin-bot bot commented Nov 19, 2024

📣 @suneox 🎉 An offer has been automatically sent to your Upwork account for the Reviewer role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job

@melvin-bot melvin-bot bot added Reviewing Has a PR in review and removed Daily KSv2 labels Nov 19, 2024
@melvin-bot melvin-bot bot added the Weekly KSv2 label Nov 19, 2024
@bernhardoj
Copy link
Contributor

PR is ready

cc: @suneox

@JmillsExpensify
Copy link

Same same. One highlight pattern to rule them all.

@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels Nov 26, 2024
@melvin-bot melvin-bot bot changed the title [$250] Workspace members - User is not highlighted briefly in the table after being invited [HOLD for payment 2024-12-03] [$250] Workspace members - User is not highlighted briefly in the table after being invited Nov 26, 2024
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label Nov 26, 2024
Copy link

melvin-bot bot commented Nov 26, 2024

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented Nov 26, 2024

The solution for this issue has been 🚀 deployed to production 🚀 in version 9.0.66-8 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2024-12-03. 🎊

For reference, here are some details about the assignees on this issue:

Copy link

melvin-bot bot commented Nov 26, 2024

@suneox @sakluger @suneox The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

@sakluger
Copy link
Contributor

sakluger commented Dec 2, 2024

Hey @suneox, please complete the BZ checklist before the payment due date tomorrow. Thanks!

@suneox
Copy link
Contributor

suneox commented Dec 3, 2024

BugZero Checklist:

  • [Contributor] Classify the bug:
Bug classification

Source of bug:

  • 1a. Result of the original design (eg. a case wasn't considered)
  • 1b. Mistake during implementation
  • 1c. Backend bug
  • 1z. Other:

Where bug was reported:

  • 2a. Reported on production
  • 2b. Reported on staging (deploy blocker)
  • 2c. Reported on both staging and production
  • 2d. Reported on a PR
  • 2z. Other:

Who reported the bug:

  • 3a. Expensify user
  • 3b. Expensify employee
  • 3c. Contributor
  • 3d. QA
  • 3z. Other:
  • [Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.

    Link to comment: https://github.com/Expensify/App/pull/51227/files#r1866995349

  • [Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.

    Link to discussion: N/A

  • [Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
    N/A: It isn't an impactful bug

@melvin-bot melvin-bot bot added Daily KSv2 and removed Weekly KSv2 labels Dec 3, 2024
@sakluger
Copy link
Contributor

sakluger commented Dec 3, 2024

Summarizing payment on this issue:

Contributor: @bernhardoj $250, please request via NewDot
Contributor+: @suneox $250, paid via Upwork

@sakluger sakluger closed this as completed Dec 3, 2024
@JmillsExpensify
Copy link

$250 approved for @bernhardoj

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor
Projects
None yet
Development

No branches or pull requests