From f2af60b54da28451a209e92ba3860c89b9b977df Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Thu, 25 Apr 2024 12:30:14 -0400
Subject: [PATCH 01/14] basic grants fetching to determine if picker should be
shown
---
packages/common/src/api/account.ts | 13 ++++-
.../components/nav/desktop/AccountDetails.tsx | 5 ++
.../AccountSwitcher/AccountSwitcher.tsx | 47 +++++++++++++++++++
3 files changed, 64 insertions(+), 1 deletion(-)
create mode 100644 packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index 7cb5e092795..caf66af04eb 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -29,10 +29,21 @@ const accountApi = createApi({
options: {
type: 'mutation'
}
+ },
+ getManagedAccounts: {
+ async fetch(_, context) {
+ const sdk = await context.audiusSdk()
+ const grants = await sdk.users.getUserGrants()
+ return grants.data ?? []
+ },
+ options: {
+ type: 'query'
+ }
}
}
})
-export const { useGetCurrentUserId, useResetPassword } = accountApi.hooks
+export const { useGetCurrentUserId, useResetPassword, useGetManagedAccounts } =
+ accountApi.hooks
export const accountApiReducer = accountApi.reducer
diff --git a/packages/web/src/components/nav/desktop/AccountDetails.tsx b/packages/web/src/components/nav/desktop/AccountDetails.tsx
index 935e168f439..1974b11a148 100644
--- a/packages/web/src/components/nav/desktop/AccountDetails.tsx
+++ b/packages/web/src/components/nav/desktop/AccountDetails.tsx
@@ -7,6 +7,9 @@ import { useSelector } from 'utils/reducer'
import { SIGN_IN_PAGE, profilePage } from 'utils/route'
import styles from './AccountDetails.module.css'
+import { FeatureFlags } from '@audius/common/services'
+import { useFlag } from 'hooks/useRemoteConfig'
+import { AccountSwitcher } from './AccountSwitcher/AccountSwitcher'
const { getAccountUser } = accountSelectors
@@ -17,6 +20,7 @@ const messages = {
export const AccountDetails = () => {
const account = useSelector((state) => getAccountUser(state))
+ const { isEnabled: isManagerModeEnabled } = useFlag(FeatureFlags.MANAGER_MODE)
const profileLink = profilePage(account?.handle ?? '')
@@ -57,6 +61,7 @@ export const AccountDetails = () => {
>
)}
+ {isManagerModeEnabled && account ? : null}
)
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
new file mode 100644
index 00000000000..f9d9c36e037
--- /dev/null
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -0,0 +1,47 @@
+import {
+ useGetManagedAccounts,
+ useGetUserIdFromWallet
+} from '@audius/common/api'
+import { useAudiusQueryContext } from '@audius/common/audius-query'
+import { IconButton, IconCaretDown } from '@audius/harmony'
+import { useEffect, useState } from 'react'
+
+const useEthWalletAddress = () => {
+ const { audiusBackend } = useAudiusQueryContext()
+ const [ethWalletAddress, setEthWalletAddress] = useState(null)
+
+ useEffect(() => {
+ const fetchEthWalletAddress = async () => {
+ const libs = await audiusBackend.getAudiusLibsTyped()
+ const ethWalletAddress = await libs.web3Manager?.getWalletAddress()
+ if (!ethWalletAddress) {
+ console.error('Unexpected missing ethWalletAddress')
+ }
+ console.log(ethWalletAddress)
+ setEthWalletAddress(ethWalletAddress)
+ }
+
+ fetchEthWalletAddress()
+ }, [audiusBackend])
+
+ return ethWalletAddress
+}
+
+const useManagedAccounts = () => {
+ const ethWalletAddress = useEthWalletAddress()
+}
+
+export const AccountSwitcher = () => {
+ const { data: managedAccounts } = useGetManagedAccounts({})
+ const onClickExpander = () => {}
+
+ return managedAccounts && managedAccounts.length ? (
+
+ ) : null
+}
From f22f100fef71183fd4f205bab2b1bd082e7c728d Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Fri, 26 Apr 2024 12:16:11 -0400
Subject: [PATCH 02/14] Use correct endpoint
---
packages/common/src/api/account.ts | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index caf66af04eb..c63e4e772ee 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -1,4 +1,5 @@
import { createApi } from '~/audius-query'
+import { Id } from './utils'
type ResetPasswordArgs = {
email: string
@@ -31,10 +32,13 @@ const accountApi = createApi({
}
},
getManagedAccounts: {
- async fetch(_, context) {
- const sdk = await context.audiusSdk()
- const grants = await sdk.users.getUserGrants()
- return grants.data ?? []
+ async fetch(_, { audiusSdk, audiusBackend }) {
+ const sdk = await audiusSdk()
+ const currentUserId = (await audiusBackend.getAccount())?.user_id
+ const managedUsers = await sdk.users.getManagedUsers({
+ id: Id.parse(currentUserId)
+ })
+ return managedUsers.data ?? []
},
options: {
type: 'query'
From 9d8f335a52fd9cd4c7dd2a65c4926a91ed4a7258 Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 29 Apr 2024 10:49:08 -0400
Subject: [PATCH 03/14] checkpoint
---
packages/common/src/api/account.ts | 7 ++--
packages/common/src/audius-query/schema.ts | 5 +++
packages/common/src/models/Grant.ts | 23 +++++++++++++
packages/common/src/models/User.ts | 15 ++++++++-
.../AccountSwitcher/AccountSwitcher.tsx | 32 ++-----------------
5 files changed, 50 insertions(+), 32 deletions(-)
create mode 100644 packages/common/src/models/Grant.ts
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index c63e4e772ee..a680c80cc3d 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -38,10 +38,13 @@ const accountApi = createApi({
const managedUsers = await sdk.users.getManagedUsers({
id: Id.parse(currentUserId)
})
- return managedUsers.data ?? []
+
+ const { data = [] } = managedUsers
+ return
},
options: {
- type: 'query'
+ type: 'query',
+ schemaKey: 'managedUsers'
}
}
}
diff --git a/packages/common/src/audius-query/schema.ts b/packages/common/src/audius-query/schema.ts
index 767000cd8e9..b855749377f 100644
--- a/packages/common/src/audius-query/schema.ts
+++ b/packages/common/src/audius-query/schema.ts
@@ -22,7 +22,12 @@ export const collectionSchema = new schema.Entity(
{ idAttribute: 'playlist_id' }
)
+export const managedUserSchema = new schema.Object({
+ user: userSchema
+})
+
export const apiResponseSchema = new schema.Object({
+ managedUsers: new schema.Array(managedUserSchema),
user: userSchema,
track: trackSchema,
collection: collectionSchema,
diff --git a/packages/common/src/models/Grant.ts b/packages/common/src/models/Grant.ts
new file mode 100644
index 00000000000..fbcea36b91a
--- /dev/null
+++ b/packages/common/src/models/Grant.ts
@@ -0,0 +1,23 @@
+import { Grant as SDKGrant } from '@audius/sdk'
+import { Nullable, decodeHashId } from '~/utils'
+import { ID } from './Identifiers'
+
+export type Grant = {
+ grantee_address: string
+ user_id: Nullable
+ is_revoked: boolean
+ is_approved: boolean
+ created_at: string
+ updated_at: string
+}
+
+export const grantFromSDK = (input: SDKGrant): Grant => {
+ return {
+ grantee_address: input.granteeAddress,
+ user_id: decodeHashId(input.userId) ?? null,
+ is_revoked: input.isRevoked,
+ is_approved: input.isApproved,
+ created_at: input.createdAt,
+ updated_at: input.updatedAt
+ }
+}
diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts
index d45a46c2027..d05aa84347f 100644
--- a/packages/common/src/models/User.ts
+++ b/packages/common/src/models/User.ts
@@ -1,4 +1,4 @@
-import { full } from '@audius/sdk'
+import { full, ManagedUser } from '@audius/sdk'
import { omit } from 'lodash'
import snakecaseKeys from 'snakecase-keys'
@@ -23,6 +23,7 @@ import { Nullable, removeNullable } from '~/utils/typeUtils'
import { Timestamped } from './Timestamped'
import { UserEvent } from './UserEvent'
+import { Grant, grantFromSDK } from './Grant'
export type UserMetadata = {
album_count: number
@@ -85,6 +86,11 @@ export type UserMetadata = {
events?: UserEvent
} & Timestamped
+export type ManagedUserMetadata = {
+ grant: Grant
+ user: UserMetadata
+}
+
export type ComputedUserProperties = {
_profile_picture_sizes: ProfilePictureSizes
_cover_photo_sizes: CoverPhotoSizes
@@ -164,3 +170,10 @@ export const userMetadataFromSDK = (
export const userMetadataListFromSDK = (input?: full.UserFull[]) =>
input ? input.map((d) => userMetadataFromSDK(d)).filter(removeNullable) : []
+
+export const managedUserFromSDK = (input: ManagedUser): ManagedUserMetadata => {
+ return {
+ grant: grantFromSDK(input.grant),
+ user: userMetadataFromSDK(input.user) as UserMetadata
+ }
+}
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index f9d9c36e037..775b835fd21 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -1,40 +1,14 @@
-import {
- useGetManagedAccounts,
- useGetUserIdFromWallet
-} from '@audius/common/api'
+import { useGetManagedAccounts } from '@audius/common/api'
import { useAudiusQueryContext } from '@audius/common/audius-query'
import { IconButton, IconCaretDown } from '@audius/harmony'
import { useEffect, useState } from 'react'
-const useEthWalletAddress = () => {
- const { audiusBackend } = useAudiusQueryContext()
- const [ethWalletAddress, setEthWalletAddress] = useState(null)
-
- useEffect(() => {
- const fetchEthWalletAddress = async () => {
- const libs = await audiusBackend.getAudiusLibsTyped()
- const ethWalletAddress = await libs.web3Manager?.getWalletAddress()
- if (!ethWalletAddress) {
- console.error('Unexpected missing ethWalletAddress')
- }
- console.log(ethWalletAddress)
- setEthWalletAddress(ethWalletAddress)
- }
-
- fetchEthWalletAddress()
- }, [audiusBackend])
-
- return ethWalletAddress
-}
-
-const useManagedAccounts = () => {
- const ethWalletAddress = useEthWalletAddress()
-}
-
export const AccountSwitcher = () => {
const { data: managedAccounts } = useGetManagedAccounts({})
const onClickExpander = () => {}
+ console.log(managedAccounts)
+
return managedAccounts && managedAccounts.length ? (
Date: Mon, 29 Apr 2024 11:58:31 -0400
Subject: [PATCH 04/14] use full endpoint
---
packages/common/src/api/account.ts | 5 +++--
packages/common/src/models/User.ts | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index a680c80cc3d..e49a4236eb6 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -1,5 +1,6 @@
import { createApi } from '~/audius-query'
import { Id } from './utils'
+import { managedUserFromSDK } from '~/models'
type ResetPasswordArgs = {
email: string
@@ -35,12 +36,12 @@ const accountApi = createApi({
async fetch(_, { audiusSdk, audiusBackend }) {
const sdk = await audiusSdk()
const currentUserId = (await audiusBackend.getAccount())?.user_id
- const managedUsers = await sdk.users.getManagedUsers({
+ const managedUsers = await sdk.full.users.getManagedUsers({
id: Id.parse(currentUserId)
})
const { data = [] } = managedUsers
- return
+ return data.map(managedUserFromSDK)
},
options: {
type: 'query',
diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts
index d05aa84347f..ee0dd556edc 100644
--- a/packages/common/src/models/User.ts
+++ b/packages/common/src/models/User.ts
@@ -1,4 +1,4 @@
-import { full, ManagedUser } from '@audius/sdk'
+import { full } from '@audius/sdk'
import { omit } from 'lodash'
import snakecaseKeys from 'snakecase-keys'
@@ -171,7 +171,9 @@ export const userMetadataFromSDK = (
export const userMetadataListFromSDK = (input?: full.UserFull[]) =>
input ? input.map((d) => userMetadataFromSDK(d)).filter(removeNullable) : []
-export const managedUserFromSDK = (input: ManagedUser): ManagedUserMetadata => {
+export const managedUserFromSDK = (
+ input: full.ManagedUser
+): ManagedUserMetadata => {
return {
grant: grantFromSDK(input.grant),
user: userMetadataFromSDK(input.user) as UserMetadata
From 83e95d596eb4f9b278b7ed4d03d338fb9380deb9 Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 29 Apr 2024 16:39:30 -0400
Subject: [PATCH 05/14] add managers endpoint
---
packages/common/src/api/account.ts | 24 +++++++++++++++++++--
packages/common/src/models/User.ts | 34 +++++++++++++++++++++++++++---
2 files changed, 53 insertions(+), 5 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index e49a4236eb6..817b177997a 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -1,6 +1,6 @@
import { createApi } from '~/audius-query'
import { Id } from './utils'
-import { managedUserFromSDK } from '~/models'
+import { managedUserListFromSDK, userManagerListFromSDK } from '~/models'
type ResetPasswordArgs = {
email: string
@@ -35,13 +35,33 @@ const accountApi = createApi({
getManagedAccounts: {
async fetch(_, { audiusSdk, audiusBackend }) {
const sdk = await audiusSdk()
+ // TODO: Look this up in a better way
+ // https://linear.app/audius/issue/PAY-2816/look-up-parentchild-ids-from-a-better-place
const currentUserId = (await audiusBackend.getAccount())?.user_id
const managedUsers = await sdk.full.users.getManagedUsers({
id: Id.parse(currentUserId)
})
const { data = [] } = managedUsers
- return data.map(managedUserFromSDK)
+ return managedUserListFromSDK(data)
+ },
+ options: {
+ type: 'query',
+ schemaKey: 'managedUsers'
+ }
+ },
+ getManagers: {
+ async fetch(_, { audiusSdk, audiusBackend }) {
+ const sdk = await audiusSdk()
+ // TODO: Look this up in a better way
+ // https://linear.app/audius/issue/PAY-2816/look-up-parentchild-ids-from-a-better-place
+ const currentUserId = (await audiusBackend.getAccount())?.user_id
+ const managedUsers = await sdk.full.users.getManagers({
+ id: Id.parse(currentUserId)
+ })
+
+ const { data = [] } = managedUsers
+ return userManagerListFromSDK(data)
},
options: {
type: 'query',
diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts
index ee0dd556edc..b0186f6616e 100644
--- a/packages/common/src/models/User.ts
+++ b/packages/common/src/models/User.ts
@@ -91,6 +91,11 @@ export type ManagedUserMetadata = {
user: UserMetadata
}
+export type UserManagerMetadata = {
+ grant: Grant
+ manager: UserMetadata
+}
+
export type ComputedUserProperties = {
_profile_picture_sizes: ProfilePictureSizes
_cover_photo_sizes: CoverPhotoSizes
@@ -173,9 +178,32 @@ export const userMetadataListFromSDK = (input?: full.UserFull[]) =>
export const managedUserFromSDK = (
input: full.ManagedUser
-): ManagedUserMetadata => {
+): ManagedUserMetadata | undefined => {
+ const user = userMetadataFromSDK(input.user)
+ if (!user) {
+ return undefined
+ }
return {
- grant: grantFromSDK(input.grant),
- user: userMetadataFromSDK(input.user) as UserMetadata
+ user,
+ grant: grantFromSDK(input.grant)
}
}
+
+export const managedUserListFromSDK = (input?: full.ManagedUser[]) =>
+ input ? input.map((d) => managedUserFromSDK(d)).filter(removeNullable) : []
+
+export const userManagerFromSDK = (
+ input: full.UserManager
+): UserManagerMetadata | undefined => {
+ const manager = userMetadataFromSDK(input.manager)
+ if (!manager) {
+ return undefined
+ }
+ return {
+ manager,
+ grant: grantFromSDK(input.grant)
+ }
+}
+
+export const userManagerListFromSDK = (input?: full.UserManager[]) =>
+ input ? input.map((d) => userManagerFromSDK(d)).filter(removeNullable) : []
From 4dd1649f7cfbd9facbe04e3050a18d1eeadb44fa Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 29 Apr 2024 16:42:58 -0400
Subject: [PATCH 06/14] add schema for manager users
---
packages/common/src/api/account.ts | 2 +-
packages/common/src/audius-query/schema.ts | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index 817b177997a..8e44aabbaa7 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -65,7 +65,7 @@ const accountApi = createApi({
},
options: {
type: 'query',
- schemaKey: 'managedUsers'
+ schemaKey: 'userManagers'
}
}
}
diff --git a/packages/common/src/audius-query/schema.ts b/packages/common/src/audius-query/schema.ts
index b855749377f..f2015b52e1d 100644
--- a/packages/common/src/audius-query/schema.ts
+++ b/packages/common/src/audius-query/schema.ts
@@ -26,9 +26,14 @@ export const managedUserSchema = new schema.Object({
user: userSchema
})
+export const userManagerSchema = new schema.Object({
+ manager: userSchema
+})
+
export const apiResponseSchema = new schema.Object({
managedUsers: new schema.Array(managedUserSchema),
user: userSchema,
+ userManagers: new schema.Array(userManagerSchema),
track: trackSchema,
collection: collectionSchema,
users: new schema.Array(userSchema),
From 7173c7611b41001157a003fbe6447e92ed9582c3 Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 29 Apr 2024 16:49:01 -0400
Subject: [PATCH 07/14] lint fix
---
packages/common/src/models/Grant.ts | 4 ++--
packages/web/src/components/nav/desktop/AccountDetails.tsx | 4 ++--
.../nav/desktop/AccountSwitcher/AccountSwitcher.tsx | 4 ----
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/packages/common/src/models/Grant.ts b/packages/common/src/models/Grant.ts
index fbcea36b91a..a6ded695c0c 100644
--- a/packages/common/src/models/Grant.ts
+++ b/packages/common/src/models/Grant.ts
@@ -1,4 +1,4 @@
-import { Grant as SDKGrant } from '@audius/sdk'
+import { full } from '@audius/sdk'
import { Nullable, decodeHashId } from '~/utils'
import { ID } from './Identifiers'
@@ -11,7 +11,7 @@ export type Grant = {
updated_at: string
}
-export const grantFromSDK = (input: SDKGrant): Grant => {
+export const grantFromSDK = (input: full.Grant): Grant => {
return {
grantee_address: input.granteeAddress,
user_id: decodeHashId(input.userId) ?? null,
diff --git a/packages/web/src/components/nav/desktop/AccountDetails.tsx b/packages/web/src/components/nav/desktop/AccountDetails.tsx
index 1974b11a148..8acf880c051 100644
--- a/packages/web/src/components/nav/desktop/AccountDetails.tsx
+++ b/packages/web/src/components/nav/desktop/AccountDetails.tsx
@@ -1,14 +1,14 @@
+import { FeatureFlags } from '@audius/common/services'
import { accountSelectors } from '@audius/common/store'
import { Text } from '@audius/harmony'
import { AvatarLegacy } from 'components/avatar/AvatarLegacy'
import { TextLink, UserLink } from 'components/link'
+import { useFlag } from 'hooks/useRemoteConfig'
import { useSelector } from 'utils/reducer'
import { SIGN_IN_PAGE, profilePage } from 'utils/route'
import styles from './AccountDetails.module.css'
-import { FeatureFlags } from '@audius/common/services'
-import { useFlag } from 'hooks/useRemoteConfig'
import { AccountSwitcher } from './AccountSwitcher/AccountSwitcher'
const { getAccountUser } = accountSelectors
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index 775b835fd21..1580638be28 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -1,14 +1,10 @@
import { useGetManagedAccounts } from '@audius/common/api'
-import { useAudiusQueryContext } from '@audius/common/audius-query'
import { IconButton, IconCaretDown } from '@audius/harmony'
-import { useEffect, useState } from 'react'
export const AccountSwitcher = () => {
const { data: managedAccounts } = useGetManagedAccounts({})
const onClickExpander = () => {}
- console.log(managedAccounts)
-
return managedAccounts && managedAccounts.length ? (
Date: Thu, 2 May 2024 12:53:01 -0400
Subject: [PATCH 08/14] Finish styling and behavior for basic account switcher
---
.../AccountSwitcher/AccountListContent.tsx | 83 +++++++++++++++++
.../AccountSwitcher/AccountSwitcher.tsx | 70 ++++++++++++---
.../AccountSwitcherRow.module.css | 27 ++++++
.../AccountSwitcher/AccountSwitcherRow.tsx | 88 +++++++++++++++++++
4 files changed, 256 insertions(+), 12 deletions(-)
create mode 100644 packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
create mode 100644 packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.module.css
create mode 100644 packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
new file mode 100644
index 00000000000..9a80ca05540
--- /dev/null
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
@@ -0,0 +1,83 @@
+import { ManagedUserMetadata, User } from '@audius/common/models'
+import { Box, Flex, IconUserGroup, Text, useTheme } from '@audius/harmony'
+import styled from '@emotion/styled'
+import { AccountSwitcherRow } from './AccountSwitcherRow'
+
+const messages = {
+ switchAccount: 'Switch Account',
+ maangedAccounts: 'Managed Accounts'
+}
+
+export type AccountListContentProps = {
+ accounts: ManagedUserMetadata[]
+ managerAccount: User
+}
+
+const StyledList = styled.ul`
+ all: unset;
+ list-style: none;
+`
+
+export const AccountListContent = ({
+ accounts,
+ managerAccount
+}: AccountListContentProps) => {
+ const theme = useTheme()
+ // TODO: aria-labels
+ return (
+
+
+
+
+ {messages.switchAccount}
+
+
+
+
+
+
+
+
+ {messages.maangedAccounts}
+
+
+
+ {accounts.map(({ user }, i) => (
+ console.log(`clicked ${user.user_id}`)}
+ tabIndex={-1}
+ >
+
+
+
+
+ ))}
+
+
+ )
+}
+
+// Make ticket for migrating follows you thing
+// Talk about in meeting about how to hide high level pages
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index 1580638be28..250d941d9f4 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -1,17 +1,63 @@
+import { useCallback, useMemo, useRef, useState } from 'react'
+
import { useGetManagedAccounts } from '@audius/common/api'
-import { IconButton, IconCaretDown } from '@audius/harmony'
+import { Flex, IconButton, IconCaretDown, Popup } from '@audius/harmony'
+
+import { AccountListContent } from './AccountListContent'
+import { useSelector } from 'react-redux'
+import { accountSelectors } from '@audius/common/store'
export const AccountSwitcher = () => {
- const { data: managedAccounts } = useGetManagedAccounts({})
- const onClickExpander = () => {}
+ const { data: managedAccounts = [] } = useGetManagedAccounts({})
+ const [isExpanded, setIsExpanded] = useState(false)
+
+ const managerAccount = useSelector(accountSelectors.getAccountUser)
+
+ const parentElementRef = useRef(null)
+ const onClickExpander = useCallback(
+ () => setIsExpanded((expanded) => !expanded),
+ []
+ )
+
+ const accounts = useMemo(() => {
+ return managedAccounts.filter(({ grant }) => grant.is_approved)
+ }, [managedAccounts])
- return managedAccounts && managedAccounts.length ? (
-
- ) : null
+ return managerAccount === null || accounts.length === 0 ? null : (
+
+
+ {
+ if (target instanceof Element && parentElementRef.current) {
+ return parentElementRef.current.contains(target)
+ }
+ return false
+ }}
+ anchorRef={parentElementRef}
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
+ transformOrigin={{ vertical: 'top', horizontal: 'left' }}
+ dismissOnMouseLeave={false}
+ isVisible={isExpanded}
+ onClose={() => setIsExpanded(false)}
+ >
+
+
+
+ )
}
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.module.css b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.module.css
new file mode 100644
index 00000000000..e80cfb45737
--- /dev/null
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.module.css
@@ -0,0 +1,27 @@
+:root {
+ --profile-picture-size: var(--harmony-unit-12);
+}
+
+.profilePictureWrapper {
+ height: var(--profile-picture-size);
+ width: var(--profile-picture-size);
+ flex: 0 0 var(--profile-picture-size);
+}
+
+.profilePicture {
+ box-sizing: border-box;
+ height: var(--profile-picture-size);
+ width: var(--profile-picture-size);
+ flex: 0 0 var(--profile-picture-size);
+ border: 1px solid var(--harmony-n-100);
+ border-radius: 50%;
+
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-color: var(--default-profile-picture-background);
+}
+
+.profilePictureSkeleton {
+ border-radius: 50%;
+}
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
new file mode 100644
index 00000000000..1ae47dca52d
--- /dev/null
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
@@ -0,0 +1,88 @@
+import { SquareSizes, UserMetadata } from '@audius/common/models'
+import { Flex, Text, useTheme } from '@audius/harmony'
+import DynamicImage from 'components/dynamic-image/DynamicImage'
+import UserBadges from 'components/user-badges/UserBadges'
+import { useProfilePicture } from 'hooks/useUserProfilePicture'
+
+import styled from '@emotion/styled'
+import styles from './AccountSwitcherRow.module.css'
+
+export type AccountSwitcherRowProps = {
+ user: UserMetadata
+ isSelected?: boolean
+}
+
+const Indicator = styled.div(({ theme }) => ({
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ bottom: 0,
+ width: theme.spacing.xs,
+ backgroundColor: theme.color.background.accent
+}))
+
+export const AccountSwitcherRow = ({
+ user,
+ isSelected = false
+}: AccountSwitcherRowProps) => {
+ const profilePicture = useProfilePicture(
+ user.user_id,
+ SquareSizes.SIZE_150_BY_150
+ )
+ const { iconSizes, color } = useTheme()
+ return (
+
+ {isSelected && }
+
+
+
+
+ {user.name}
+
+
+
+ {`@${user.handle}`}
+
+
+ )
+}
From 63544f7ff0b9ea312b7c3efd983eeff68c93168f Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Fri, 3 May 2024 16:32:20 -0400
Subject: [PATCH 09/14] wire up saving user override and refreshing
---
packages/common/src/api/account.ts | 42 ++++++++----
packages/common/src/audius-query/schema.ts | 1 +
.../services/audius-backend/AudiusBackend.ts | 2 +-
packages/libs/src/api/Account.ts | 10 +++
.../discoveryProvider/DiscoveryProvider.ts | 64 +++++++++++--------
.../services/discoveryProvider/constants.ts | 2 +
packages/libs/src/userStateManager.ts | 14 ++++
.../AccountSwitcher/AccountListContent.tsx | 47 +++++++++++---
.../AccountSwitcher/AccountSwitcher.tsx | 40 ++++++++++--
9 files changed, 166 insertions(+), 56 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index 8e44aabbaa7..a51cae8a3d5 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -1,6 +1,11 @@
import { createApi } from '~/audius-query'
import { Id } from './utils'
-import { managedUserListFromSDK, userManagerListFromSDK } from '~/models'
+import {
+ ID,
+ UserMetadata,
+ managedUserListFromSDK,
+ userManagerListFromSDK
+} from '~/models'
type ResetPasswordArgs = {
email: string
@@ -20,6 +25,19 @@ const accountApi = createApi({
type: 'query'
}
},
+ getCurrentWeb3User: {
+ async fetch(_, { audiusBackend }) {
+ const libs = await audiusBackend.getAudiusLibsTyped()
+ // TODO: What happens in the cache if something here is null?
+ // Note: This cast is mostly safe, but is missing info populated in AudiusBackend.getAccount()
+ // Okay for now as that info isn't generally available on
+ return libs.Account?.getWeb3User() as UserMetadata | null
+ },
+ options: {
+ type: 'query',
+ schemaKey: 'currentWeb3User'
+ }
+ },
resetPassword: {
async fetch(args: ResetPasswordArgs, context) {
const { email, password } = args
@@ -33,13 +51,10 @@ const accountApi = createApi({
}
},
getManagedAccounts: {
- async fetch(_, { audiusSdk, audiusBackend }) {
+ async fetch({ userId }: { userId: ID }, { audiusSdk }) {
const sdk = await audiusSdk()
- // TODO: Look this up in a better way
- // https://linear.app/audius/issue/PAY-2816/look-up-parentchild-ids-from-a-better-place
- const currentUserId = (await audiusBackend.getAccount())?.user_id
const managedUsers = await sdk.full.users.getManagedUsers({
- id: Id.parse(currentUserId)
+ id: Id.parse(userId)
})
const { data = [] } = managedUsers
@@ -51,13 +66,10 @@ const accountApi = createApi({
}
},
getManagers: {
- async fetch(_, { audiusSdk, audiusBackend }) {
+ async fetch({ userId }: { userId: ID }, { audiusSdk }) {
const sdk = await audiusSdk()
- // TODO: Look this up in a better way
- // https://linear.app/audius/issue/PAY-2816/look-up-parentchild-ids-from-a-better-place
- const currentUserId = (await audiusBackend.getAccount())?.user_id
const managedUsers = await sdk.full.users.getManagers({
- id: Id.parse(currentUserId)
+ id: Id.parse(userId)
})
const { data = [] } = managedUsers
@@ -71,7 +83,11 @@ const accountApi = createApi({
}
})
-export const { useGetCurrentUserId, useResetPassword, useGetManagedAccounts } =
- accountApi.hooks
+export const {
+ useGetCurrentUserId,
+ useGetCurrentWeb3User,
+ useResetPassword,
+ useGetManagedAccounts
+} = accountApi.hooks
export const accountApiReducer = accountApi.reducer
diff --git a/packages/common/src/audius-query/schema.ts b/packages/common/src/audius-query/schema.ts
index f2015b52e1d..09c71942185 100644
--- a/packages/common/src/audius-query/schema.ts
+++ b/packages/common/src/audius-query/schema.ts
@@ -31,6 +31,7 @@ export const userManagerSchema = new schema.Object({
})
export const apiResponseSchema = new schema.Object({
+ currentWeb3User: userSchema,
managedUsers: new schema.Array(managedUserSchema),
user: userSchema,
userManagers: new schema.Array(userManagerSchema),
diff --git a/packages/common/src/services/audius-backend/AudiusBackend.ts b/packages/common/src/services/audius-backend/AudiusBackend.ts
index c29f786f9f3..4bc5752afd9 100644
--- a/packages/common/src/services/audius-backend/AudiusBackend.ts
+++ b/packages/common/src/services/audius-backend/AudiusBackend.ts
@@ -706,7 +706,7 @@ export const audiusBackend = ({
getRemoteVar(IntKeys.DISCOVERY_NODE_MAX_BLOCK_DIFF) ?? undefined,
discoveryNodeSelector,
- enableUserIdOverride: isManagerModeEnabled
+ enableUserWalletOverride: isManagerModeEnabled
},
identityServiceConfig:
AudiusLibs.configIdentityService(identityServiceUrl),
diff --git a/packages/libs/src/api/Account.ts b/packages/libs/src/api/Account.ts
index d82175944e1..c6ea9d6f4f5 100644
--- a/packages/libs/src/api/Account.ts
+++ b/packages/libs/src/api/Account.ts
@@ -25,6 +25,7 @@ export class Account extends Base {
this.ServiceProvider = serviceProvider
this.getCurrentUser = this.getCurrentUser.bind(this)
+ this.getWeb3User = this.getWeb3User.bind(this)
this.login = this.login.bind(this)
this.logout = this.logout.bind(this)
this.generateRecoveryLink = this.generateRecoveryLink.bind(this)
@@ -54,6 +55,15 @@ export class Account extends Base {
return this.userStateManager.getCurrentUser()
}
+ /**
+ * Fetches the user metadata for user belonging to the current web3 wallet.
+ * May be different if acting as a managed account.
+ * @return {Object} user metadata
+ */
+ getWeb3User() {
+ return this.userStateManager.getWeb3User()
+ }
+
/**
* Logs a user into Audius
*/
diff --git a/packages/libs/src/services/discoveryProvider/DiscoveryProvider.ts b/packages/libs/src/services/discoveryProvider/DiscoveryProvider.ts
index 4842f56f76a..60dcd4ff7ba 100644
--- a/packages/libs/src/services/discoveryProvider/DiscoveryProvider.ts
+++ b/packages/libs/src/services/discoveryProvider/DiscoveryProvider.ts
@@ -21,7 +21,11 @@ import {
DiscoveryProviderSelection,
DiscoveryProviderSelectionConfig
} from './DiscoveryProviderSelection'
-import { DEFAULT_UNHEALTHY_BLOCK_DIFF, REQUEST_TIMEOUT_MS } from './constants'
+import {
+ DEFAULT_UNHEALTHY_BLOCK_DIFF,
+ DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE,
+ REQUEST_TIMEOUT_MS
+} from './constants'
import * as Requests from './requests'
const MAX_MAKE_REQUEST_RETRY_COUNT = 5
@@ -65,7 +69,7 @@ export type DiscoveryProviderConfig = {
unhealthySlotDiffPlays?: number
unhealthyBlockDiff?: number
discoveryNodeSelector?: DiscoveryNodeSelector
- enableUserIdOverride?: boolean
+ enableUserWalletOverride?: boolean
} & Pick<
DiscoveryProviderSelectionConfig,
'selectionCallback' | 'monitoringCallbacks' | 'localStorage'
@@ -97,10 +101,10 @@ type DiscoveryNodeChallenge = {
disbursed_amount: number
}
-const getUserIdOverride = async (localStorage?: LocalStorage) => {
+const getUserWalletOverride = async (localStorage?: LocalStorage) => {
try {
const userIdOverride = await localStorage?.getItem(
- '@audius/user-id-override'
+ DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE
)
return userIdOverride == null ? undefined : userIdOverride
} catch {
@@ -152,7 +156,7 @@ export class DiscoveryProvider {
| DiscoveryProviderSelection['monitoringCallbacks']
| undefined
- enableUserIdOverride = false
+ enableUserWalletOverride = false
discoveryProviderEndpoint: string | undefined
isInitialized = false
@@ -176,7 +180,7 @@ export class DiscoveryProvider {
unhealthySlotDiffPlays,
unhealthyBlockDiff,
discoveryNodeSelector,
- enableUserIdOverride = false
+ enableUserWalletOverride = false
}: DiscoveryProviderConfig) {
this.whitelist = whitelist
this.blacklist = blacklist
@@ -185,7 +189,7 @@ export class DiscoveryProvider {
this.web3Manager = web3Manager
this.selectionCallback = selectionCallback
this.localStorage = localStorage
- this.enableUserIdOverride = enableUserIdOverride
+ this.enableUserWalletOverride = enableUserWalletOverride
this.unhealthyBlockDiff = unhealthyBlockDiff ?? DEFAULT_UNHEALTHY_BLOCK_DIFF
this.serviceSelector = new DiscoveryProviderSelection(
@@ -243,12 +247,33 @@ export class DiscoveryProvider {
this.web3Manager &&
this.web3Manager.web3
) {
- // Set current user if it exists
- const userAccount = await this.getUserAccount(
+ const walletOverride = this.enableUserWalletOverride
+ ? await getUserWalletOverride(this.localStorage)
+ : undefined
+
+ const web3AccountPromise = this.getUserAccount(
this.web3Manager.getWalletAddress()
)
- if (userAccount) {
- await this.userStateManager.setCurrentUser(userAccount)
+
+ if (walletOverride) {
+ const overrideAccountPromise = this.getUserAccount(walletOverride)
+ const [web3User, currentUser] = await Promise.all([
+ web3AccountPromise,
+ overrideAccountPromise
+ ])
+
+ if (web3User) {
+ this.userStateManager.setWeb3User(web3User)
+ }
+ if (currentUser) {
+ await this.userStateManager.setCurrentUser(currentUser)
+ }
+ } else {
+ const currentUser = await web3AccountPromise
+ if (currentUser) {
+ this.userStateManager.setWeb3User(currentUser)
+ await this.userStateManager.setCurrentUser(currentUser)
+ }
}
}
}
@@ -839,21 +864,8 @@ export class DiscoveryProvider {
* Return user collections (saved & uploaded) along w/ users for those collections
*/
async getUserAccount(wallet: string) {
- const userIdOverride = this.enableUserIdOverride
- ? await getUserIdOverride(this.localStorage)
- : undefined
- // If override is used, fetch that account instead
- if (userIdOverride) {
- const req = Requests.getUsers(1, 0, [parseInt(userIdOverride)])
- const res = await this._makeRequest(req)
- if (res && res.length > 0 && res[0]) {
- return { ...res[0], playlists: [] } as CurrentUser
- }
- return null
- } else {
- const req = Requests.getUserAccount(wallet)
- return await this._makeRequest(req)
- }
+ const req = Requests.getUserAccount(wallet)
+ return await this._makeRequest(req)
}
/**
diff --git a/packages/libs/src/services/discoveryProvider/constants.ts b/packages/libs/src/services/discoveryProvider/constants.ts
index f95eaad67ac..fa81fc1e64d 100644
--- a/packages/libs/src/services/discoveryProvider/constants.ts
+++ b/packages/libs/src/services/discoveryProvider/constants.ts
@@ -1,5 +1,7 @@
export const DISCOVERY_PROVIDER_TIMESTAMP =
'@audius/libs:discovery-node-timestamp'
+export const DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE =
+ '@audius/user-wallet-override'
export const DISCOVERY_SERVICE_NAME = 'discovery-node'
export const DEFAULT_UNHEALTHY_BLOCK_DIFF = 15
export const REGRESSED_MODE_TIMEOUT = 2 * 60 * 1000 // two minutes
diff --git a/packages/libs/src/userStateManager.ts b/packages/libs/src/userStateManager.ts
index 4ff581ecac7..8acb9418aec 100644
--- a/packages/libs/src/userStateManager.ts
+++ b/packages/libs/src/userStateManager.ts
@@ -19,11 +19,13 @@ type UserStateManagerConfig = {
*/
export class UserStateManager {
currentUser: CurrentUser | null
+ web3User: CurrentUser | null
localStorage?: LocalStorage
constructor({ localStorage }: UserStateManagerConfig) {
// Should reflect the same fields as discovery node's /users?handle=
this.currentUser = null
+ this.web3User = null
this.localStorage = localStorage
}
@@ -41,14 +43,26 @@ export class UserStateManager {
}
}
+ setWeb3User(user: CurrentUser) {
+ this.web3User = user
+ }
+
getCurrentUser() {
return this.currentUser
}
+ getWeb3User() {
+ return this.web3User
+ }
+
getCurrentUserId() {
return this.currentUser ? this.currentUser.user_id : null
}
+ getWeb3UserId() {
+ return this.web3User ? this.web3User.user_id : null
+ }
+
async clearUser() {
this.currentUser = null
if (this.localStorage) {
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
index 9a80ca05540..03e83cddb1e 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
@@ -1,7 +1,13 @@
-import { ManagedUserMetadata, User } from '@audius/common/models'
-import { Box, Flex, IconUserGroup, Text, useTheme } from '@audius/harmony'
+import {
+ ID,
+ ManagedUserMetadata,
+ User,
+ UserMetadata
+} from '@audius/common/models'
+import { Box, Flex, IconUserArrowRotate, Text, useTheme } from '@audius/harmony'
import styled from '@emotion/styled'
import { AccountSwitcherRow } from './AccountSwitcherRow'
+import { useCallback } from 'react'
const messages = {
switchAccount: 'Switch Account',
@@ -10,7 +16,9 @@ const messages = {
export type AccountListContentProps = {
accounts: ManagedUserMetadata[]
- managerAccount: User
+ managerAccount: UserMetadata
+ currentUserId: ID
+ onAccountSelected: (user: UserMetadata) => void
}
const StyledList = styled.ul`
@@ -20,9 +28,20 @@ const StyledList = styled.ul`
export const AccountListContent = ({
accounts,
- managerAccount
+ managerAccount,
+ currentUserId,
+ onAccountSelected
}: AccountListContentProps) => {
const theme = useTheme()
+
+ const onUserSelected = useCallback(
+ (user: UserMetadata) => {
+ if (user.user_id !== currentUserId) {
+ onAccountSelected(user)
+ }
+ },
+ [currentUserId, onAccountSelected]
+ )
// TODO: aria-labels
return (
-
+
{messages.switchAccount}
-
-
+ onAccountSelected(managerAccount)}
+ >
+
console.log(`clicked ${user.user_id}`)}
+ onClick={() => onAccountSelected(user)}
tabIndex={-1}
>
-
+
))}
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index 250d941d9f4..29b2316a646 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -1,17 +1,41 @@
import { useCallback, useMemo, useRef, useState } from 'react'
-import { useGetManagedAccounts } from '@audius/common/api'
+import {
+ useGetCurrentUserId,
+ useGetCurrentWeb3User,
+ useGetManagedAccounts
+} from '@audius/common/api'
import { Flex, IconButton, IconCaretDown, Popup } from '@audius/harmony'
+import { localStorage } from 'services/local-storage'
import { AccountListContent } from './AccountListContent'
-import { useSelector } from 'react-redux'
-import { accountSelectors } from '@audius/common/store'
+import { UserMetadata } from '@audius/common/models'
+
+// Matches corresponding key in libs (DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE)
+const USER_WALLET_OVERRIDE_KEY = '@audius/user-wallet-override'
export const AccountSwitcher = () => {
- const { data: managedAccounts = [] } = useGetManagedAccounts({})
const [isExpanded, setIsExpanded] = useState(false)
- const managerAccount = useSelector(accountSelectors.getAccountUser)
+ const { data: currentWeb3User } = useGetCurrentWeb3User({})
+ const { data: currentUserId } = useGetCurrentUserId({})
+
+ const onAccountSelected = useCallback((user: UserMetadata) => {
+ if (!user.wallet) {
+ console.error('User has no wallet address')
+ return
+ }
+ localStorage.setItem(USER_WALLET_OVERRIDE_KEY, user.wallet).then(() => {
+ // TODO: Don't use window directly?
+ // TODO: Need to clear the user from localStorage before switching or we get a flash of previous user.
+ window.location.reload()
+ })
+ }, [])
+
+ const { data: managedAccounts = [] } = useGetManagedAccounts(
+ { userId: currentWeb3User?.user_id! },
+ { disabled: !currentWeb3User }
+ )
const parentElementRef = useRef(null)
const onClickExpander = useCallback(
@@ -23,7 +47,7 @@ export const AccountSwitcher = () => {
return managedAccounts.filter(({ grant }) => grant.is_approved)
}, [managedAccounts])
- return managerAccount === null || accounts.length === 0 ? null : (
+ return !currentWeb3User || !currentUserId || accounts.length === 0 ? null : (
{
onClose={() => setIsExpanded(false)}
>
From adb612927107f0011f697de6461d294170082c64 Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 6 May 2024 11:19:12 -0400
Subject: [PATCH 10/14] fix stale account showing on switch
---
packages/common/src/hooks/index.ts | 1 +
.../common/src/hooks/useAccountSwitcher.ts | 25 +++++++++++++++++++
.../AccountSwitcher/AccountSwitcher.tsx | 17 +++----------
3 files changed, 30 insertions(+), 13 deletions(-)
create mode 100644 packages/common/src/hooks/useAccountSwitcher.ts
diff --git a/packages/common/src/hooks/index.ts b/packages/common/src/hooks/index.ts
index 845523bdc56..f76de3cb310 100644
--- a/packages/common/src/hooks/index.ts
+++ b/packages/common/src/hooks/index.ts
@@ -1,3 +1,4 @@
+export * from './useAccountSwitcher'
export * from './useBooleanOnce'
export * from './useFeatureFlag'
export * from './useRemoteVar'
diff --git a/packages/common/src/hooks/useAccountSwitcher.ts b/packages/common/src/hooks/useAccountSwitcher.ts
new file mode 100644
index 00000000000..a070eb8041b
--- /dev/null
+++ b/packages/common/src/hooks/useAccountSwitcher.ts
@@ -0,0 +1,25 @@
+import { useCallback } from 'react'
+import { useAppContext } from '~/context'
+import { UserMetadata } from '~/models/User'
+
+// Matches corresponding key in libs (DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE)
+const USER_WALLET_OVERRIDE_KEY = '@audius/user-wallet-override'
+
+export const useAccountSwitcher = () => {
+ const { localStorage } = useAppContext()
+ const switchAccount = useCallback(async (user: UserMetadata) => {
+ if (!user.wallet) {
+ console.error('User has no wallet address')
+ return
+ }
+
+ await localStorage.setItem(USER_WALLET_OVERRIDE_KEY, user.wallet)
+ await localStorage.clearAudiusAccount()
+ await localStorage.clearAudiusAccountUser()
+
+ // TODO: Need to clear the user from localStorage before switching or we get a flash of previous user.
+ window.location.reload()
+ }, [])
+
+ return { switchAccount }
+}
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index 29b2316a646..070732b3d85 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -6,13 +6,10 @@ import {
useGetManagedAccounts
} from '@audius/common/api'
import { Flex, IconButton, IconCaretDown, Popup } from '@audius/harmony'
-import { localStorage } from 'services/local-storage'
import { AccountListContent } from './AccountListContent'
import { UserMetadata } from '@audius/common/models'
-
-// Matches corresponding key in libs (DISCOVERY_PROVIDER_USER_WALLET_OVERRIDE)
-const USER_WALLET_OVERRIDE_KEY = '@audius/user-wallet-override'
+import { useAccountSwitcher } from '@audius/common/hooks'
export const AccountSwitcher = () => {
const [isExpanded, setIsExpanded] = useState(false)
@@ -20,16 +17,10 @@ export const AccountSwitcher = () => {
const { data: currentWeb3User } = useGetCurrentWeb3User({})
const { data: currentUserId } = useGetCurrentUserId({})
+ const { switchAccount } = useAccountSwitcher()
+
const onAccountSelected = useCallback((user: UserMetadata) => {
- if (!user.wallet) {
- console.error('User has no wallet address')
- return
- }
- localStorage.setItem(USER_WALLET_OVERRIDE_KEY, user.wallet).then(() => {
- // TODO: Don't use window directly?
- // TODO: Need to clear the user from localStorage before switching or we get a flash of previous user.
- window.location.reload()
- })
+ switchAccount(user)
}, [])
const { data: managedAccounts = [] } = useGetManagedAccounts(
From 5dd0c216baddd970530f4628455d9cd820489c8b Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 6 May 2024 11:26:27 -0400
Subject: [PATCH 11/14] lint fixes
---
.../AccountSwitcher/AccountListContent.tsx | 20 +++++++------------
.../AccountSwitcher/AccountSwitcher.tsx | 19 +++++++++++-------
.../AccountSwitcher/AccountSwitcherRow.tsx | 3 ++-
3 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
index 03e83cddb1e..050f4d89652 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
@@ -1,13 +1,10 @@
-import {
- ID,
- ManagedUserMetadata,
- User,
- UserMetadata
-} from '@audius/common/models'
-import { Box, Flex, IconUserArrowRotate, Text, useTheme } from '@audius/harmony'
+import { useCallback } from 'react'
+
+import { ID, ManagedUserMetadata, UserMetadata } from '@audius/common/models'
+import { Box, Flex, IconUserArrowRotate, Text } from '@audius/harmony'
import styled from '@emotion/styled'
+
import { AccountSwitcherRow } from './AccountSwitcherRow'
-import { useCallback } from 'react'
const messages = {
switchAccount: 'Switch Account',
@@ -32,8 +29,6 @@ export const AccountListContent = ({
currentUserId,
onAccountSelected
}: AccountListContentProps) => {
- const theme = useTheme()
-
const onUserSelected = useCallback(
(user: UserMetadata) => {
if (user.user_id !== currentUserId) {
@@ -42,7 +37,6 @@ export const AccountListContent = ({
},
[currentUserId, onAccountSelected]
)
- // TODO: aria-labels
return (
onAccountSelected(managerAccount)}
+ onClick={() => onUserSelected(managerAccount)}
>
onAccountSelected(user)}
+ onClick={() => onUserSelected(user)}
tabIndex={-1}
>
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
index 070732b3d85..e3cd4d4b494 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcher.tsx
@@ -5,11 +5,11 @@ import {
useGetCurrentWeb3User,
useGetManagedAccounts
} from '@audius/common/api'
+import { useAccountSwitcher } from '@audius/common/hooks'
+import { UserMetadata } from '@audius/common/models'
import { Flex, IconButton, IconCaretDown, Popup } from '@audius/harmony'
import { AccountListContent } from './AccountListContent'
-import { UserMetadata } from '@audius/common/models'
-import { useAccountSwitcher } from '@audius/common/hooks'
export const AccountSwitcher = () => {
const [isExpanded, setIsExpanded] = useState(false)
@@ -19,13 +19,18 @@ export const AccountSwitcher = () => {
const { switchAccount } = useAccountSwitcher()
- const onAccountSelected = useCallback((user: UserMetadata) => {
- switchAccount(user)
- }, [])
+ const onAccountSelected = useCallback(
+ (user: UserMetadata) => {
+ switchAccount(user)
+ },
+ [switchAccount]
+ )
+
+ const web3UserId = currentWeb3User?.user_id ?? null
const { data: managedAccounts = [] } = useGetManagedAccounts(
- { userId: currentWeb3User?.user_id! },
- { disabled: !currentWeb3User }
+ { userId: web3UserId! },
+ { disabled: !web3UserId }
)
const parentElementRef = useRef(null)
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
index 1ae47dca52d..9226fff4750 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountSwitcherRow.tsx
@@ -1,10 +1,11 @@
import { SquareSizes, UserMetadata } from '@audius/common/models'
import { Flex, Text, useTheme } from '@audius/harmony'
+import styled from '@emotion/styled'
+
import DynamicImage from 'components/dynamic-image/DynamicImage'
import UserBadges from 'components/user-badges/UserBadges'
import { useProfilePicture } from 'hooks/useUserProfilePicture'
-import styled from '@emotion/styled'
import styles from './AccountSwitcherRow.module.css'
export type AccountSwitcherRowProps = {
From 670395fe2f9a2f96e4ab087ad02ba2e53c0e9b70 Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 6 May 2024 11:38:17 -0400
Subject: [PATCH 12/14] PR feedback
---
packages/common/src/api/account.ts | 6 ++++--
packages/common/src/hooks/useAccountSwitcher.ts | 1 -
.../nav/desktop/AccountSwitcher/AccountListContent.tsx | 3 ---
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index a51cae8a3d5..e9f2da36beb 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -28,9 +28,11 @@ const accountApi = createApi({
getCurrentWeb3User: {
async fetch(_, { audiusBackend }) {
const libs = await audiusBackend.getAudiusLibsTyped()
- // TODO: What happens in the cache if something here is null?
+ // TODO: https://linear.app/audius/issue/PAY-2838/separate-walletentropy-user-and-current-user-in-state
+ // What happens in the cache if something here is null?
+
// Note: This cast is mostly safe, but is missing info populated in AudiusBackend.getAccount()
- // Okay for now as that info isn't generally available on
+ // Okay for now as that info isn't generally available on non-account users and isn't used in manager mode.
return libs.Account?.getWeb3User() as UserMetadata | null
},
options: {
diff --git a/packages/common/src/hooks/useAccountSwitcher.ts b/packages/common/src/hooks/useAccountSwitcher.ts
index a070eb8041b..cd3f5776a14 100644
--- a/packages/common/src/hooks/useAccountSwitcher.ts
+++ b/packages/common/src/hooks/useAccountSwitcher.ts
@@ -17,7 +17,6 @@ export const useAccountSwitcher = () => {
await localStorage.clearAudiusAccount()
await localStorage.clearAudiusAccountUser()
- // TODO: Need to clear the user from localStorage before switching or we get a flash of previous user.
window.location.reload()
}, [])
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
index 050f4d89652..607876c6a9d 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
@@ -101,6 +101,3 @@ export const AccountListContent = ({
)
}
-
-// Make ticket for migrating follows you thing
-// Talk about in meeting about how to hide high level pages
From 77e956c4dd118aa7f3bb041d7ad6e2d000ebe53c Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Mon, 6 May 2024 14:39:18 -0400
Subject: [PATCH 13/14] more lint fixes
---
packages/common/src/api/account.ts | 3 ++-
.../common/src/hooks/useAccountSwitcher.ts | 24 +++++++++++--------
packages/common/src/models/Grant.ts | 2 ++
packages/common/src/models/User.ts | 2 +-
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/packages/common/src/api/account.ts b/packages/common/src/api/account.ts
index e9f2da36beb..3876712b337 100644
--- a/packages/common/src/api/account.ts
+++ b/packages/common/src/api/account.ts
@@ -1,5 +1,4 @@
import { createApi } from '~/audius-query'
-import { Id } from './utils'
import {
ID,
UserMetadata,
@@ -7,6 +6,8 @@ import {
userManagerListFromSDK
} from '~/models'
+import { Id } from './utils'
+
type ResetPasswordArgs = {
email: string
password: string
diff --git a/packages/common/src/hooks/useAccountSwitcher.ts b/packages/common/src/hooks/useAccountSwitcher.ts
index cd3f5776a14..b547e7fd63e 100644
--- a/packages/common/src/hooks/useAccountSwitcher.ts
+++ b/packages/common/src/hooks/useAccountSwitcher.ts
@@ -1,4 +1,5 @@
import { useCallback } from 'react'
+
import { useAppContext } from '~/context'
import { UserMetadata } from '~/models/User'
@@ -7,18 +8,21 @@ const USER_WALLET_OVERRIDE_KEY = '@audius/user-wallet-override'
export const useAccountSwitcher = () => {
const { localStorage } = useAppContext()
- const switchAccount = useCallback(async (user: UserMetadata) => {
- if (!user.wallet) {
- console.error('User has no wallet address')
- return
- }
+ const switchAccount = useCallback(
+ async (user: UserMetadata) => {
+ if (!user.wallet) {
+ console.error('User has no wallet address')
+ return
+ }
- await localStorage.setItem(USER_WALLET_OVERRIDE_KEY, user.wallet)
- await localStorage.clearAudiusAccount()
- await localStorage.clearAudiusAccountUser()
+ await localStorage.setItem(USER_WALLET_OVERRIDE_KEY, user.wallet)
+ await localStorage.clearAudiusAccount()
+ await localStorage.clearAudiusAccountUser()
- window.location.reload()
- }, [])
+ window.location.reload()
+ },
+ [localStorage]
+ )
return { switchAccount }
}
diff --git a/packages/common/src/models/Grant.ts b/packages/common/src/models/Grant.ts
index a6ded695c0c..655735a83fd 100644
--- a/packages/common/src/models/Grant.ts
+++ b/packages/common/src/models/Grant.ts
@@ -1,5 +1,7 @@
import { full } from '@audius/sdk'
+
import { Nullable, decodeHashId } from '~/utils'
+
import { ID } from './Identifiers'
export type Grant = {
diff --git a/packages/common/src/models/User.ts b/packages/common/src/models/User.ts
index b0186f6616e..17d32d3a06e 100644
--- a/packages/common/src/models/User.ts
+++ b/packages/common/src/models/User.ts
@@ -21,9 +21,9 @@ import { SolanaWalletAddress, StringWei, WalletAddress } from '~/models/Wallet'
import { decodeHashId } from '~/utils/hashIds'
import { Nullable, removeNullable } from '~/utils/typeUtils'
+import { Grant, grantFromSDK } from './Grant'
import { Timestamped } from './Timestamped'
import { UserEvent } from './UserEvent'
-import { Grant, grantFromSDK } from './Grant'
export type UserMetadata = {
album_count: number
From 20573e3cdb4eae837ad207e6a1111e793d00dd6b Mon Sep 17 00:00:00 2001
From: Randy Schott <1815175+schottra@users.noreply.github.com>
Date: Tue, 7 May 2024 10:57:00 -0400
Subject: [PATCH 14/14] fix typo
---
.../nav/desktop/AccountSwitcher/AccountListContent.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
index 607876c6a9d..2a09745ce24 100644
--- a/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
+++ b/packages/web/src/components/nav/desktop/AccountSwitcher/AccountListContent.tsx
@@ -8,7 +8,7 @@ import { AccountSwitcherRow } from './AccountSwitcherRow'
const messages = {
switchAccount: 'Switch Account',
- maangedAccounts: 'Managed Accounts'
+ managedAccounts: 'Managed Accounts'
}
export type AccountListContentProps = {
@@ -78,7 +78,7 @@ export const AccountListContent = ({
borderBottom='default'
>
- {messages.maangedAccounts}
+ {messages.managedAccounts}