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

[$250] Contact method - There is no feature to delete unverified contact methods. #54626

Open
6 of 8 tasks
IuliiaHerets opened this issue Dec 27, 2024 · 26 comments
Open
6 of 8 tasks
Assignees
Labels
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

@IuliiaHerets
Copy link

IuliiaHerets commented Dec 27, 2024

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: v9.0.79-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from TestRail: https://expensify.testrail.io/index.php?/tests/view/5288103
Email or phone of affected tester (no customers): [email protected]
Issue reported by: Applause Internal Team
Device used: macOS Sequoia 15.1.1 / Web
App Component: undefined

Action Performed:

  1. Open the URL: https://staging.new.expensify.com
  2. Loggin
  3. Click on 'Settings'
  4. Click on 'Profile'
  5. Click on 'Contact methods'
  6. Click on 'New contact method'
  7. Enter a valid email & click on 'Add'
  8. Paste the code from mail and click on 'Verify'
  9. On the contact methods screen, click on the recently added unverified contact method.

Expected Result:

The user should be able to delete the contact method as long as it is unverified

Actual Result:

It is not possible to delete a univerified contact methods because there is no feature for that

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Bug6682518_1733188311399.There_is_no_feature_for_delete_unverified_contact_methods.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021874053836834663264
  • Upwork Job ID: 1874053836834663264
  • Last Price Increase: 2024-12-31
Issue OwnerCurrent Issue Owner: @parasharrajat
@IuliiaHerets IuliiaHerets added Daily KSv2 Bug Something is broken. Auto assigns a BugZero manager. labels Dec 27, 2024
Copy link

melvin-bot bot commented Dec 27, 2024

Triggered auto assignment to @laurenreidexpensify (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.

@Shahidullah-Muffakir
Copy link
Contributor

Shahidullah-Muffakir commented Dec 27, 2024

Edited by proposal-police: This proposal was edited at 2024-12-30 19:29:21 UTC.

Proposal

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

User is not able to remove an unverified contact method

What is the root cause of that problem?

New feature

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

We can accept the children prop in the ValidateCodeActionModal component as:

<View style={[themeStyles.borderTop, themeStyles.mv4]} />
{children}

Then, we simply pass the "Remove" button to it in the ContactMethodDetailsPage component as shown below:
here: ContactMethodDetailsPage

<ValidateCodeActionModal
                   title={formattedContactMethod}
                   onModalHide={() => {}}
                   hasMagicCodeBeenSent={hasMagicCodeBeenSent}
                   isVisible={isValidateCodeActionModalVisible && !loginData.validatedDate && !!loginData}
                   validatePendingAction={loginData.pendingFields?.validateCodeSent}
                   handleSubmitForm={(validateCode) => User.validateSecondaryLogin(loginList, contactMethod, validateCode)}
                   validateError={!isEmptyObject(validateLoginError) ? validateLoginError : ErrorUtils.getLatestErrorField(loginData, 'validateCodeSent')}
                   clearError={() => User.clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')}
                   onClose={() => {
                       Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo));
                       setIsValidateCodeActionModalVisible(false);
                   }}
                   sendValidateCode={() => User.requestContactMethodValidateCode(contactMethod)}
                   descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})}
               >
+                <OfflineWithFeedback
+                   pendingAction={loginData.pendingFields?.deletedLogin}
+                   errors={ErrorUtils.getLatestErrorField(loginData, 'deletedLogin')}
+                    errorRowStyles={[themeStyles.mt6, themeStyles.ph5]}
+                    onClose={() => User.clearContactMethodErrors(contactMethod, 'deletedLogin')}
+                >
+                    <MenuItem
+                       title={translate('common.remove')}
+                        icon={Expensicons.Trashcan}
+                        iconFill={theme.danger}
+                       onPress={() => toggleDeleteModal(true)}
+                    />
+               </OfflineWithFeedback>
               </ValidateCodeActionModal>

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

What alternative solutions did you explore? (Optional)

We can pass the ThreeDotsMenu as rightComponent to the Secondary emails, we need design confirmation for this:

Screen.Recording.2024-12-31.at.12.58.16.AM.mov
Screen.Recording.2024-12-28.at.12.15.37.AM.mov

@huult
Copy link
Contributor

huult commented Dec 29, 2024

Edited by proposal-police: This proposal was edited at 2024-12-29 08:39:48 UTC.

Proposal

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

There is no feature to delete unverified contact methods.

What is the root cause of that problem?

We are able to remove the contact method when it is verified and not the default contact.

setIsValidateCodeActionModalVisible(!loginData?.validatedDate);

{!isValidateCodeActionModalVisible && getMenuItems()}

And in the case of this ticket, the contact method is unable to be removed. This is a new feature

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

If we want to remove the contact method when it is not yet verified, we need to add getMenuItems to the footer props of ValidateCodeActionModal and update the parameters of getMenuItems to suit this case.

1 update ValidateCodeActionModal

update to:

    <ValidateCodeActionModal
        title={formattedContactMethod}
        onModalHide={() => {}}
        hasMagicCodeBeenSent={hasMagicCodeBeenSent}
        isVisible={isValidateCodeActionModalVisible && !loginData.validatedDate && !!loginData}
        validatePendingAction={loginData.pendingFields?.validateCodeSent}
        handleSubmitForm={(validateCode) => User.validateSecondaryLogin(loginList, contactMethod, validateCode)}
        validateError={!isEmptyObject(validateLoginError) ? validateLoginError : ErrorUtils.getLatestErrorField(loginData, 'validateCodeSent')}
        clearError={() => User.clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')}
        onClose={() => {
            Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo));
            setIsValidateCodeActionModalVisible(false);
        }}
        sendValidateCode={() => User.requestContactMethodValidateCode(contactMethod)}
        descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})}
        footer={() => getMenuItems(true)} // Add this line
    />

2 update getMenuItems

const getMenuItems = (onlyRemove = false) => {
        if (onlyRemove) { // Add this block
            if (isDefaultContactMethod) {
                return <View />;
            }
            return (
                <>
                    <OfflineWithFeedback
                        pendingAction={loginData.pendingFields?.deletedLogin}
                        errors={ErrorUtils.getLatestErrorField(loginData, 'deletedLogin')}
                        errorRowStyles={[themeStyles.mt6, themeStyles.ph5]}
                        onClose={() => User.clearContactMethodErrors(contactMethod, 'deletedLogin')}
                    >
                        <MenuItem
                            title={translate('common.remove')}
                            icon={Expensicons.Trashcan}
                            iconFill={theme.danger}
                            onPress={() => toggleDeleteModal(true)}
                        />
                    </OfflineWithFeedback>
                    <ConfirmModal
                        title={translate('contacts.removeContactMethod')}
                        onConfirm={confirmDeleteAndHideModal}
                        onCancel={() => toggleDeleteModal(false)}
                        onModalHide={() => {
                            InteractionManager.runAfterInteractions(() => {
                                validateCodeFormRef.current?.focusLastSelected?.();
                            });
                        }}
                        prompt={translate('contacts.removeAreYouSure')}
                        confirmText={translate('common.yesContinue')}
                        cancelText={translate('common.cancel')}
                        isVisible={isDeleteModalOpen && !isDefaultContactMethod}
                        danger
                    />
                </>
            );
        }

        ...
    };
POC
Screen.Recording.2024-12-29.at.15.47.31.mov

Note: I will test the other case and optimize the code during the pull request phase

Test branch

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

This issue updates the logic to allow removing the contact method when it is not verified, so I think we don’t need to test here

What alternative solutions did you explore? (Optional)

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

@melvin-bot melvin-bot bot added the Overdue label Dec 30, 2024
@laurenreidexpensify
Copy link
Contributor

I'm not sure I fully follow the last repro steps:

Paste the code from mail and click on 'Verify'
On the contact methods screen, click on the recently added unverified contact method.

It sounds like we're verifying the contact, but then looking to remove an unverified contact?

@melvin-bot melvin-bot bot removed the Overdue label Dec 30, 2024
@Shahidullah-Muffakir
Copy link
Contributor

It sounds like we're verifying the contact, but then looking to remove an unverified contact?

The first code we paste from the email is sent to the main email of the current user. The secondary email we are trying to add remains unverified until we enter the second code sent to that secondary email. So, until the code is entered for the secondary email, it is still considered unverified.

@parasharrajat
Copy link
Member

Ok, it looks like a valid issue. I can see that it was caused by #51882.

@parasharrajat
Copy link
Member

@Shahidullah-Muffakir I don't see how your proposal will open the Delete Modal.

@Shahidullah-Muffakir
Copy link
Contributor

@Shahidullah-Muffakir I don't see how your proposal will open the Delete Modal.

@parasharrajat Do you mean in the alternative method?"

@parasharrajat
Copy link
Member

parasharrajat commented Dec 30, 2024

No, on the main solution.

@Shahidullah-Muffakir
Copy link
Contributor

No, on the main solution.

Oh, okay. Since we're passing the Remove button as a child, clicking on it triggers the
onPress={() => toggleDeleteModal(true)} function, which opens the delete modal.

@parasharrajat
Copy link
Member

parasharrajat commented Dec 30, 2024

But where are we rendering the modal?

@parasharrajat
Copy link
Member

@laurenreidexpensify I can help review the proposals here as I have the context of the problem.

@Shahidullah-Muffakir
Copy link
Contributor

But where are we rendering the modal?

We're already rendering the Confirmation modal here:

<ConfirmModal
title={translate('contacts.removeContactMethod')}
onConfirm={confirmDeleteAndHideModal}
onCancel={() => toggleDeleteModal(false)}
onModalHide={() => {
InteractionManager.runAfterInteractions(() => {
validateCodeFormRef.current?.focusLastSelected?.();
});
}}
prompt={translate('contacts.removeAreYouSure')}
confirmText={translate('common.yesContinue')}
cancelText={translate('common.cancel')}
isVisible={isDeleteModalOpen && !isDefaultContactMethod}
danger

It’s on the same page, and the isVisible prop becomes true when isDeleteModalOpen && !isDefaultContactMethod is true, which happens when you press the button.

@laurenreidexpensify laurenreidexpensify added the External Added to denote the issue can be worked on by a contributor label Dec 31, 2024
@melvin-bot melvin-bot bot changed the title Contact method - There is no feature to delete unverified contact methods. [$250] Contact method - There is no feature to delete unverified contact methods. Dec 31, 2024
Copy link

melvin-bot bot commented Dec 31, 2024

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

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

melvin-bot bot commented Dec 31, 2024

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

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

@Shahidullah-Muffakir But that Modal is rendered conditionally. It will be rendered when the ValidateCode modal is not rendered on the UI.

About your proposal, you chose to add the remove option via the children prop. Why didn't you use a footer prop for that?

@huult
Copy link
Contributor

huult commented Dec 31, 2024

@parasharrajat I included it in my proposal

@parasharrajat
Copy link
Member

parasharrajat commented Dec 31, 2024

I saw that, just trying to understand the proposal.

@Shahidullah-Muffakir
Copy link
Contributor

@Shahidullah-Muffakir But that Modal is rendered conditionally. It will be rendered when the ValidateCode modal is not rendered on the UI.

No, I think it can still be displayed even if the ValidateCode modal is rendered, as I showed in the video. This is because we're only checking isVisible={isDeleteModalOpen && !isDefaultContactMethod}

About your proposal, you chose to add the remove option via the children prop. Why didn't you use a footer prop for that?

The footer prop would place the Remove button at the bottom of the screen, but the design team hasn't confirmed where the Remove button should go yet. Using the children prop allows us to display the Remove button anywhere we need."

@parasharrajat
Copy link
Member

parasharrajat commented Dec 31, 2024

But if you look at the code the Modal is mounted at

{!isValidateCodeActionModalVisible && getMenuItems()}
where mounting is controlled conditionally.

The footer prop would place the Remove button at the bottom of the screen, but the design team hasn't confirmed where the Remove button should go yet. Using the children prop allows us to display the Remove button anywhere we need."

I was expecting a slightly different motive so I asked. Thanks.

@parasharrajat
Copy link
Member

parasharrajat commented Dec 31, 2024

Here, we can't use the footer prop as it will force the verify button to float above the screen, which is against our design guidelines. That's why it was removed in #51882.

But the remove button should not have been removed from here. The correct location to show the Remove button would be the empty area like we have done in status page for clear status.

@Shahidullah-Muffakir
Copy link
Contributor

But if you look at the code the Modal is mounted at

{!isValidateCodeActionModalVisible && getMenuItems()}

where mounting is controlled conditionally.

Oh, sorry, I missed that. We can move the ConfirmModal out of the getMenuItems function and place it directly below {!isValidateCodeActionModalVisible && getMenuItems()}

@parasharrajat
Copy link
Member

After reviewing both proposals I can say that both lack some details. But following the reason in #54626 (comment), we can't use footer prop. We need a new prop or use children to achieve it. Tweaking both proposals will result in desired result, so I am going with the first in line and it does consider the placement of the remove button.

Let's go with @Shahidullah-Muffakir proposal for this one.

🎀 👀 🎀 C+ reviewed

Copy link

melvin-bot bot commented Dec 31, 2024

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

@huult
Copy link
Contributor

huult commented Dec 31, 2024

@parasharrajat If the design team wants the button for unverified contact methods to be located at the bottom and under the save button, then my proposal is valid.

@parasharrajat
Copy link
Member

That's a valid point @huult. Let me tag @Expensify/design team to suggest the placement of the delete button.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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
Development

No branches or pull requests

7 participants