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

Refactor/16286 refactor profile context menu #16334

Merged
merged 2 commits into from
Sep 24, 2024

Conversation

iurimatias
Copy link
Member

@iurimatias iurimatias commented Sep 13, 2024

closes #16286

What does the PR do

This refactor ProfileContextMenu to make it a functional component by:

  • refactored out direct calls to backend, and passing backend data structures and moved this logic to the callers, also refactored common calls between the callers
  • common types of context menus have been extracted to their sub components which removes a lot of logic too and makes the behaviour very clear
  • user verification workflow (which was already disabled) has been removed

Affected areas

Any where in which one can right click or click on ... menu to see the profile context menu, to my knoweldge this includes:

  • left click or right click username on a message in all chats (1 on 1, group chats and communities)
  • right click username on a member list of a group chat
  • right click username on a member list of a community channel
  • clicking on the ... menu in contacts list in settings

Impact on end user

The before/after behaviour should be the same for the end user

How to test

  • test affected areas and that 1) the profile context menu opens correctly with the right menu items visible) and 2) menu items works as expected (e.g clicking "add nickname" should open the add nickname modal)

note: The goal here is to refactor under the hood while keeping the same behaviour as before. For example, if a profile is in a blocked state, the trustworthy/untrustworthy mark doesn't show because it didn't show before either, if that behaviour should change is beyond the scope of this PR.

Risk

Needs further testing before merging:

  • contacts with ENS, I couldn't verify if this works as expected because I keep seeing the ring (meaning the ENS verification didn't work) it's not necessary a issue with this PR but needs to be checked
  • any other areas that might have been forgotten, I haven't tested in a contact list in a community admin settings

@status-im-auto
Copy link
Member

status-im-auto commented Sep 13, 2024

Jenkins Builds

Click to see older builds (42)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 4391fe6 #1 2024-09-13 14:47:56 ~6 min tests/nim 📄log
✔️ 4391fe6 #1 2024-09-13 14:49:54 ~8 min macos/aarch64 🍎dmg
✔️ 4391fe6 #1 2024-09-13 14:52:53 ~11 min tests/ui 📄log
✔️ 4391fe6 #1 2024-09-13 14:53:25 ~11 min macos/x86_64 🍎dmg
✔️ 88d1f1f #2 2024-09-13 15:00:14 ~6 min macos/aarch64 🍎dmg
✔️ 88d1f1f #2 2024-09-13 15:01:13 ~7 min macos/x86_64 🍎dmg
✔️ 88d1f1f #2 2024-09-13 15:01:22 ~7 min tests/nim 📄log
✔️ 88d1f1f #2 2024-09-13 15:05:32 ~11 min tests/ui 📄log
✔️ 88d1f1f #2 2024-09-13 15:09:11 ~15 min linux-nix/x86_64 📦tgz
✔️ 88d1f1f #2 2024-09-13 15:11:58 ~18 min linux/x86_64 📦tgz
✔️ 88d1f1f #2 2024-09-13 15:19:55 ~26 min windows/x86_64 💿exe
✔️ 9789141 #3 2024-09-17 16:38:12 ~6 min macos/aarch64 🍎dmg
✔️ 9789141 #3 2024-09-17 16:38:42 ~6 min tests/nim 📄log
✔️ 9789141 #3 2024-09-17 16:40:12 ~8 min macos/x86_64 🍎dmg
✔️ 9789141 #3 2024-09-17 16:43:42 ~11 min tests/ui 📄log
✔️ 9789141 #3 2024-09-17 16:45:13 ~13 min linux-nix/x86_64 📦tgz
✔️ 9789141 #3 2024-09-17 16:48:16 ~16 min linux/x86_64 📦tgz
✔️ 9789141 #3 2024-09-17 16:59:08 ~27 min windows/x86_64 💿exe
✔️ 93f17b2 #6 2024-09-17 22:08:28 ~5 min tests/nim 📄log
✔️ 93f17b2 #6 2024-09-17 22:11:09 ~8 min macos/aarch64 🍎dmg
✔️ 93f17b2 #6 2024-09-17 22:13:23 ~10 min macos/x86_64 🍎dmg
✔️ 93f17b2 #6 2024-09-17 22:15:41 ~13 min linux-nix/x86_64 📦tgz
✔️ 93f17b2 #6 2024-09-17 22:18:29 ~15 min linux/x86_64 📦tgz
✔️ 93f17b2 #6 2024-09-17 22:27:57 ~25 min windows/x86_64 💿exe
✔️ 8e0b619 #7 2024-09-19 16:55:16 ~6 min macos/aarch64 🍎dmg
✔️ 8e0b619 #7 2024-09-19 16:55:55 ~6 min tests/nim 📄log
✔️ 8e0b619 #7 2024-09-19 16:57:29 ~8 min macos/x86_64 🍎dmg
✔️ 8e0b619 #7 2024-09-19 17:02:41 ~13 min linux-nix/x86_64 📦tgz
✔️ 8e0b619 #7 2024-09-19 17:03:09 ~14 min linux/x86_64 📦tgz
✔️ 8e0b619 #7 2024-09-19 17:10:06 ~20 min windows/x86_64 💿exe
✔️ e423081 #8 2024-09-20 14:35:35 ~6 min macos/aarch64 🍎dmg
✔️ e423081 #8 2024-09-20 14:36:13 ~6 min tests/nim 📄log
✔️ e423081 #8 2024-09-20 14:37:59 ~8 min macos/x86_64 🍎dmg
✔️ e423081 #8 2024-09-20 14:42:30 ~13 min linux-nix/x86_64 📦tgz
✔️ e423081 #8 2024-09-20 14:45:17 ~15 min linux/x86_64 📦tgz
✔️ e423081 #8 2024-09-20 14:49:05 ~19 min windows/x86_64 💿exe
✔️ 0d80878 #9 2024-09-20 19:57:31 ~6 min macos/aarch64 🍎dmg
✔️ 0d80878 #9 2024-09-20 19:57:59 ~6 min tests/nim 📄log
✔️ 0d80878 #9 2024-09-20 19:59:27 ~7 min macos/x86_64 🍎dmg
✔️ 0d80878 #9 2024-09-20 20:04:59 ~13 min linux-nix/x86_64 📦tgz
✔️ 0d80878 #9 2024-09-20 20:06:20 ~14 min linux/x86_64 📦tgz
✔️ 0d80878 #9 2024-09-20 20:10:52 ~19 min windows/x86_64 💿exe
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ a09b773 #10 2024-09-23 16:10:55 ~6 min macos/aarch64 🍎dmg
✔️ a09b773 #10 2024-09-23 16:11:31 ~6 min tests/nim 📄log
✔️ a09b773 #10 2024-09-23 16:14:55 ~10 min macos/x86_64 🍎dmg
✔️ a09b773 #10 2024-09-23 16:18:06 ~13 min linux-nix/x86_64 📦tgz
✔️ a09b773 #10 2024-09-23 16:20:47 ~15 min linux/x86_64 📦tgz
✔️ a09b773 #10 2024-09-23 16:24:17 ~19 min windows/x86_64 💿exe
✔️ a09b773 #12 2024-09-23 16:45:16 ~11 min tests/ui 📄log
✔️ c979956 #11 2024-09-23 20:29:47 ~6 min tests/nim 📄log
✔️ c979956 #11 2024-09-23 20:31:52 ~8 min macos/aarch64 🍎dmg
✔️ c979956 #11 2024-09-23 20:35:10 ~12 min linux-nix/x86_64 📦tgz
✔️ c979956 #13 2024-09-23 20:35:20 ~12 min tests/ui 📄log
✔️ c979956 #11 2024-09-23 20:39:05 ~16 min linux/x86_64 📦tgz
✔️ c979956 #11 2024-09-23 20:43:09 ~20 min macos/x86_64 🍎dmg
✔️ c979956 #11 2024-09-23 20:44:32 ~21 min windows/x86_64 💿exe

@iurimatias iurimatias force-pushed the refactor/16286_refactor_profile_context_menu branch from 4391fe6 to 88d1f1f Compare September 13, 2024 14:53
Copy link
Member

@micieslak micieslak left a comment

Choose a reason for hiding this comment

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

Nice work! Looks promising in general but there are several things to make it better:

  1. Please use one Storybook page per component. Then it's clear that provided controls are for that given component. Ideally the whole API of the component should be accessible in the page via controls like e.g. check boxes for flags or text fields for strings.

  2. For the popups/menus it's handy to instantiate the component in a following way:

    MessageContextMenuView {
        id: menu
    
        anchors.centerIn: parent
        hideDisabledItems: false
    
        visible: true
        closePolicy: Popup.NoAutoClose
    }
    
    Button {
        text: "reopen"
    
        anchors.centerIn: parent
        onClicked: menu.open()
    }

    Than it's not necessary to re-open the menu after every change via the provided controls. It's also not necessary to create it dynamically via createObject().

  3. Do not pass stores to low-level like those menus, especially that only tiny flag from the store is used (isDebugEnabled). It's better to expose bool property isDebugEnabled and take just a single bool instead of the whole store object.

  4. As mentioned above, store should not be part of the API. But whenever stores are part of the api, they should be mocked in a storybook page in a following way:

    MessageContextMenuView {
        id: menu
    
        store: ChatStores.RootStore {
            readonly property bool isDebugEnabled: true
        }
    }
  5. Please keep only necessary imports, in components and in SB pages as well.

  6. Separate components for BridgeProfileContextMenu, RegularProfileContextMenu, SelfProfileContextMenu, BlockedProfileContextMenu which are then aggregated in ProfileContentMenu are not good idea for serveral reasons:

    • huge code duplication, e.g. ProfileHeader { part is almost the same in all variants
    • need of using Loader and complicated imperative code in onLoaded handler doing assignments to type-erasured item object
    • overgrown api of ProfileContextMenu taking stuff necessary for all 4 variants. E.g. it's not clear without reading the impl details that for self version onlineStatus is irrelevant.
    • ProfileContextMenu is Item so we loose access to Popup api which may be needed on the caller side

    Probably the better idea would be to create two top-level variants for own profile and another for contacts.

@iurimatias
Copy link
Member Author

iurimatias commented Sep 13, 2024

wrt to 6, this a common side effect of this pattern, which is sort of the exception to the rule for DRY, in this case although it introduces some duplication it makes everything quite simple, joining them on the otherhand will introduce (like before) a lot overcomplicated if/elseif/else conditions which is easy to get lost in

"Probably the better idea would be to create two top-level variants for own profile and another for contacts."

meaning the caller chooses which one to instantiate/open?

@iurimatias
Copy link
Member Author

also why would profile and "contacts" be the variants? why not say, contacts and blocked etc..
when I analyzed this, the result was 4 type of different variants: Bridge, Self, Blocked (it is its own thing after analysis as lot of propers don't apply anymore) and then Contacts. Contacts then has properties that don't apply to others such as trustworthy, contact request state etc..

@iurimatias
Copy link
Member Author

wrt 4) I'm not sure what you're reffering to, did this PR introduce stores anywhere? (that were not already there at least) I do see some components still have the store thing which is not used, I just forgot to remove it

@iurimatias
Copy link
Member Author

wrt Please use one Storybook page per component... Ideally the whole API of the component should be accessible in the page via controls like e.g. check boxes for flags or text fields for strings.

  • the API was added in storybook (previously this component had no controls whatsoever)
  • it's a single page because it's a "state" of the component and the subcomponents are abstracted away

@iurimatias
Copy link
Member Author

wrt 2) For the popups/menus it's handy to instantiate the component in a following way:

is this something that was already there or was introduced in this PR? if the former I think it would be helpful to do it in a different stage/PR as this is already a big improvement and lots of changes to be tested too. furthermore this PR helps with other actual issues to do after this.

@iurimatias
Copy link
Member Author

wrt 3) Do not pass stores to low-level like those menus, especially that only tiny flag from the store is used (isDebugEnabled). It's better to expose bool property isDebugEnabled and take just a single bool instead of the whole store object.

What is this refering to? I don't see any isDebugEnabled, also I removed stores but it's possible the property is still defined and I forgot to remove it


StatusMenu {
Item {
id: root

property ChatStores.RootStore store
Copy link
Member Author

Choose a reason for hiding this comment

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

this is not in use actually, it should be removed from here and the sub components

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Member Author

Choose a reason for hiding this comment

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

should be removed, not in use

Copy link
Contributor

Choose a reason for hiding this comment

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

myPublicKey as well

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Member Author

Choose a reason for hiding this comment

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

should be removed, not in use

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Member Author

Choose a reason for hiding this comment

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

should be removed, not in use

Copy link
Contributor

Choose a reason for hiding this comment

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

myPublicKey as well

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Member Author

Choose a reason for hiding this comment

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

should be removed, not in use

@micieslak
Copy link
Member

Hey @iurimatias, some points are listed are probably not directly about your changes but about the general current state indeed. Like about storybook page - I haven't noticed it was like that before. It should be improved and split into two pages (ProfileContextMenu -> ProfileContextMenuPage and MessageContextMenuView -> MessageContextMenuViewPage) but it can be done separately ofc.

wrt to 6, this a common side effect of this pattern, which is sort of the exception to the rule for DRY, in this case although it introduces some duplication it makes everything quite simple, joining them on the otherhand will introduce (like before) a lot overcomplicated if/elseif/else conditions which is easy to get lost in

I think that the biggest benefit you gained is achieved by simplifying API of ProfileContextMenu. Splitting into those 4 subcomponents is sth I would replace with qml's states. I would allow to limit amount of imperative code, keep the differentiating logic in one place and still have that component relatively small.

Something that we probably should reconsider is location of getProfileContext, getProfileType and getContactType because according to the guideline we should not access backend via singletons. He we do that because getProfileContent calls getContactDetailsAsJson which is accessing mainModuleInst context property from the singleton. This is something we are struggling to sort out and keep access to backend hidden behind stores.

Copy link
Contributor

@alexjba alexjba left a comment

Choose a reason for hiding this comment

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

Nice work! 🍻 I'm glad that these components are getting some attention.

I've done some initial testing and found no regressions.

Added a few findings below. Some points have already been touched by @micieslak, but I think it's worth reiterating them as it brings some long term value.

@@ -455,6 +455,44 @@ QtObject {
}
}

function getProfileContext(publicKey, myPublicKey, isBridgedAccount = false) {
const contactDetails = getContactDetailsAsJson(publicKey, true, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

There's this effort of removing the nim access from singletons. Adding this function here will add more work for later.

I'd move this to ContactsStore.qml if it's really needed.

@@ -85,6 +86,46 @@ SplitView {
ProfileContextMenu {
anchors.centerIn: parent
hideDisabledItems: false
profileType: profileTypeSelector.currentText
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a warning herefile:///Users/alexjbanca/Repos/status-desktop/storybook/pages/MessageContextMenuPage.qml:89:21: Unable to assign QString to int

Copy link
Contributor

Choose a reason for hiding this comment

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

This could become the base component for the other 3.
Then we'd have a ProfileMenuBase containing the ProfileHeader. In this case other components won't have to duplicate the header. WDYT?

The advantage here would be that the other components will be much cleaner with this logic extracted in a base component. We'd probably end-up with simple sets of actions for each variation.

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Contributor

Choose a reason for hiding this comment

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

myPublicKey as well

StatusMenu {
id: root

property ChatStores.RootStore store
Copy link
Contributor

Choose a reason for hiding this comment

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

myPublicKey as well

signal removeContact(string publicKey)
signal blockContact(string publicKey)

onClosed: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove the onClosed handler from all menu components. The issue with this handler is that it's breaking the bindings set from the outside. A component should not break the bindings on its public API.

If we need to reset the data here it's better to do it from the outside. Also, the reset should cover all the input properties. But I think it's fine without the reset, right?

topPadding: root.topPadding
visible: !root.isBridgedAccount
}
onLoaded: {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd do it the other way: Each component to bind its properties and signals to the root properties and signals.

The are a few advantages:

  1. we won't need this imperative approach and all the bindings would work as expected.
  2. No need to create most of the the if branches
  3. No need for the manual connections
  4. Failing fast in case of type errors at qml compilation time
    And probably more.

In general it's a good approach to choose the declarative approach as it brings many advantages.

Global.openProfilePopup(publicKey, null)
}
onCreateOneToOneChat: (communityId, chatId, ensName) => {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
root.rootStore.chatCommunitySectionModule.createOneToOneChat("", chatId, ensName)
}
onReviewContactRequest: (publicKey) => {
const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true)
Copy link
Contributor

Choose a reason for hiding this comment

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

WDYT of using the ContactDetails component as a helper for the ProfileContextMenu instead of Utils.getContactDetailsAsJson usages. I think it would simplify our life quite a bit.
We'd end-up with something like this:

Global.openMenu(profileContextMenuComponent, sender, { selectedUserPublicKey: publicKey })
...

ProfileContextMenu {
    ContactDetails {
                id: contactDetails
                publicKey: selectedUserPublicKey
                contactsStore: root.contactsStore
                profileStore: root.profileStore
         }
         
         selectedUserDisplayName: contactDetails.displayName
         selectedUserIcon: contactDetails.icon
          profileType: Utils.getProfileType(publicKey, myPublicKey, isBridgedAccount, isBlocked);
          contactType: Utils.getContactType(contactDetails.contactRequestState, contactDetails.isContact);
          trustStatus: contactDetails.trustStatus
          ensVerified: contactDetails.ensVerified
          onlineStatus: contactDetails.onlineStatus
          hasLocalNickname: !!contactDetails.localNickname
    }

Would be a step in the right direction in the sense that we won't need to revisit this code when removing usages of Utils.getContactDetailsAsJson. Another big advantage IMO is that it completely removes the need of adding more dependencies to the nim layer in the Utils singleton (Utils.getProfileContext).

Copy link
Contributor

Choose a reason for hiding this comment

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

The same could be done for ContactsView, UsersPanel. My hope is that the code could eventually be extracted in a single place if we only need to specify the publicKey to the ProfileContextMenu.

Copy link
Member Author

Choose a reason for hiding this comment

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

not sure I understood what you want here, may I suggest in a different PR though?

Copy link
Contributor

Choose a reason for hiding this comment

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

sounds good to me! The idea here is to use ContactDetails instead of getContactDetailsAsJson where possible.

onOpenProfileClicked: (publicKey) => {
console.log("MessageView.qml:1: open profile clicked", publicKey)
Copy link
Contributor

Choose a reason for hiding this comment

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

leftover

@@ -170,13 +173,48 @@ Item {
ProfileContextMenu {
store: root.store
margins: 8
onOpenProfileClicked: {
onOpenProfileClicked: (publicKey) => {
console.log("UserListPanel.qml:1: open profile clicked", publicKey)
Copy link
Contributor

Choose a reason for hiding this comment

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

leftover

Copy link
Contributor

@alexjba alexjba left a comment

Choose a reason for hiding this comment

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

Minor findings below. Other than that, looks great! Thank you!

Tested

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm glad ProfileContextMenu is back to a StatusMenu 👍 Looks great

@@ -85,6 +86,46 @@ SplitView {
ProfileContextMenu {
anchors.centerIn: parent
hideDisabledItems: false
profileType: profileTypeSelector.currentText
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
profileType: profileTypeSelector.currentText
profileType: profileTypeSelector.currentValue

Comment on lines 123 to 100
onTriggered: {
root.createOneToOneChat("", root.selectedUserPublicKey, "")
root.close()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be removed. The menu closes by itself after triggering the action

Suggested change
onTriggered: {
root.createOneToOneChat("", root.selectedUserPublicKey, "")
root.close()
}
onTriggered: root.createOneToOneChat("", root.selectedUserPublicKey, "")

Comment on lines 73 to 70
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey)
root.close()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey)
root.close()
}
onTriggered: root.openProfileClicked(root.selectedUserPublicKey)

signal markAsUntrusted(string publicKey)
signal removeTrustStatus(string publicKey)
signal removeContact(string publicKey)
signal blockContact(string publicKey)

onClosed: {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a good chance to remove this onClosed handler. It's not needed and potentially a source of bugs because it's breaking the bindings. We're currently destroying the menu on close anyways.

@iurimatias iurimatias force-pushed the refactor/16286_refactor_profile_context_menu branch 2 times, most recently from 2349473 to 93f17b2 Compare September 17, 2024 22:02
Copy link
Member

@micieslak micieslak left a comment

Choose a reason for hiding this comment

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

Looks nice already, much simpler than initially.
Couple minor suggestions left.

What I'd love to see here is splitting storybook pages. Now the page is MessageContextMenuPage.qml, for two components: MessageContextMenuView and ProfileContextMenu.

The convention, respected almost in all pages is the rule 1 page per 1 component, with naming convention: MyComponent -> MyComponentPage.

So we should have
MessageContextMenuViewPage and ProfileContextMenuPage instead of the single one used now. Also the previously left suggestions how to instantiate menus/popups would improve readability/usability of the page as well.

property bool ensVerified: false
property int onlineStatus: Constants.onlineStatus.unknown
property bool hasLocalNickname: false
property int profileType: Constants.profileType.regular

signal openProfileClicked(string publicKey)
Copy link
Member

Choose a reason for hiding this comment

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

Signals could be simplified because publicKey is always known at the caller side. Providing some kind of identifier is necessary only when the component maintains more than one item of given type, e.g. in a list.

signal openProfileClicked
signal createOneToOneChat
signal reviewContactRequest
signal sendContactRequest
signal editNickname
signal removeNickname
signal unblockContact
signal markAsUntrusted
signal removeTrustStatus
signal removeContact
signal blockContact

Especially confusing is
signal createOneToOneChat(string communityId, string chatId, string ensName) because is triggered only in one place in the following way:

root.createOneToOneChat("", root.selectedUserPublicKey, "")

So communityId and ensName are always empty strings and chatId is the same publicKey as in other signals.

Comment on lines 15 to 17
property string selectedUserPublicKey: ""
property string selectedUserDisplayName: ""
property string selectedUserIcon: ""
Copy link
Member

Choose a reason for hiding this comment

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

Minor thing: those names could be simplified to just publicKey, displayNameandicon`. The prefix doesn't disambiguate anything, so probably can be removed.

@@ -178,4 +178,42 @@ QtObject {
function getLinkToProfile(publicKey) {
return root.contactsModule.shareUserUrlWithData(publicKey)
}

function getProfileContext(publicKey, myPublicKey, isBridgedAccount = false) {
const contactDetails = Utils.getContactDetailsAsJson(publicKey, true, true);
Copy link
Member

Choose a reason for hiding this comment

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

We are not using ; in qml code. Not a big deal, but for consistency it would be nice to keep the no ; convention :)

const onlineStatus = contactDetails ? contactDetails.onlineStatus : Constants.onlineStatus.unknown;
const hasLocalNickname = contactDetails ? !!contactDetails.localNickname : false;

return { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname };
Copy link
Member

Choose a reason for hiding this comment

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

I would consider early return to increase readability of that function:

    function getProfileContext(publicKey, myPublicKey, isBridgedAccount = false) {
        const contactDetails = Utils.getContactDetailsAsJson(publicKey, true, true);
        
        if (!contactDetails) {
            return {
                profileType: getProfileType(publicKey, myPublicKey, isBridgedAccount, false),
                trustStatus: Constants.trustStatus.unknown,
                contactType: getContactType(Constants.ContactRequestState.None, false),
                ensVerified: false,
                onlineStatus: Constants.onlineStatus.unknown,
                hasLocalNickname: false
            }
        }
        
        const isBlocked = contactDetails.isBlocked
        const profileType = getProfileType(publicKey, myPublicKey, isBridgedAccount, isBlocked)
        const contactType = getContactType(contactDetails.contactRequestState, contactDetails.isContact)
        const trustStatus = contactDetails.trustStatus
        const ensVerified = contactDetails.ensVerified
        const onlineStatus = contactDetails.onlineStatus
        const hasLocalNickname = !!contactDetails.localNickname

        return { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname }
    }

Copy link
Member

Choose a reason for hiding this comment

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

or

    function getProfileContext(publicKey, myPublicKey, isBridgedAccount = false) {
        const contactDetails = Utils.getContactDetailsAsJson(publicKey, true, true);
        
        if (!contactDetails) {
            return {
                profileType: getProfileType(publicKey, myPublicKey, isBridgedAccount, false),
                trustStatus: Constants.trustStatus.unknown,
                contactType: getContactType(Constants.ContactRequestState.None, false),
                ensVerified: false,
                onlineStatus: Constants.onlineStatus.unknown,
                hasLocalNickname: false
            }
        }
        
        return {
            profileType: getProfileType(publicKey, myPublicKey, isBridgedAccount, contactDetails.isBlocked),
            trustStatus: contactDetails.trustStatus,
            contactType: getContactType(contactDetails.contactRequestState, contactDetails.isContact),
            ensVerified: contactDetails.ensVerified,
            onlineStatus: contactDetails.onlineStatus,
            hasLocalNickname: !!contactDetails.localNickname
        }
    }

}

function getProfileType(publicKey, myPublicKey, isBridgedAccount, isBlocked) {
if (publicKey === myPublicKey) {
Copy link
Member

Choose a reason for hiding this comment

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

we usually skip {} for one liners

Copy link
Contributor

@glitchminer glitchminer left a comment

Choose a reason for hiding this comment

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

Related issues found to be raised against master:

  • ENS names are not being shown
  • Context menu in community members list does not display profile image or name
    --
    image

Completed:

SD-343: Profile context menu for a stranger
SD-344: Profile context menu for a contact
SD-347: Profile context menu for discord bridge user
SD-346: Profile context menu for self

TR: https://ethstatus.testrail.net/index.php?/plans/view/17989

@caybro
Copy link
Member

caybro commented Sep 19, 2024

Related issues found to be raised against master:

  • ENS names are not being shown
  • Context menu in community members list does not display profile image or name

Both are definitely working in master:
image

So it's a regression here

@iurimatias
Copy link
Member Author

ok we should not merge this then if there is a regression, I'll look into it

@iurimatias
Copy link
Member Author

that said, I just tested it and it's not happening to me 🤔

@iurimatias iurimatias force-pushed the refactor/16286_refactor_profile_context_menu branch from 93f17b2 to 8e0b619 Compare September 19, 2024 16:48
@iurimatias
Copy link
Member Author

I cannot replicate the regressions, or perhaps I'm looking at the wrong place, I need more info.

@glitchminer
Copy link
Contributor

I cannot replicate the regressions, or perhaps I'm looking at the wrong place, I need more info.

Reproduced the issues mentioned on master.

@iurimatias iurimatias force-pushed the refactor/16286_refactor_profile_context_menu branch from 8e0b619 to e423081 Compare September 20, 2024 14:29
Copy link
Contributor

@glitchminer glitchminer left a comment

Choose a reason for hiding this comment

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

@iurimatias , noted a couple of regressions compared to master:

  1. There is no longer a line above the red items at the bottom of lists

  2. Remove nickname is not moved to the lower part of the list with the other red items
    image

  3. In community settings > members, "add nickname" and "send contact request" fail to open the dialogs to perform those actions
    image

refactor ProfileContextMenu to make it a functional component

refactor ProfileContextMenu to make it a functional component

refactor ProfileContextMenu to make it a functional component

This refactor ProfileContextMenu to make it a functional component by:

refactored out direct calls to backend, and passing backend data structures and moved this logic to the callers, also refactored common calls between the callers
common types of context menus have been extracted to their sub components which removes a lot of logic too and makes the behaviour very clear
user verification workflow (which was already disabled) has been removed

refactor: use signals and call singletons on the parent instead

remove unused code for now from profile context menu

refactor profile context menu into two components; add property to storybook

extract blocked profile context menu and self profile context menu

use profileType instead of individual bools

refactor to pass trustStatus as an argument

make contact type a parameter

remove unnecessary method from RegularProfileContextMenu

add ensVerified property to ProfileContextMenu components

add onlineStatus property to ProfileContextMenu components

move ProfileContextMenu storybook controls to the right sidebar

move contactDetails logic up from the view

add local nickname property to ProfileContextMenu components

fix issue with missing signal; fix logs in storybook

use constant for profileType instead of string

refactor common code into a single method

refactor getProfileContext

remove references to contactDetails which are not longer needed

remove unnecessary comments

fix bridged constant

refactor into a single ProfileContextMenu component

refactor into a single ProfileContextMenu component

refactor into a single ProfileContextMenu component

simplify imports

remove unused store field

move methods from utils to contacts store

remove onClosed signal

remove unused param

rename ProfileContextMenu variables

simplify signals in ProfileContextMenu

remove ;

refactor: do early return

simplify ifs

move ProfileContextMenu to its own storybook page

fix wrong params

fix profile context menu separator

add missing signals to profile context menu on the members tab panel
@iurimatias iurimatias force-pushed the refactor/16286_refactor_profile_context_menu branch from 0d80878 to a09b773 Compare September 23, 2024 16:04
Copy link
Contributor

@glitchminer glitchminer left a comment

Choose a reason for hiding this comment

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

From community settings members list:

  • Remove nickname does not remove nickname
  • Remove untrusted mark does not remove untrusted icon in menu

Copy link
Contributor

@glitchminer glitchminer 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, previously noted issues are resolved

@iurimatias iurimatias merged commit 7a6144f into master Sep 24, 2024
8 of 9 checks passed
@iurimatias iurimatias deleted the refactor/16286_refactor_profile_context_menu branch September 24, 2024 14:04
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.

refactor ProfileContextMenu
6 participants